#! /usr/bin/env python2

# application.py
#
# Demonstrates the use of SSGridView.py.
# Multiple instances of a SpreadsheetGridView window are created.
# Currently, there is no link between the data in individual windows.
#
# Note: as the application is very simple, it is not encapsulated
# in a class, but rather coded in a non-OO (procedural encapsulation
# only) fashion. This makes the code simple, but not very re-usable.
# TODO: put application in a class.

# Hans Vangheluwe March 2002
# last modified: 04/04/02  --- by Jean-Sébastien Bolduc

# Required modules
import sys                       # for exit()
from Tkinter      import *       # basic Tkinter
#                                                  *** MODIFIED FOR ASSGT 4 ***
# Need the stuff from assignment 1:
from SSheetData import *
from SSGridView import *

# The application consists of one root window with 3 buttons
#  - Add GridView      : creates a new GridView window
#  - Add PlotView      : creates a new PlotView window 
#                        (empty in this prototype)
#  - Quit Application
#
# The application will also terminate cleanly when it receives
# a window-closed event from the window manager

# The callbacks

def wmQuit():
  """
  Handle root window close: exit() application
  """
  # we may wish to put cleanup actions here
  print "Spreadsheet Application was closed (by Window Manager)"
  sys.exit()

def rootQuit():
  """
  Handle Quit clicked in root window: exit() application
  """
  # we may wish to put cleanup actions here
  print "Spreadsheet Application was closed (by Quit in root window)"
  sys.exit()

def ctrlCQuit():
  """
  Handle SIGINT signal: exit() application
  """
  # we may wish to put cleanup actions here
  print "Spreadsheet Application was closed (by SIGINT signal)"
  sys.exit()

def addGridView():
  """
  Creates a new GridView window.
  """

  # A global variable which assigns a unique (sequence)
  # number to opened windows. Closed window numbers are
  # not recycled. 
  # In a pure OO implementation, application.py would
  # be encapsulated in a class. numObservers would then
  # be a class variable.
  # Note how there is some redundancy (for efficiency reasons)
  # numObservers can be obtained as len(observers)
  global numObservers   
  numObservers = numObservers + 1

  window = Toplevel(root)
  windowTitle= "Spreadsheet View " + str(numObservers)

  # get height and width from Entry field
  # TODO: check that Strictly Positive Integers were entered
  rows     = int(rowsEntry.get()) 
  columns  = int(columnsEntry.get()) 

  # get cellHeight and cellWidth from Entry field
  # TODO: check that Strictly Positive Integers were entered
  cellHeight = int(cellHeightEntry.get()) 
  cellWidth  = int(cellWidthEntry.get()) 

  # get padHor and padVer from Entry field
  # TODO: check that Strictly Positive Integers were entered
  padHor     = int(padHorEntry.get()) 
  padVer     = int(padVerEntry.get()) 

  gridView = SpreadsheetGridView(master=window,
                                 title=windowTitle,
                                 data=theSubject,
             height=rows, width=columns,
                                 cellHeight=cellHeight, cellWidth=cellWidth,
             padHor=padHor, padVer=padVer)
  # Add to the list of observers
  # This list will be used to notify() observers by 
  # sending each of them an update() message.
  # For efficient updating, we also keep track of 
  # the extent of each observer. 
  observers.append((gridView, rows, columns))
  
  #                                                *** MODIFIED FOR ASSGT 4 ***
  # A gridView may be created when the subject is not empty. To reflect that, 
  # the gridView has to be updated upon creation.
  for y in range(gridView.dataOffsetVer,                                      \
        gridView.dataOffsetVer+gridView.height): 
    for x in range(gridView.dataOffsetHor,                                    \
        gridView.dataOffsetHor+gridView.width):
      # We add 1 because the lowest indexes for a SpreadsheetData are 1,
      # whereas they are 0 for a SpreadsheetGridView...
      cdata = theSubject[CellCoordinate(y+1, x+1)]
      if cdata != None:
        gridView.update(y, x, cdata)
  

def addPlotView():
  """
  Creates a new PlotView window. 
  """

  # A global variable which assigns a unique (sequence)
  # number to opened windows. Closed window numbers are
  # not recycled. 
  global numObservers
  numObservers = numObservers + 1

  window = Toplevel(root)
  windowTitle= "Spreadsheet View " + str(numObservers)

  # Not yet implemented
  # plotView = SpreadsheetPlotView(master=window, ...)
  #
  # # Add to list of observers
  #observers.append((plotView, rows, columns))

# The spreadsheet application
#
if __name__ == "__main__":

  #                                                *** MODIFIED FOR ASSGT 4 ***
  # Declare a unique, global concrete subject (a SpreadsheetData object):
  theSubject = SpreadsheetData()

  # root window
  root = Tk()
  root.protocol("WM_DELETE_WINDOW", wmQuit)
  root.title("Spreadsheet control")

  # Keep track of observers 
  observers = []   
  numObservers = 0 

  # Frame to add a grid spreadsheet view 
  gridViewFrame  = Frame(master=root)

  # Rows Label
  Label(master=gridViewFrame, text="rows:").pack(side=LEFT)
 
  # Entry field to enter the number of rows
  rowsEntry = Entry(master=gridViewFrame, width=4)
  rowsEntry.insert(0, "10")
  rowsEntry.pack(side=LEFT)

  # Columns Label
  Label(master=gridViewFrame, text="columns:").pack(side=LEFT)
 
  # Entry field to enter the number of columns 
  columnsEntry = Entry(master=gridViewFrame, width=4)
  columnsEntry.insert(0, "10")
  columnsEntry.pack(side=LEFT)

  # cellHeight Label
  Label(master=gridViewFrame, text="cellHeight:").pack(side=LEFT)
 
  # Entry field to enter the cellHeight 
  cellHeightEntry = Entry(master=gridViewFrame, width=4)
  cellHeightEntry.insert(0, "18")
  cellHeightEntry.pack(side=LEFT)

  # cellWidth Label
  Label(master=gridViewFrame, text="cellWidth:").pack(side=LEFT)
 
  # Entry field to enter the cellWidth 
  cellWidthEntry = Entry(master=gridViewFrame, width=4)
  cellWidthEntry.insert(0, "50")
  cellWidthEntry.pack(side=LEFT)

  # padHor Label
  Label(master=gridViewFrame, text="padHor:").pack(side=LEFT)
 
  # Entry field to enter the padHor 
  padHorEntry = Entry(master=gridViewFrame, width=4)
  padHorEntry.insert(0, "10")
  padHorEntry.pack(side=LEFT)

  # padVer Label
  Label(master=gridViewFrame, text="padVer:").pack(side=LEFT)
 
  # Entry field to enter the padVer 
  padVerEntry = Entry(master=gridViewFrame, width=4)
  padVerEntry.insert(0, "20")
  padVerEntry.pack(side=LEFT)

  # Button to add a grid spreadsheet view 
  gridViewButton = Button(master=gridViewFrame,
                          text="Add GridView",
                          command=addGridView)
  gridViewButton.pack(side=RIGHT)

  gridViewFrame.pack()

  # Button to add a plot spreadsheet view 
  plotViewButton = Button(master=root,
                          text="Add PlotView",
                          command=addPlotView)
  plotViewButton.pack()

  # Button to quit the application
  quitButton = Button(master=root,
                      text="Quit Application",
                      foreground="red",
                      command=rootQuit)
  quitButton.pack(side=BOTTOM, fill=X)

  try:
   root.mainloop()          # The main Tkinter event loop
  except KeyboardInterrupt: # catch SIGINT signal
   ctrlCQuit()
    
# End of file application.py

