Changeset 11208:b2091aba2a49 in orange


Ignore:
Timestamp:
11/28/12 17:57:08 (17 months ago)
Author:
Ales Erjavec <ales.erjavec@…>
Branch:
default
Message:

Moved widget actions definitions into SchemeEditWidget.

Location:
Orange/OrangeCanvas
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • Orange/OrangeCanvas/application/canvasmain.py

    r11206 r11208  
    66import sys 
    77import logging 
    8 import traceback 
    98import operator 
    109 
     
    1413    QMainWindow, QWidget, QAction, QActionGroup, QMenu, QMenuBar, QDialog, 
    1514    QFileDialog, QMessageBox, QVBoxLayout, QSizePolicy, QColor, QKeySequence, 
    16     QIcon, QToolBar, QToolButton, QDockWidget, QDesktopServices, QUndoGroup, 
     15    QIcon, QToolBar, QToolButton, QDockWidget, QDesktopServices, 
    1716    QApplication 
    1817) 
     
    2726from ..gui.dropshadow import DropShadowFrame 
    2827from ..gui.dock import CollapsibleDockWidget 
     28from ..gui.utils import message_critical, message_question, message_information 
    2929 
    3030from .canvastooldock import CanvasToolDock, QuickCategoryToolbar 
     
    7575 
    7676 
    77 def message_critical(text, title=None, informative_text=None, details=None, 
    78                      buttons=None, default_button=None, exc_info=False, 
    79                      parent=None): 
    80     """Show a critical message. 
    81     """ 
    82     if not text: 
    83         text = "An unexpected error occurred." 
    84  
    85     if title is None: 
    86         title = "Error" 
    87  
    88     return message(QMessageBox.Critical, text, title, informative_text, 
    89                    details, buttons, default_button, exc_info, parent) 
    90  
    91  
    92 def message_warning(text, title=None, informative_text=None, details=None, 
    93                     buttons=None, default_button=None, exc_info=False, 
    94                     parent=None): 
    95     """Show a warning message. 
    96     """ 
    97     if not text: 
    98         import random 
    99         text_candidates = ["Death could come at any moment.", 
    100                            "Murphy lurks about. Remember to save frequently." 
    101                            ] 
    102         text = random.choice(text_candidates) 
    103  
    104     if title is not None: 
    105         title = "Warning" 
    106  
    107     return message(QMessageBox.Warning, text, title, informative_text, 
    108                    details, buttons, default_button, exc_info, parent) 
    109  
    110  
    111 def message_information(text, title=None, informative_text=None, details=None, 
    112                         buttons=None, default_button=None, exc_info=False, 
    113                         parent=None): 
    114     """Show an information message box. 
    115     """ 
    116     if title is None: 
    117         title = "Information" 
    118     if not text: 
    119         text = "I am not a number." 
    120  
    121     return message(QMessageBox.Information, text, title, informative_text, 
    122                    details, buttons, default_button, exc_info, parent) 
    123  
    124  
    125 def message_question(text, title, informative_text=None, details=None, 
    126                      buttons=None, default_button=None, exc_info=False, 
    127                      parent=None): 
    128     """Show an message box asking the user to select some 
    129     predefined course of action (set by buttons argument). 
    130  
    131     """ 
    132     return message(QMessageBox.Question, text, title, informative_text, 
    133                    details, buttons, default_button, exc_info, parent) 
    134  
    135  
    136 def message(icon, text, title=None, informative_text=None, details=None, 
    137             buttons=None, default_button=None, exc_info=False, parent=None): 
    138     """Show a message helper function. 
    139     """ 
    140     if title is None: 
    141         title = "Message" 
    142     if not text: 
    143         text = "I am neither a postman nor a doctor." 
    144  
    145     if buttons is None: 
    146         buttons = QMessageBox.Ok 
    147  
    148     if details is None and exc_info: 
    149         details = traceback.format_exc(limit=20) 
    150  
    151     mbox = QMessageBox(icon, title, text, buttons, parent) 
    152  
    153     if informative_text: 
    154         mbox.setInformativeText(informative_text) 
    155  
    156     if details: 
    157         mbox.setDetailedText(details) 
    158  
    159     if default_button is not None: 
    160         mbox.setDefaultButton(default_button) 
    161  
    162     return mbox.exec_() 
    163  
    164  
    16577class FakeToolBar(QToolBar): 
    16678    """A Toolbar with no contents (used to reserve top and bottom margins 
     
    196108        self.recent_schemes = config.recent_schemes() 
    197109 
     110        self.setup_actions() 
    198111        self.setup_ui() 
     112        self.setup_menu() 
    199113 
    200114        self.resize(800, 600) 
     
    208122 
    209123        log.info("Setting up Canvas main window.") 
    210  
    211         self.setup_actions() 
    212         self.setup_menu() 
    213124 
    214125        # Two dummy tool bars to reserve space 
     
    235146        self.scheme_widget = SchemeEditWidget() 
    236147        self.scheme_widget.setScheme(widgetsscheme.WidgetsScheme()) 
    237  
    238         self.undo_group.addStack(self.scheme_widget.undoStack()) 
    239         self.undo_group.setActiveStack(self.scheme_widget.undoStack()) 
    240148 
    241149        w.layout().addWidget(self.scheme_widget) 
     
    533441                    toolTip=self.tr("Show application output."), 
    534442                    triggered=self.show_output_view, 
    535                     ) 
    536  
    537         self.undo_group = QUndoGroup(self) 
    538         self.undo_action = self.undo_group.createUndoAction(self) 
    539         self.undo_action.setShortcut(QKeySequence.Undo) 
    540         self.redo_action = self.undo_group.createRedoAction(self) 
    541         self.redo_action.setShortcut(QKeySequence.Redo) 
    542  
    543         self.select_all_action = \ 
    544             QAction(self.tr("Select All"), self, 
    545                     objectName="select-all-action", 
    546                     triggered=self.select_all, 
    547                     shortcut=QKeySequence.SelectAll, 
    548                     ) 
    549  
    550         self.open_widget_action = \ 
    551             QAction(self.tr("Open"), self, 
    552                     objectName="open-widget-action", 
    553                     triggered=self.open_widget, 
    554                     ) 
    555  
    556         self.rename_widget_action = \ 
    557             QAction(self.tr("Rename"), self, 
    558                     objectName="rename-widget-action", 
    559                     triggered=self.rename_widget, 
    560                     toolTip="Rename a widget", 
    561                     shortcut=QKeySequence(Qt.Key_F2) 
    562                     ) 
    563  
    564         self.remove_widget_action = \ 
    565             QAction(self.tr("Remove"), self, 
    566                     objectName="remove-action", 
    567                     triggered=self.remove_selected, 
    568                     ) 
    569  
    570         delete_shortcuts = [Qt.Key_Delete, 
    571                             Qt.ControlModifier + Qt.Key_Backspace] 
    572  
    573         if sys.platform == "darwin": 
    574             # Command Backspace should be the first 
    575             # (visible shortcut in the menu) 
    576             delete_shortcuts.reverse() 
    577  
    578         self.remove_widget_action.setShortcuts(delete_shortcuts) 
    579  
    580         self.widget_help_action = \ 
    581             QAction(self.tr("Help"), self, 
    582                     objectName="widget-help-action", 
    583                     triggered=self.widget_help, 
    584                     toolTip=self.tr("Show widget help."), 
    585                     shortcut=QKeySequence.HelpContents, 
    586443                    ) 
    587444 
     
    657514        menu_bar.addMenu(file_menu) 
    658515 
     516        editor_menus = self.scheme_widget.menuBarActions() 
     517 
     518        # WARNING: Hard coded order, should lookup the action text 
     519        # and determine the proper order 
     520        self.edit_menu = editor_menus[0].menu() 
     521        self.widget_menu = editor_menus[1].menu() 
     522 
    659523        # Edit menu 
    660         self.edit_menu = QMenu("&Edit", menu_bar) 
    661         self.edit_menu.addAction(self.undo_action) 
    662         self.edit_menu.addAction(self.redo_action) 
    663         self.edit_menu.addSeparator() 
    664         self.edit_menu.addAction(self.select_all_action) 
    665524        menu_bar.addMenu(self.edit_menu) 
    666525 
     
    694553 
    695554        # Widget menu 
    696         self.widget_menu = QMenu(self.tr("Widget"), self) 
    697         self.widget_menu.addAction(self.open_widget_action) 
    698         self.widget_menu.addSeparator() 
    699         self.widget_menu.addAction(self.rename_widget_action) 
    700         self.widget_menu.addAction(self.remove_widget_action) 
    701         self.widget_menu.addSeparator() 
    702         self.widget_menu.addAction(self.widget_help_action) 
    703555        menu_bar.addMenu(self.widget_menu) 
    704556 
  • Orange/OrangeCanvas/document/schemeedit.py

    r11201 r11208  
    33 
    44""" 
     5import sys 
    56import logging 
    67from operator import attrgetter 
     
    1011    QKeySequence, QUndoStack, QGraphicsItem, QGraphicsObject, 
    1112    QGraphicsTextItem, QCursor, QFont, QPainter, QPixmap, QColor, 
    12     QIcon 
     13    QIcon, QDesktopServices 
    1314) 
    1415 
    15 from PyQt4.QtCore import Qt, QObject, QEvent, QSignalMapper, QRectF 
     16from PyQt4.QtCore import Qt, QObject, QEvent, QSignalMapper, QRectF, QUrl 
    1617from PyQt4.QtCore import pyqtProperty as Property, pyqtSignal as Signal 
    1718 
     19from ..gui.utils import message_information, disabled 
    1820from ..scheme import scheme 
    1921from ..canvas.scene import CanvasScene 
     
    3941 
    4042    def sceneEventFilter(self, obj, event): 
    41         print obj, event, event.type() 
    4243        if event.type() == QEvent.FocusIn and \ 
    4344                obj.flags() & QGraphicsItem.ItemIsFocusable: 
     
    102103        self.__setupUi() 
    103104 
    104         self.__linkMenu = QMenu(self) 
     105        self.__editMenu = QMenu(self.tr("&Edit"), self) 
     106        self.__editMenu.addAction(self.__undoAction) 
     107        self.__editMenu.addAction(self.__redoAction) 
     108        self.__editMenu.addSeparator() 
     109        self.__editMenu.addAction(self.__selectAllAction) 
     110 
     111        self.__widgetMenu = QMenu(self.tr("&Widget"), self) 
     112        self.__widgetMenu.addAction(self.__openSelectedAction) 
     113        self.__widgetMenu.addSeparator() 
     114        self.__widgetMenu.addAction(self.__removeSelectedAction) 
     115        self.__widgetMenu.addAction(self.__renameAction) 
     116        self.__widgetMenu.addSeparator() 
     117        self.__widgetMenu.addAction(self.__helpAction) 
     118 
     119        self.__linkMenu = QMenu(self.tr("Link"), self) 
    105120        self.__linkMenu.addAction(self.__linkEnableAction) 
    106121        self.__linkMenu.addSeparator() 
     
    112127        self.__zoomAction = \ 
    113128            QAction(self.tr("Zoom"), self, 
    114                     objectName="zoom", 
     129                    objectName="zoom-action", 
    115130                    checkable=True, 
    116131                    shortcut=QKeySequence.ZoomIn, 
     
    121136        self.__cleanUpAction = \ 
    122137            QAction(self.tr("Clean Up"), self, 
    123                     objectName="cleanup", 
     138                    objectName="cleanup-action", 
    124139                    toolTip=self.tr("Align widget to a grid."), 
    125140                    triggered=self.alignToGrid, 
     
    128143        self.__newTextAnnotationAction = \ 
    129144            QAction(self.tr("Text"), self, 
    130                     objectName="new-text-annotation", 
     145                    objectName="new-text-action", 
    131146                    toolTip=self.tr("Add a text annotation to the scheme."), 
    132147                    checkable=True, 
     
    156171        self.__newArrowAnnotationAction = \ 
    157172            QAction(self.tr("Arrow"), self, 
    158                     objectName="new-arrow-annotation", 
     173                    objectName="new-arrow-action", 
    159174                    toolTip=self.tr("Add a arrow annotation to the scheme."), 
    160175                    checkable=True, 
     
    193208        self.__newArrowAnnotationAction.setMenu(self.__arrowColorMenu) 
    194209 
     210        self.__undoAction = self.__undoStack.createUndoAction(self) 
     211        self.__undoAction.setShortcut(QKeySequence.Undo) 
     212        self.__undoAction.setObjectName("undo-action") 
     213 
     214        self.__redoAction = self.__undoStack.createRedoAction(self) 
     215        self.__redoAction.setShortcut(QKeySequence.Redo) 
     216        self.__redoAction.setObjectName("redo-action") 
     217 
     218        self.__selectAllAction = \ 
     219            QAction(self.tr("Select all"), self, 
     220                    objectName="select-all-action", 
     221                    toolTip=self.tr("Select all items."), 
     222                    triggered=self.selectAll, 
     223                    shortcut=QKeySequence.SelectAll 
     224                    ) 
     225 
     226        self.__openSelectedAction = \ 
     227            QAction(self.tr("Open"), self, 
     228                    objectName="open-action", 
     229                    toolTip=self.tr("Open selected widget"), 
     230                    triggered=self.openSelected, 
     231                    enabled=False) 
     232 
     233        self.__removeSelectedAction = \ 
     234            QAction(self.tr("Remove"), self, 
     235                    objectName="remove-selected", 
     236                    toolTip=self.tr("Remove selected items"), 
     237                    triggered=self.removeSelected, 
     238                    enabled=False 
     239                    ) 
     240 
     241        shortcuts = [Qt.Key_Delete, 
     242                     Qt.ControlModifier + Qt.Key_Backspace] 
     243 
     244        if sys.platform == "darwin": 
     245            # Command Backspace should be the first 
     246            # (visible shortcut in the menu) 
     247            shortcuts.reverse() 
     248 
     249        self.__removeSelectedAction.setShortcuts(shortcuts) 
     250 
     251        self.__renameAction = \ 
     252            QAction(self.tr("Rename"), self, 
     253                    objectName="rename-action", 
     254                    toolTip=self.tr("Rename selected widget"), 
     255                    triggered=self.__onRenameAction, 
     256                    shortcut=QKeySequence(Qt.Key_F2), 
     257                    enabled=False) 
     258 
     259        self.__helpAction = \ 
     260            QAction(self.tr("Help"), self, 
     261                    objectName="help-action", 
     262                    toolTip=self.tr("Show widget help"), 
     263                    triggered=self.__onHelpAction, 
     264                    shortcut=QKeySequence.HelpContents 
     265                    ) 
     266 
    195267        self.__linkEnableAction = \ 
    196268            QAction(self.tr("Enabled"), self, 
     
    256328                self.__newArrowAnnotationAction] 
    257329 
     330    def menuBarActions(self): 
     331        """Return a list of actions that can be inserted into a QMenuBar. 
     332        These actions should have a menu. 
     333 
     334        """ 
     335        return [self.__editMenu.menuAction(), self.__widgetMenu.menuAction()] 
     336 
    258337    def isModified(self): 
    259338        return not self.__undoStack.isClean() 
     
    428507        self.__undoStack.beginMacro(self.tr("Remove")) 
    429508        for item in selected: 
    430             print item 
    431509            if isinstance(item, items.NodeItem): 
    432510                node = self.scene().node_for_item(item) 
     
    559637        if anchor_item and event.button() == Qt.LeftButton: 
    560638            # Start a new link starting at item 
     639            scene.clearSelection() 
    561640            handler = interactions.NewLinkAction(self) 
    562641            scene.set_user_interaction_handler(handler) 
     
    688767            return False 
    689768 
     769        handler = None 
    690770        if (event.key() == Qt.Key_Space and \ 
    691771                self.__quickMenuTriggers & SchemeEditWidget.SpaceKey): 
    692             action = interactions.NewNodeAction(self) 
    693             action.create_new(QCursor.pos()) 
     772            handler = interactions.NewNodeAction(self) 
     773 
     774        elif len(event.text()) and \ 
     775                self.__quickMenuTriggers & SchemeEditWidget.AnyKey: 
     776            handler = interactions.NewNodeAction(self) 
     777            # TODO: set the search text to event.text() and set focus on the 
     778            # search line 
     779 
     780        if handler is not None: 
     781            # Control + Backspace (remove widget action) conflicts with the 
     782            # 'Clear text action in the search widget, so we disable the 
     783            # remove widget action so the text editing follows standard 
     784            # 'look and feel' 
     785            with disabled(self.__removeSelectedAction): 
     786                handler.create_new(QCursor.pos()) 
     787 
    694788            event.accept() 
    695789            return True 
    696790 
    697         if len(event.text()) and \ 
    698                 self.__quickMenuTriggers & SchemeEditWidget.AnyKey: 
    699             action = interactions.NewNodeAction(self) 
    700             # TODO: set the search text to event.text() and set focus on the 
    701             # search line 
    702             action.create_new(QCursor.pos()) 
    703             event.accept() 
    704             return True 
    705  
    706791        return False 
    707792 
     
    713798 
    714799    def __onSelectionChanged(self): 
    715         pass 
     800        selected = self.selectedNodes() 
     801 
     802        enabled = bool(selected) 
     803        self.__openSelectedAction.setEnabled(enabled) 
     804        self.__removeSelectedAction.setEnabled(enabled) 
     805 
     806        if len(selected) == 0: 
     807            self.__openSelectedAction.setText(self.tr("Open")) 
     808            self.__removeSelectedAction.setText(self.tr("Remove")) 
     809 
     810        elif len(selected) == 1: 
     811            self.__openSelectedAction.setText(self.tr("Open")) 
     812            self.__removeSelectedAction.setText(self.tr("Remove")) 
     813 
     814            self.__renameAction.setEnabled(True) 
     815            self.__helpAction.setEnabled(True) 
     816 
     817        else: 
     818            self.__widgetMenu.setEnabled(enabled) 
     819            self.__openSelectedAction.setText(self.tr("Open All")) 
     820            self.__removeSelectedAction.setText(self.tr("Remove All")) 
     821 
     822            self.__renameAction.setEnabled(False) 
     823            self.__helpAction.setEnabled(False) 
    716824 
    717825    def __onNodeAdded(self, node): 
     
    8981006        item = self.scene().item_at(scenePos, items.NodeItem) 
    8991007        if item is not None: 
    900             self.window().widget_menu.popup(globalPos) 
     1008            self.__widgetMenu.popup(globalPos) 
    9011009            return 
    9021010 
     
    9081016            self.__linkMenu.popup(globalPos) 
    9091017            return 
     1018 
     1019    def __onRenameAction(self): 
     1020        selected = self.selectedNodes() 
     1021        if len(selected) == 1: 
     1022            self.editNodeTitle(selected[0]) 
     1023 
     1024    def __onHelpAction(self): 
     1025        nodes = self.selectedNodes() 
     1026        help_url = None 
     1027        if len(nodes) == 1: 
     1028            node = nodes[0] 
     1029            desc = node.description 
     1030            if desc.help: 
     1031                help_url = desc.help 
     1032 
     1033        if help_url is not None: 
     1034            QDesktopServices.openUrl(QUrl(help_url)) 
     1035        else: 
     1036            message_information( 
     1037                self.tr("Sorry there is documentation available for " 
     1038                        "this widget."), 
     1039                parent=self) 
    9101040 
    9111041    def __toggleLinkEnabled(self, enabled): 
  • Orange/OrangeCanvas/gui/utils.py

    r11170 r11208  
    55import os 
    66import sys 
     7import traceback 
    78 
    89from contextlib import contextmanager 
    910 
    1011from PyQt4.QtGui import ( 
    11     QWidget, QGradient, QLinearGradient, QRadialGradient, QBrush, QPainter, 
    12     QStyleOption, QStyle 
     12    QWidget, QMessageBox, QGradient, QLinearGradient, QRadialGradient, QBrush, 
     13    QPainter, QStyleOption, QStyle 
    1314) 
    1415 
     
    3839    finally: 
    3940        qobject.blockSignals(old_state) 
     41 
     42 
     43@contextmanager 
     44def disabled(qobject): 
     45    """Disables a disablable QObject instance. 
     46    """ 
     47    if not (hasattr(qobject, "setEnabled") and hasattr(qobject, "isEnabled")): 
     48        raise TypeError("%r does not have 'enabled' property" % qobject) 
     49 
     50    old_state = qobject.isEnabled() 
     51    qobject.setEnabled(False) 
     52    try: 
     53        yield 
     54    finally: 
     55        qobject.setEnabled(old_state) 
    4056 
    4157 
     
    147163        brush.setColor(brush.color().darker(factor)) 
    148164        return brush 
     165 
     166 
     167def message_critical(text, title=None, informative_text=None, details=None, 
     168                     buttons=None, default_button=None, exc_info=False, 
     169                     parent=None): 
     170    """Show a critical message. 
     171    """ 
     172    if not text: 
     173        text = "An unexpected error occurred." 
     174 
     175    if title is None: 
     176        title = "Error" 
     177 
     178    return message(QMessageBox.Critical, text, title, informative_text, 
     179                   details, buttons, default_button, exc_info, parent) 
     180 
     181 
     182def message_warning(text, title=None, informative_text=None, details=None, 
     183                    buttons=None, default_button=None, exc_info=False, 
     184                    parent=None): 
     185    """Show a warning message. 
     186    """ 
     187    if not text: 
     188        import random 
     189        text_candidates = ["Death could come at any moment.", 
     190                           "Murphy lurks about. Remember to save frequently." 
     191                           ] 
     192        text = random.choice(text_candidates) 
     193 
     194    if title is not None: 
     195        title = "Warning" 
     196 
     197    return message(QMessageBox.Warning, text, title, informative_text, 
     198                   details, buttons, default_button, exc_info, parent) 
     199 
     200 
     201def message_information(text, title=None, informative_text=None, details=None, 
     202                        buttons=None, default_button=None, exc_info=False, 
     203                        parent=None): 
     204    """Show an information message box. 
     205    """ 
     206    if title is None: 
     207        title = "Information" 
     208    if not text: 
     209        text = "I am not a number." 
     210 
     211    return message(QMessageBox.Information, text, title, informative_text, 
     212                   details, buttons, default_button, exc_info, parent) 
     213 
     214 
     215def message_question(text, title, informative_text=None, details=None, 
     216                     buttons=None, default_button=None, exc_info=False, 
     217                     parent=None): 
     218    """Show an message box asking the user to select some 
     219    predefined course of action (set by buttons argument). 
     220 
     221    """ 
     222    return message(QMessageBox.Question, text, title, informative_text, 
     223                   details, buttons, default_button, exc_info, parent) 
     224 
     225 
     226def message(icon, text, title=None, informative_text=None, details=None, 
     227            buttons=None, default_button=None, exc_info=False, parent=None): 
     228    """Show a message helper function. 
     229    """ 
     230    if title is None: 
     231        title = "Message" 
     232    if not text: 
     233        text = "I am neither a postman nor a doctor." 
     234 
     235    if buttons is None: 
     236        buttons = QMessageBox.Ok 
     237 
     238    if details is None and exc_info: 
     239        details = traceback.format_exc(limit=20) 
     240 
     241    mbox = QMessageBox(icon, title, text, buttons, parent) 
     242 
     243    if informative_text: 
     244        mbox.setInformativeText(informative_text) 
     245 
     246    if details: 
     247        mbox.setDetailedText(details) 
     248 
     249    if default_button is not None: 
     250        mbox.setDefaultButton(default_button) 
     251 
     252    return mbox.exec_() 
Note: See TracChangeset for help on using the changeset viewer.