verbose messages for freedesktop installer, added missing import for main window
[debian/gnuradio] / grc / src / gui / MainWindow.py
1 """
2 Copyright 2008 Free Software Foundation, Inc.
3 This file is part of GNU Radio
4
5 GNU Radio Companion is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 GNU Radio Companion is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18 """
19
20 from Constants import \
21         MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT, \
22         NEW_FLOGRAPH_TITLE, REPORTS_WINDOW_HEIGHT, \
23         FLOW_GRAPH_FILE_EXTENSION
24 from Actions import \
25         APPLICATION_QUIT, FLOW_GRAPH_KILL, \
26         FLOW_GRAPH_SAVE
27 import pygtk
28 pygtk.require('2.0')
29 import gtk
30 import Bars
31 from BlockTreeWindow import BlockTreeWindow
32 from Dialogs import TextDisplay, MessageDialogHelper
33 from DrawingArea import DrawingArea
34 from NotebookPage import NotebookPage
35 import Preferences
36 import Messages
37 import os
38
39 ############################################################
40 # Main window
41 ############################################################
42
43 class MainWindow(gtk.Window):
44         """The topmost window with menus, the tool bar, and other major windows."""
45
46         def __init__(self, handle_states, platform):
47                 """
48                 MainWindow contructor.
49                 @param handle_states the callback function
50                 """
51                 self._platform = platform
52                 #setup window
53                 self.handle_states = handle_states
54                 gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
55                 vbox = gtk.VBox()
56                 hbox = gtk.HBox()
57                 self.add(vbox)
58                 #create the menu bar and toolbar
59                 vbox.pack_start(Bars.MenuBar(), False)
60                 vbox.pack_start(Bars.Toolbar(), False)
61                 #setup scrolled window
62                 self.scrolled_window = gtk.ScrolledWindow()
63                 self.scrolled_window.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT)
64                 self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
65                 self.drawing_area = DrawingArea(self)
66                 self.scrolled_window.add_with_viewport(self.drawing_area)
67                 #create the notebook
68                 self.notebook = gtk.Notebook()
69                 self.page_to_be_closed = None
70                 self.current_page = None
71                 self.notebook.set_show_border(False)
72                 self.notebook.set_scrollable(True) #scroll arrows for page tabs
73                 self.notebook.connect('switch-page', self._handle_page_change)
74                 fg_and_report_box = gtk.VBox(False, 0)
75                 fg_and_report_box.pack_start(self.notebook, False, False, 0)
76                 fg_and_report_box.pack_start(self.scrolled_window)
77                 hbox.pack_start(fg_and_report_box)
78                 vbox.pack_start(hbox)
79                 #create the side windows
80                 side_box = gtk.VBox()
81                 hbox.pack_start(side_box, False)
82                 side_box.pack_start(BlockTreeWindow(platform, self.get_flow_graph)) #allow resize, selection window can have more space
83                 #create the reports window
84                 self.text_display = TextDisplay()
85                 #house the reports in a scrolled window
86                 self.reports_scrolled_window = gtk.ScrolledWindow()
87                 self.reports_scrolled_window.set_size_request(-1, REPORTS_WINDOW_HEIGHT)
88                 self.reports_scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
89                 self.reports_scrolled_window.add_with_viewport(self.text_display)
90                 fg_and_report_box.pack_end(self.reports_scrolled_window, False) #dont allow resize, fg should get all the space
91                 #show all but the main window container and the reports window
92                 vbox.show_all()
93                 self.notebook.hide()
94                 self._show_reports_window(False)
95                 # load preferences and show the main window
96                 Preferences.load(platform)
97                 self.resize(*Preferences.window_size())
98                 self.show()#show after resize in preferences
99
100         ############################################################
101         # Event Handlers
102         ############################################################
103
104         def _quit(self, window, event):
105                 """
106                 Handle the delete event from the main window.
107                 Generated by pressing X to close, alt+f4, or right click+close.
108                 This method in turns calls the state handler to quit.
109                 @return true
110                 """
111                 self.handle_states(APPLICATION_QUIT)
112                 return True
113
114         def _handle_page_change(self, notebook, page, page_num):
115                 """
116                 Handle a page change. When the user clicks on a new tab,
117                 reload the flow graph to update the vars window and
118                 call handle states (select nothing) to update the buttons.
119                 @param notebook the notebook
120                 @param page new page
121                 @param page_num new page number
122                 """
123                 self.current_page = self.notebook.get_nth_page(page_num)
124                 Messages.send_page_switch(self.current_page.get_file_path())
125                 self.handle_states()
126
127         ############################################################
128         # Report Window
129         ############################################################
130
131         def add_report_line(self, line):
132                 """
133                 Place line at the end of the text buffer, then scroll its window all the way down.
134                 @param line the new text
135                 """
136                 self.text_display.insert(line)
137                 vadj = self.reports_scrolled_window.get_vadjustment()
138                 vadj.set_value(vadj.upper)
139                 vadj.emit('changed')
140
141         def _show_reports_window(self, show):
142                 """
143                 Show the reports window when show is True.
144                 Hide the reports window when show is False.
145                 @param show boolean flag
146                 """
147                 if show: self.reports_scrolled_window.show()
148                 else: self.reports_scrolled_window.hide()
149
150         ############################################################
151         # Pages: create and close
152         ############################################################
153
154         def new_page(self, file_path='', show=False):
155                 """
156                 Create a new notebook page.
157                 Set the tab to be selected.
158                 @param file_path optional file to load into the flow graph
159                 @param show true if the page should be shown after loading
160                 """
161                 #if the file is already open, show the open page and return
162                 if file_path and file_path in self._get_files(): #already open
163                         page = self.notebook.get_nth_page(self._get_files().index(file_path))
164                         self._set_page(page)
165                         return
166                 try: #try to load from file
167                         if file_path: Messages.send_start_load(file_path)
168                         flow_graph = self._platform.get_new_flow_graph()
169                         #inject drawing area and handle states into flow graph
170                         flow_graph.drawing_area = self.drawing_area
171                         flow_graph.handle_states = self.handle_states
172                         page = NotebookPage(
173                                 self,
174                                 flow_graph=flow_graph,
175                                 file_path=file_path,
176                         )
177                         if file_path: Messages.send_end_load()
178                 except Exception, e: #return on failure
179                         Messages.send_fail_load(e)
180                         return
181                 #add this page to the notebook
182                 self.notebook.append_page(page, page.get_tab())
183                 try: self.notebook.set_tab_reorderable(page, True)
184                 except: pass #gtk too old
185                 self.notebook.set_tab_label_packing(page, False, False, gtk.PACK_START)
186                 #only show if blank or manual
187                 if not file_path or show: self._set_page(page)
188
189         def close_pages(self):
190                 """
191                 Close all the pages in this notebook.
192                 @return true if all closed
193                 """
194                 open_files = filter(lambda file: file, self._get_files()) #filter blank files
195                 open_file = self.get_page().get_file_path()
196                 #close each page
197                 for page in self._get_pages():
198                         self.page_to_be_closed = page
199                         self.close_page(False)
200                 if self.notebook.get_n_pages(): return False
201                 #save state before closing
202                 Preferences.files_open(open_files)
203                 Preferences.file_open(open_file)
204                 Preferences.window_size(self.get_size())
205                 Preferences.save()
206                 return True
207
208         def close_page(self, ensure=True):
209                 """
210                 Close the current page.
211                 If the notebook becomes empty, and ensure is true,
212                 call new page upon exit to ensure that at least one page exists.
213                 @param ensure boolean
214                 """
215                 if not self.page_to_be_closed: self.page_to_be_closed = self.get_page()
216                 #show the page if it has an executing flow graph or is unsaved
217                 if self.page_to_be_closed.get_pid() or not self.page_to_be_closed.get_saved():
218                         self._set_page(self.page_to_be_closed)
219                 #unsaved? ask the user
220                 if not self.page_to_be_closed.get_saved() and self._save_changes():
221                         self.handle_states(FLOW_GRAPH_SAVE) #try to save
222                         if not self.page_to_be_closed.get_saved(): #still unsaved?
223                                 self.page_to_be_closed = None #set the page to be closed back to None
224                                 return
225                 #stop the flow graph if executing
226                 if self.page_to_be_closed.get_pid(): self.handle_states(FLOW_GRAPH_KILL)
227                 #remove the page
228                 self.notebook.remove_page(self.notebook.page_num(self.page_to_be_closed))
229                 if ensure and self.notebook.get_n_pages() == 0: self.new_page() #no pages, make a new one
230                 self.page_to_be_closed = None #set the page to be closed back to None
231
232         ############################################################
233         # Misc
234         ############################################################
235
236         def update(self):
237                 """
238                 Set the title of the main window.
239                 Set the titles on the page tabs.
240                 Show/hide the reports window.
241                 @param title the window title
242                 """
243                 if self.get_page():
244                         title = ''.join((
245                                         Preferences.window_prefix(),
246                                         ' - Editing: ',
247                                         (self.get_page().get_file_path() or NEW_FLOGRAPH_TITLE),
248                                         (self.get_page().get_saved() and ' ' or '*'), #blank must be non empty
249                                 )
250                         )
251                 else: title = MAIN_WINDOW_PREFIX + ' - Editor '
252                 gtk.Window.set_title(self, title)
253                 #set tab titles
254                 for page in self._get_pages():
255                         title = os.path.basename(page.get_file_path())
256                         #strip file extension #TEMP
257                         if title.endswith('.xml'):
258                                 title = title[0:-len('.xml')]
259                         #strip file extension
260                         if title.endswith(FLOW_GRAPH_FILE_EXTENSION):
261                                 title = title[0:-len(FLOW_GRAPH_FILE_EXTENSION)]
262                         page.set_text(''.join((
263                                                 (title or NEW_FLOGRAPH_TITLE),
264                                                 (page.get_saved() and ' ' or '*'), #blank must be non empty
265                                         )
266                                 )
267                         )
268                 #reports window
269                 self._show_reports_window(Preferences.show_reports_window())
270                 #show/hide notebook tabs
271                 if len(self._get_pages()) > 1: self.notebook.show()
272                 else: self.notebook.hide()
273
274         def get_page(self):
275                 """
276                 Get the selected page.
277                 @return the selected page
278                 """
279                 return self.current_page
280
281         def get_flow_graph(self):
282                 """
283                 Get the selected flow graph.
284                 @return the selected flow graph
285                 """
286                 return self.get_page().get_flow_graph()
287
288         ############################################################
289         # Helpers
290         ############################################################
291
292         def _set_page(self, page):
293                 """
294                 Set the current page.
295                 @param page the page widget
296                 """
297                 self.current_page = page
298                 self.notebook.set_current_page(self.notebook.page_num(self.current_page))
299
300         def _save_changes(self):
301                 """
302                 Save changes to flow graph?
303                 @return true if yes
304                 """
305                 return MessageDialogHelper(
306                         gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, 'Unsaved Changes!',
307                         'Would you like to save changes before closing?'
308                 ) == gtk.RESPONSE_YES
309
310         def _get_files(self):
311                 """
312                 Get the file names for all the pages, in order.
313                 @return list of file paths
314                 """
315                 return map(lambda page: page.get_file_path(), self._get_pages())
316
317         def _get_pages(self):
318                 """
319                 Get a list of all pages in the notebook.
320                 @return list of pages
321                 """
322                 return [self.notebook.get_nth_page(page_num) for page_num in range(self.notebook.get_n_pages())]