1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 import logging
29
30 logger = logging.getLogger('mainwindow')
31 logger.setLevel(logging.INFO)
32
33
34
35
36
37 from sqlalchemy.databases import sqlite
38 import sqlite3
39
40 from PyQt4.QtCore import Qt
41 from PyQt4 import QtGui, QtCore
42 from PyQt4 import QtWebKit
43
44 from camelot.view.art import Icon
45 from camelot.action import createAction, addActions
46 from camelot.view.controls.navpane import NavigationPane
47 from camelot.view.controls.printer import Printer
48 from camelot.view.model_thread import post
49
50 QT_MAJOR_VERSION = float('.'.join(str(QtCore.QT_VERSION_STR).split('.')[0:2]))
51
52 from camelot.core.utils import ugettext as _
53
54 -class MainWindow(QtGui.QMainWindow):
55 """Main window GUI"""
56
57 - def __init__(self, app_admin, parent=None):
58 from workspace import construct_workspace
59 logger.debug('initializing main window')
60 QtGui.QMainWindow.__init__(self, parent)
61
62 self.app_admin = app_admin
63
64 logger.debug('setting up workspace')
65 self.workspace = construct_workspace(self)
66
67 logger.debug('setting child windows dictionary')
68
69 logger.debug('setting central widget to our workspace')
70 self.setCentralWidget(self.workspace)
71
72 self.connect(
73 self.workspace,
74 QtCore.SIGNAL('subWindowActivated(QMdiSubWindow *)'),
75 self.updateMenus
76 )
77
78 logger.debug('creating navigation pane')
79 self.createNavigationPane()
80
81 logger.debug('creating all the required actions')
82 self.createActions()
83
84 logger.debug('creating the menus')
85 self.createMenus()
86
87 logger.debug('creating the toolbars')
88 self.createToolBars()
89
90 logger.debug('creating status bar')
91 self.createStatusBar()
92
93 logger.debug('updating menus')
94 self.updateMenus()
95
96 logger.debug('reading saved settings' )
97 self.readSettings()
98
99 logger.debug('setting up printer object')
100 self.printer = Printer()
101
102 logger.debug('setting up window title')
103 self.setWindowTitle(self.app_admin.get_name())
104
105
106 logger.debug('initialization complete')
107
108
109
111 logger.debug('showing about message box')
112 abtmsg = self.app_admin.get_about()
113 QtGui.QMessageBox.about(self, _('About'), _(abtmsg))
114 logger.debug('about message closed')
115
116 - def whats_new(self):
117 widget = self.app_admin.get_whats_new()
118 if widget:
119 widget.exec_()
120
122 from PyQt4.QtGui import QDesktopServices
123 url = self.app_admin.get_affiliated_url()
124 if url:
125 QDesktopServices.openUrl(url)
126
127 - def remote_support(self):
128 from PyQt4.QtGui import QDesktopServices
129 url = self.app_admin.get_remote_support_url()
130 if url:
131 QDesktopServices.openUrl(url)
132
133 - def readSettings(self):
134
135 settings = QtCore.QSettings()
136 self.restoreGeometry(settings.value('geometry').toByteArray())
137
138
139
140
141 - def writeSettings(self):
142
143 logger.debug('writing application settings')
144 settings = QtCore.QSettings()
145 settings.setValue('geometry', QtCore.QVariant(self.saveGeometry()))
146 settings.setValue('state', QtCore.QVariant(self.saveState()))
147 logger.debug('settings written')
148
152
153 - def runAction(self, name, callable):
154 progress = QtGui.QProgressDialog('Please wait', QtCore.QString(), 0, 0)
155 progress.setWindowTitle(name)
156 progress.show()
157 post(
158 callable,
159 progress.close,
160 exception=self.display_exception_message_box
161 )
162
163 - def createActions(self):
164 icon_backup = Icon('tango/16x16/actions/document-save.png').fullpath()
165 icon_restore = Icon('tango/16x16/devices/drive-harddisk.png').fullpath()
166 icon_pgsetup = Icon('tango/16x16/actions/document-properties.png').fullpath()
167 icon_print = Icon('tango/16x16/actions/document-print.png').fullpath()
168 icon_preview = Icon('tango/16x16/actions/document-print-preview.png').fullpath()
169 icon_copy = Icon('tango/16x16/actions/edit-copy.png').fullpath()
170
171 icon_new = Icon('tango/16x16/actions/document-new.png').fullpath()
172 icon_delete = Icon('tango/16x16/places/user-trash.png').fullpath()
173
174 icon_gofirst = Icon('tango/16x16/actions/go-first.png').fullpath()
175 icon_golast = Icon('tango/16x16/actions/go-last.png').fullpath()
176 icon_gonext = Icon('tango/16x16/actions/go-next.png').fullpath()
177 icon_goprevious = Icon('tango/16x16/actions/go-previous.png').fullpath()
178
179 icon_excel = Icon('tango/16x16/mimetypes/x-office-spreadsheet.png').fullpath()
180 icon_word = Icon('tango/16x16/mimetypes/x-office-document.png').fullpath()
181 icon_mail = Icon('tango/16x16/actions/mail-message-new.png').fullpath()
182
183 icon_import = Icon('tango/16x16/mimetypes/text-x-generic.png').fullpath()
184
185 icon_help = Icon('tango/16x16/apps/help-browser.png').fullpath()
186
187
188 self.backupAct = createAction(
189 parent=self,
190 text=_('&Backup'),
191 slot=self.backup,
192 actionicon=icon_backup,
193 tip=_('Backup the database')
194 )
195
196 self.restoreAct = createAction(
197 parent=self,
198 text=_('&Restore'),
199 slot=self.restore,
200 actionicon=icon_restore,
201 tip=_('Restore the database from a backup')
202 )
203
204 self.pageSetupAct = createAction(
205 parent=self,
206 text=_('Page Setup...'),
207 slot=self.pageSetup,
208 actionicon=icon_pgsetup,
209 tip=_('Page Setup...')
210 )
211
212 self.printAct = createAction(
213 parent=self,
214 text=_('Print...'),
215 slot=self.printDoc,
216 shortcut=QtGui.QKeySequence.Print,
217 actionicon=icon_print,
218 tip=_('Print...')
219 )
220
221 self.previewAct = createAction(
222 parent=self,
223 text=_('Print Preview'),
224 slot=self.previewDoc,
225 actionicon=icon_preview,
226 tip=_('Print Preview')
227 )
228
229 self.exitAct= createAction(
230 parent=self,
231 text=_('E&xit'),
232 slot=self.close,
233 actionicon=Icon('tango/16x16/actions/system-shutdown.png').fullpath(),
234 tip=_('Exit the application')
235 )
236
237 self.copyAct = createAction(
238 parent=self,
239 text=_('&Copy'),
240 slot=self.copy,
241 shortcut=QtGui.QKeySequence.Copy,
242 actionicon=icon_copy,
243 tip=_("Duplicate the selected rows")
244 )
245
246 self.selectAllAct = createAction(
247 parent=self,
248 text=_('Select &All'),
249 slot=self.select_all,
250 shortcut=QtGui.QKeySequence.SelectAll,
251 tip=_('Select all rows in the table'),
252 )
253
254
255
256
257
258
259 self.closeAct = createAction(
260 parent=self,
261 text=_('Cl&ose'),
262 slot=self.workspace.closeActiveSubWindow,
263 shortcut='Ctrl+W',
264 tip=_('Close the active window')
265 )
266
267 self.closeAllAct = createAction(
268 parent=self,
269 text=_('Close &All'),
270 slot=self.workspace.closeAllSubWindows,
271 tip=_('Close all the windows')
272 )
273
274 self.cascadeAct = createAction(
275 parent=self,
276 text=_('&Cascade windows'),
277 slot=self.workspace.cascadeSubWindows,
278 tip=_('Arranges all the child windows in a cascade pattern.')
279 )
280
281 self.separatorAct = QtGui.QAction(self)
282 self.separatorAct.setSeparator(True)
283
284 self.aboutAct = createAction(
285 parent=self,
286 text=_('&About'),
287 slot=self.about,
288 actionicon=Icon('tango/16x16/mimetypes/application-certificate.png').fullpath(),
289 tip=_("Show the application's About box")
290 )
291
292 self.whats_new_action = createAction(
293 parent=self,
294 text=_('&What\'s new'),
295 slot=self.whats_new,
296 actionicon=Icon('tango/16x16/status/software-update-available.png').fullpath(),
297 tip=_("Show the What's New box")
298 )
299
300 self.affiliated_website_action = createAction(
301 parent=self,
302 text=_('Affiliated website'),
303 slot=self.affiliated_website,
304 actionicon=Icon('tango/16x16/apps/internet-web-browser.png').fullpath(),
305 tip=_('Go to the affiliated website')
306 )
307
308 self.remote_support_action = createAction(
309 parent=self,
310 text=_('Remote support'),
311 slot=self.remote_support,
312 actionicon=Icon('tango/16x16/devices/video-display.png').fullpath(),
313 tip=_('Let the support agent take over your desktop')
314 )
315
316 self.helpAct = createAction(
317 parent=self,
318 text=_('Help'),
319 slot=self.help,
320 shortcut=QtGui.QKeySequence.HelpContents,
321 actionicon=icon_help,
322 tip=_('Help content')
323 )
324
325 self.newAct = createAction(
326 parent=self,
327 text=_('New'),
328 slot=self.new,
329 shortcut=QtGui.QKeySequence.New,
330 actionicon=icon_new,
331 tip=_('New')
332 )
333
334 self.deleteAct = createAction(
335 parent=self,
336 text=_('Delete'),
337 slot=self.delete,
338 shortcut=QtGui.QKeySequence.Delete,
339 actionicon=icon_delete,
340 tip=_('Delete')
341 )
342
343 self.viewFirstAct = createAction(
344 parent=self,
345 text=_('First'),
346 slot=self.viewFirst,
347 shortcut=QtGui.QKeySequence.MoveToStartOfDocument,
348 actionicon=icon_gofirst,
349 tip=_('First')
350 )
351
352 self.viewLastAct = createAction(
353 parent=self,
354 text=_('Last'),
355 slot=self.viewLast,
356 shortcut=QtGui.QKeySequence.MoveToEndOfDocument,
357 actionicon=icon_golast,
358 tip=_('Last')
359 )
360
361 self.viewNextAct = createAction(
362 parent=self,
363 text=_('Next'),
364 slot=self.viewNext,
365 shortcut=QtGui.QKeySequence.MoveToNextPage,
366 actionicon=icon_gonext,
367 tip=_('Next')
368 )
369
370 self.viewPreviousAct = createAction(
371 parent=self,
372 text=_('Previous'),
373 slot=self.viewPrevious,
374 shortcut=QtGui.QKeySequence.MoveToPreviousPage,
375 actionicon=icon_goprevious,
376 tip=_('Previous')
377 )
378
379 if QT_MAJOR_VERSION > 4.3:
380 self.viewFirstAct.setIconVisibleInMenu(False)
381 self.viewLastAct.setIconVisibleInMenu(False)
382 self.viewNextAct.setIconVisibleInMenu(False)
383 self.viewPreviousAct.setIconVisibleInMenu(False)
384
385 self.updateValueAct = createAction(
386 parent = self,
387 text = _('Replace field contents'),
388 slot = self.updateValue,
389 tip = _('Replace the content of a field for all rows in a selection')
390 )
391
392 self.exportToExcelAct = createAction(
393 parent=self,
394 text=_('Export to MS Excel'),
395 slot=self.exportToExcel,
396 actionicon=icon_excel,
397 tip=_('Export to MS Excel')
398 )
399
400 self.exportToWordAct = createAction(
401 parent=self,
402 text=_('Export to MS Word'),
403 slot=self.exportToWord,
404 actionicon=icon_word,
405 tip=_('Export to MS Word')
406 )
407
408 self.exportToMailAct = createAction(
409 parent=self,
410 text=_('Send by e-mail'),
411 slot=self.exportToMail,
412 actionicon=icon_mail,
413 tip=_('Send by e-mail')
414 )
415
416 self.importFromFileAct = createAction(
417 parent=self,
418 text=_('Import from file'),
419 slot=self.importFromFile,
420 actionicon=icon_import,
421 tip=_('Import from file')
422 )
423
424 from camelot.action.refresh import SessionRefresh
425
426 self.sessionRefreshAct = SessionRefresh(self)
427
428 self.app_actions = []
429 for action in self.app_admin.get_actions():
430
431 def bind_action(parent, action):
432
433 def slot(*args):
434 action.run(parent)
435
436 return slot
437
438 self.app_actions.append(
439 createAction(
440 parent=self,
441 text=unicode(action.get_verbose_name()),
442 slot=bind_action(self, action),
443 actionicon=action.get_icon().getQIcon(),
444 tip=unicode(action.get_verbose_name())
445 )
446 )
447
448
449
451 TOP_LEVEL = None
452 self.view = QtWebKit.QWebView(TOP_LEVEL)
453
454
455
456
457 self.view.load(self.app_admin.get_help_url())
458 self.view.setWindowTitle(_('Help Browser'))
459 self.view.setWindowIcon(self.helpAct.icon())
460 self.view.show()
461
463 from camelot.view.wizard.backup import BackupWizard
464 wizard = BackupWizard(self.app_admin.backup_mechanism, self)
465 wizard.exec_()
466
468 from camelot.view.wizard.backup import RestoreWizard
469 wizard = RestoreWizard(self.app_admin.backup_mechanism, self)
470 wizard.exec_()
471
474
477
478 - def select_all(self):
480
481 - def printDoc(self):
483
484 - def previewDoc(self):
485 active = self.activeMdiChild()
486 from camelot.admin.form_action import PrintHtmlFormAction
487
488 class PrintPreview(PrintHtmlFormAction):
489
490 def html(self, entity_getter):
491 return active.widget().to_html()
492
493 action = PrintPreview('Print Preview')
494 action.run(lambda:None)
495
497 self.activeMdiChild().widget().newRow()
498
501
502 - def pageSetup(self):
504
505 - def viewFirst(self):
506 """selects view's first row"""
507 active = self.activeMdiChild()
508 active.widget().viewFirst()
509
510 - def viewLast(self):
511 """selects view's last row"""
512 active = self.activeMdiChild()
513 active.widget().viewLast()
514
515 - def viewNext(self):
516 """selects view's next row"""
517 active = self.activeMdiChild()
518 active.widget().viewNext()
519
520 - def viewPrevious(self):
521 """selects view's previous row"""
522 active = self.activeMdiChild()
523 active.widget().viewPrevious()
524
525 - def updateValue(self):
526 from camelot.view.wizard.update_value import UpdateValueWizard
527
528 admin = self.activeMdiChild().widget().get_admin()
529 selection_getter = self.activeMdiChild().widget().get_selection_getter()
530 wizard = UpdateValueWizard(admin=admin, selection_getter=selection_getter)
531 wizard.exec_()
532
533 - def exportToExcel(self):
534 """creates an excel file from the view"""
535 widget = self.activeMdiChild().widget()
536 post(widget.export_to_excel)
537
538 - def exportToWord(self):
539 """Use windows COM to export the active child window to MS word,
540 by using its to_html function"""
541 widget = self.activeMdiChild().widget()
542 post(widget.export_to_word)
543
544 - def exportToMail(self):
545 widget = self.activeMdiChild().widget()
546 post(widget.export_to_mail)
547
548 - def importFromFile(self):
550
551 - def createMenus(self):
552
553 self.fileMenu = self.menuBar().addMenu(_('&File'))
554 addActions(self.fileMenu, (
555 self.closeAct,
556 None,
557 self.backupAct,
558 self.restoreAct,
559 None,
560 self.pageSetupAct,
561 self.previewAct,
562 self.printAct,
563 None
564 ))
565
566 self.exportMenu = QtGui.QMenu(_('Export To'))
567 addActions(self.exportMenu, (
568 self.exportToExcelAct,
569 self.exportToWordAct,
570 self.exportToMailAct,
571 ))
572 self.fileMenu.addMenu(self.exportMenu)
573
574 self.importMenu = QtGui.QMenu(_('Import From'))
575 addActions(self.importMenu, (self.importFromFileAct,))
576 self.fileMenu.addMenu(self.importMenu)
577
578 addActions(self.fileMenu, (None, self.exitAct))
579
580 self.editMenu = self.menuBar().addMenu(_('&Edit'))
581
582 addActions(self.editMenu, (self.copyAct, self.updateValueAct, self.selectAllAct))
583
584 self.viewMenu = self.menuBar().addMenu(_('View'))
585 addActions(self.viewMenu, (self.sessionRefreshAct,))
586 gotoMenu = self.viewMenu.addMenu(_('Go To'))
587 addActions(gotoMenu, (
588 self.viewFirstAct,
589 self.viewPreviousAct,
590 self.viewNextAct,
591 self.viewLastAct
592 ))
593 self.windowMenu = self.menuBar().addMenu(_('&Window'))
594 self.connect(
595 self.windowMenu,
596 QtCore.SIGNAL('aboutToShow()'),
597
598 self.app_admin.update_window_menu(self)
599 )
600
601 self.menuBar().addSeparator()
602
603 self.helpMenu = self.menuBar().addMenu(_('&Help'))
604
605 help_menu_actions = [self.helpAct, self.aboutAct]
606 if self.app_admin.get_whats_new():
607 help_menu_actions.append(self.whats_new_action)
608 if self.app_admin.get_affiliated_url():
609 help_menu_actions.append(self.affiliated_website_action)
610 if self.app_admin.get_remote_support_url():
611 help_menu_actions.append(self.remote_support_action)
612 addActions(self.helpMenu, help_menu_actions )
613
614 - def updateMenus(self):
615 hasMdiChild = (self.activeMdiChild() is not None)
616 self.backupAct.setEnabled(True)
617 self.restoreAct.setEnabled(True)
618 self.closeAct.setEnabled(hasMdiChild)
619
620 self.closeAllAct.setEnabled(hasMdiChild)
621 self.cascadeAct.setEnabled(hasMdiChild)
622
623 self.pageSetupAct.setEnabled(hasMdiChild)
624 self.previewAct.setEnabled(hasMdiChild)
625 self.printAct.setEnabled(hasMdiChild)
626
627 self.newAct.setEnabled(hasMdiChild)
628 self.deleteAct.setEnabled(hasMdiChild)
629 self.copyAct.setEnabled(hasMdiChild)
630 self.viewFirstAct.setEnabled(hasMdiChild)
631 self.viewPreviousAct.setEnabled(hasMdiChild)
632 self.viewNextAct.setEnabled(hasMdiChild)
633 self.viewLastAct.setEnabled(hasMdiChild)
634
635 self.exportToWordAct.setEnabled(hasMdiChild)
636 self.exportToExcelAct.setEnabled(hasMdiChild)
637 self.exportToMailAct.setEnabled(hasMdiChild)
638
639 self.importFromFileAct.setEnabled(hasMdiChild)
640
641 self.separatorAct.setVisible(hasMdiChild)
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
681
683
684
685
686
687 self.tool_bar = self.addToolBar(_('Toolbar'))
688 self.tool_bar.setObjectName('ToolBar')
689 self.tool_bar.setMovable(False)
690 self.tool_bar.setFloatable(False)
691 addActions(self.tool_bar, (
692 self.newAct,
693 self.copyAct,
694 self.deleteAct,
695 self.viewFirstAct,
696 self.viewPreviousAct,
697 self.viewNextAct,
698 self.viewLastAct
699 ))
700
701 addActions(self.tool_bar, (
702 self.exportToExcelAct,
703 self.exportToWordAct,
704 self.exportToMailAct,
705 ))
706
707 addActions(self.tool_bar, (self.printAct, self.previewAct))
708
709 addActions(self.tool_bar, (self.helpAct,))
710
711 if self.app_actions:
712 addActions(self.tool_bar, self.app_actions)
713
714
715
717 self.navpane = NavigationPane(self.app_admin, parent=self)
718 self.addDockWidget(Qt.LeftDockWidgetArea, self.navpane)
719
720 self.connect(
721 self.navpane.treewidget,
722 QtCore.SIGNAL('itemClicked(QTreeWidgetItem *, int)'),
723 self.createMdiChild
724 )
725
726
727
728 - def createMdiChild(self, item):
729 index = self.navpane.treewidget.indexFromItem(item)
730 section_item = self.navpane.items[index.row()]
731 child = section_item.get_action().run(self.workspace)
732 assert child != None
733 subwindow = self.workspace.addSubWindow(child)
734 subwindow.showMaximized()
735
736 - def activeMdiChild(self):
737 return self.workspace.activeSubWindow()
738
739
740
741 - def createStatusBar(self):
742 from controls.statusbar import StatusBar
743 statusbar = StatusBar(self)
744 self.setStatusBar(statusbar)
745 statusbar.showMessage(_('Ready'), 5000)
746
747
748
749 - def closeEvent(self, event):
750 self.workspace.closeAllSubWindows()
751 if self.activeMdiChild():
752 event.ignore()
753 else:
754 self.writeSettings()
755 event.accept()
756