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
00020
00021
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
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
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
00057 vbox.pack_start(Bars.MenuBar(), False)
00058 vbox.pack_start(Bars.Toolbar(), False)
00059
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
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)
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
00078 side_box = gtk.VBox()
00079 hbox.pack_start(side_box, False)
00080 side_box.pack_start(BlockTreeWindow(platform, self.get_flow_graph))
00081
00082 self.text_display = TextDisplay()
00083
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)
00089
00090 vbox.show_all()
00091 self.notebook.hide()
00092 self._show_reports_window(False)
00093
00094 Preferences.load(platform)
00095 self.resize(*Preferences.window_size())
00096 self.show()
00097
00098
00099
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
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
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
00160 if file_path and file_path in self._get_files():
00161 page = self.notebook.get_nth_page(self._get_files().index(file_path))
00162 self._set_page(page)
00163 return
00164 try:
00165 if file_path: Messages.send_start_load(file_path)
00166 flow_graph = self._platform.get_new_flow_graph()
00167
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:
00177 Messages.send_fail_load(e)
00178 return
00179
00180 self.notebook.append_page(page, page.get_tab())
00181 try: self.notebook.set_tab_reorderable(page, True)
00182 except: pass
00183 self.notebook.set_tab_label_packing(page, False, False, gtk.PACK_START)
00184
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())
00193 open_file = self.get_page().get_file_path()
00194
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
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
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
00218 if not self.page_to_be_closed.get_saved() and self._save_changes():
00219 self.handle_states(FLOW_GRAPH_SAVE)
00220 if not self.page_to_be_closed.get_saved():
00221 self.page_to_be_closed = None
00222 return
00223
00224 if self.page_to_be_closed.get_pid(): self.handle_states(FLOW_GRAPH_KILL)
00225
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()
00228 self.page_to_be_closed = None
00229
00230
00231
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 '*'),
00247 )
00248 )
00249 else: title = MAIN_WINDOW_PREFIX + ' - Editor '
00250 gtk.Window.set_title(self, title)
00251
00252 for page in self._get_pages():
00253 title = os.path.basename(page.get_file_path())
00254
00255 if title.endswith('.xml'):
00256 title = title[0:-len('.xml')]
00257
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 '*'),
00263 )
00264 )
00265 )
00266
00267 self._show_reports_window(Preferences.show_reports_window())
00268
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
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