MainWindow.py

Go to the documentation of this file.
00001 """
00002 Copyright 2008 Free Software Foundation, Inc.
00003 This file is part of GNU Radio
00004 
00005 GNU Radio Companion is free software; you can redistribute it and/or
00006 modify it under the terms of the GNU General Public License
00007 as published by the Free Software Foundation; either version 2
00008 of the License, or (at your option) any later version.
00009 
00010 GNU Radio Companion is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU General Public License for more details.
00014 
00015 You should have received a copy of the GNU General Public License
00016 along with this program; if not, write to the Free Software
00017 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
00018 """
00019 ##@package grc.gui.MainWindow
00020 #The main window, containing all windows, tool bars, and menu bars.
00021 #@author Josh Blum
00022 
00023 from grc.Constants import *
00024 from grc.Actions import *
00025 import pygtk
00026 pygtk.require('2.0')
00027 import gtk
00028 import Bars
00029 from BlockTreeWindow import BlockTreeWindow
00030 from Dialogs import TextDisplay,MessageDialogHelper
00031 from DrawingArea import DrawingArea
00032 from grc import Preferences
00033 from grc import Messages
00034 from NotebookPage import Page
00035 import os
00036 
00037 ############################################################
00038 # Main window
00039 ############################################################
00040 
00041 class MainWindow(gtk.Window):
00042         """The topmost window with menus, the tool bar, and other major windows."""
00043 
00044         def __init__(self, handle_states, platform):
00045                 """!
00046                 MainWindow contructor.
00047                 @param handle_states the callback function
00048                 """
00049                 self._platform = platform
00050                 #setup window
00051                 self.handle_states = handle_states
00052                 gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
00053                 vbox = gtk.VBox()
00054                 hbox = gtk.HBox()
00055                 self.add(vbox)
00056                 #create the menu bar and toolbar
00057                 vbox.pack_start(Bars.MenuBar(), False)
00058                 vbox.pack_start(Bars.Toolbar(), False)
00059                 #setup scrolled window
00060                 self.scrolled_window = gtk.ScrolledWindow()
00061                 self.scrolled_window.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT)
00062                 self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
00063                 self.drawing_area = DrawingArea(self)
00064                 self.scrolled_window.add_with_viewport(self.drawing_area)
00065                 #create the notebook
00066                 self.notebook = gtk.Notebook()
00067                 self.page_to_be_closed = None
00068                 self.current_page = None
00069                 self.notebook.set_show_border(False)
00070                 self.notebook.set_scrollable(True) #scroll arrows for page tabs
00071                 self.notebook.connect('switch-page', self._handle_page_change)
00072                 fg_and_report_box = gtk.VBox(False, 0)
00073                 fg_and_report_box.pack_start(self.notebook, False, False, 0)
00074                 fg_and_report_box.pack_start(self.scrolled_window)
00075                 hbox.pack_start(fg_and_report_box)
00076                 vbox.pack_start(hbox)
00077                 #create the side windows
00078                 side_box = gtk.VBox()
00079                 hbox.pack_start(side_box, False)
00080                 side_box.pack_start(BlockTreeWindow(platform, self.get_flow_graph)) #allow resize, selection window can have more space
00081                 #create the reports window
00082                 self.text_display = TextDisplay()
00083                 #house the reports in a scrolled window
00084                 self.reports_scrolled_window = gtk.ScrolledWindow()
00085                 self.reports_scrolled_window.set_size_request(-1, REPORTS_WINDOW_HEIGHT)
00086                 self.reports_scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
00087                 self.reports_scrolled_window.add_with_viewport(self.text_display)
00088                 fg_and_report_box.pack_end(self.reports_scrolled_window, False) #dont allow resize, fg should get all the space
00089                 #show all but the main window container and the reports window
00090                 vbox.show_all()
00091                 self.notebook.hide()
00092                 self._show_reports_window(False)
00093                 # load preferences and show the main window
00094                 Preferences.load(platform)
00095                 self.resize(*Preferences.window_size())
00096                 self.show()#show after resize in preferences
00097 
00098         ############################################################
00099         # Event Handlers
00100         ############################################################
00101 
00102         def _quit(self, window, event):
00103                 """!
00104                 Handle the delete event from the main window.
00105                 Generated by pressing X to close, alt+f4, or right click+close.
00106                 This method in turns calls the state handler to quit.
00107                 @return true
00108                 """
00109                 self.handle_states(APPLICATION_QUIT)
00110                 return True
00111 
00112         def _handle_page_change(self, notebook, page, page_num):
00113                 """!
00114                 Handle a page change. When the user clicks on a new tab,
00115                 reload the flow graph to update the vars window and
00116                 call handle states (select nothing) to update the buttons.
00117                 @param notebook the notebook
00118                 @param page new page
00119                 @param page_num new page number
00120                 """
00121                 self.current_page = self.notebook.get_nth_page(page_num)
00122                 Messages.send_page_switch(self.current_page.get_file_path())
00123                 self.handle_states()
00124 
00125         ############################################################
00126         # Report Window
00127         ############################################################
00128 
00129         def add_report_line(self, line):
00130                 """!
00131                 Place line at the end of the text buffer, then scroll its window all the way down.
00132                 @param line the new text
00133                 """
00134                 self.text_display.insert(line)
00135                 vadj = self.reports_scrolled_window.get_vadjustment()
00136                 vadj.set_value(vadj.upper)
00137                 vadj.emit('changed')
00138 
00139         def _show_reports_window(self, show):
00140                 """!
00141                 Show the reports window when show is True.
00142                 Hide the reports window when show is False.
00143                 @param show boolean flag
00144                 """
00145                 if show: self.reports_scrolled_window.show()
00146                 else: self.reports_scrolled_window.hide()
00147 
00148         ############################################################
00149         # Pages: create and close
00150         ############################################################
00151 
00152         def new_page(self, file_path='', show=False):
00153                 """!
00154                 Create a new notebook page.
00155                 Set the tab to be selected.
00156                 @param file_path optional file to load into the flow graph
00157                 @param show true if the page should be shown after loading
00158                 """
00159                 #if the file is already open, show the open page and return
00160                 if file_path and file_path in self._get_files(): #already open
00161                         page = self.notebook.get_nth_page(self._get_files().index(file_path))
00162                         self._set_page(page)
00163                         return
00164                 try: #try to load from file
00165                         if file_path: Messages.send_start_load(file_path)
00166                         flow_graph = self._platform.get_new_flow_graph()
00167                         #inject drawing area and handle states into flow graph
00168                         flow_graph.drawing_area = self.drawing_area
00169                         flow_graph.handle_states = self.handle_states
00170                         page = Page(
00171                                 self,
00172                                 flow_graph=flow_graph,
00173                                 file_path=file_path,
00174                         )
00175                         if file_path: Messages.send_end_load()
00176                 except Exception, e: #return on failure
00177                         Messages.send_fail_load(e)
00178                         return
00179                 #add this page to the notebook
00180                 self.notebook.append_page(page, page.get_tab())
00181                 try: self.notebook.set_tab_reorderable(page, True)
00182                 except: pass #gtk too old
00183                 self.notebook.set_tab_label_packing(page, False, False, gtk.PACK_START)
00184                 #only show if blank or manual
00185                 if not file_path or show: self._set_page(page)
00186 
00187         def close_pages(self):
00188                 """
00189                 Close all the pages in this notebook.
00190                 @return true if all closed
00191                 """
00192                 open_files = filter(lambda file: file, self._get_files()) #filter blank files
00193                 open_file = self.get_page().get_file_path()
00194                 #close each page
00195                 for page in self._get_pages():
00196                         self.page_to_be_closed = page
00197                         self.close_page(False)
00198                 if self.notebook.get_n_pages(): return False
00199                 #save state before closing
00200                 Preferences.files_open(open_files)
00201                 Preferences.file_open(open_file)
00202                 Preferences.window_size(self.get_size())
00203                 Preferences.save()
00204                 return True
00205 
00206         def close_page(self, ensure=True):
00207                 """
00208                 Close the current page.
00209                 If the notebook becomes empty, and ensure is true,
00210                 call new page upon exit to ensure that at least one page exists.
00211                 @param ensure boolean
00212                 """
00213                 if not self.page_to_be_closed: self.page_to_be_closed = self.get_page()
00214                 #show the page if it has an executing flow graph or is unsaved
00215                 if self.page_to_be_closed.get_pid() or not self.page_to_be_closed.get_saved():
00216                         self._set_page(self.page_to_be_closed)
00217                 #unsaved? ask the user
00218                 if not self.page_to_be_closed.get_saved() and self._save_changes():
00219                         self.handle_states(FLOW_GRAPH_SAVE) #try to save
00220                         if not self.page_to_be_closed.get_saved(): #still unsaved?
00221                                 self.page_to_be_closed = None #set the page to be closed back to None
00222                                 return
00223                 #stop the flow graph if executing
00224                 if self.page_to_be_closed.get_pid(): self.handle_states(FLOW_GRAPH_KILL)
00225                 #remove the page
00226                 self.notebook.remove_page(self.notebook.page_num(self.page_to_be_closed))
00227                 if ensure and self.notebook.get_n_pages() == 0: self.new_page() #no pages, make a new one
00228                 self.page_to_be_closed = None #set the page to be closed back to None
00229 
00230         ############################################################
00231         # Misc
00232         ############################################################
00233 
00234         def update(self):
00235                 """!
00236                 Set the title of the main window.
00237                 Set the titles on the page tabs.
00238                 Show/hide the reports window.
00239                 @param title the window title
00240                 """
00241                 if self.get_page():
00242                         title = ''.join((
00243                                         MAIN_WINDOW_PREFIX,
00244                                         ' - Editing: ',
00245                                         (self.get_page().get_file_path() or NEW_FLOGRAPH_TITLE),
00246                                         (self.get_page().get_saved() and ' ' or '*'), #blank must be non empty
00247                                 )
00248                         )
00249                 else: title = MAIN_WINDOW_PREFIX + ' - Editor '
00250                 gtk.Window.set_title(self, title)
00251                 #set tab titles
00252                 for page in self._get_pages():
00253                         title = os.path.basename(page.get_file_path())
00254                         #strip file extension #TEMP
00255                         if title.endswith('.xml'): 
00256                                 title = title[0:-len('.xml')]
00257                         #strip file extension
00258                         if title.endswith(FLOW_GRAPH_FILE_EXTENSION): 
00259                                 title = title[0:-len(FLOW_GRAPH_FILE_EXTENSION)]
00260                         page.set_text(''.join((
00261                                                 (title or NEW_FLOGRAPH_TITLE),
00262                                                 (page.get_saved() and ' ' or '*'), #blank must be non empty
00263                                         )
00264                                 )
00265                         )
00266                 #reports window
00267                 self._show_reports_window(Preferences.show_reports_window())
00268                 #show/hide notebook tabs
00269                 if len(self._get_pages()) > 1: self.notebook.show()
00270                 else: self.notebook.hide()
00271 
00272         def get_page(self):
00273                 """!
00274                 Get the selected page.
00275                 @return the selected page
00276                 """
00277                 return self.current_page
00278 
00279         def get_flow_graph(self):
00280                 """!
00281                 Get the selected flow graph.
00282                 @return the selected flow graph
00283                 """
00284                 return self.get_page().get_flow_graph()
00285 
00286         ############################################################
00287         # Helpers
00288         ############################################################
00289 
00290         def _set_page(self, page):
00291                 """!
00292                 Set the current page.
00293                 @param page the page widget
00294                 """
00295                 self.current_page = page
00296                 self.notebook.set_current_page(self.notebook.page_num(self.current_page))
00297 
00298         def _save_changes(self):
00299                 """!
00300                 Save changes to flow graph?
00301                 @return true if yes
00302                 """
00303                 return MessageDialogHelper(
00304                         gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, 'Unsaved Changes!',
00305                         'Would you like to save changes before closing?'
00306                 ) == gtk.RESPONSE_YES
00307 
00308         def _get_files(self):
00309                 """
00310                 Get the file names for all the pages, in order.
00311                 @return list of file paths
00312                 """
00313                 return map(lambda page: page.get_file_path(), self._get_pages())
00314 
00315         def _get_pages(self):
00316                 """
00317                 Get a list of all pages in the notebook.
00318                 @return list of pages
00319                 """
00320                 return [self.notebook.get_nth_page(page_num) for page_num in range(self.notebook.get_n_pages())]
00321 

Generated on Sat Aug 23 02:00:11 2008 for GNU Radio Companion by  doxygen 1.5.4