Package Camelot :: Package camelot :: Package view :: Package controls :: Module navpane |
[frames] | no frames]

# Source Code for Module Camelot.camelot.view.controls.navpane

      1  #  ============================================================================
      2  #
      3  #  Copyright (C) 2007-2008 Conceptive Engineering bvba. All rights reserved.
      4  #  www.conceptive.be / project-camelot@conceptive.be
      5  #
      6  #  This file is part of the Camelot Library.
      7  #
      8  #  This file may be used under the terms of the GNU General Public
      9  #  License version 2.0 as published by the Free Software Foundation
     10  #  and appearing in the file LICENSE.GPL included in the packaging of
     11  #  this file.  Please review the following information to ensure GNU
     12  #  General Public Licensing requirements will be met:
     13  #  http://www.trolltech.com/products/qt/opensource.html
     14  #
     15  #  If you are unsure which license is appropriate for your use, please
     16  #  review the following information:
     17  #  http://www.trolltech.com/products/qt/licensing.html or contact
     18  #  project-camelot@conceptive.be.
     19  #
     20  #  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
     21  #  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     22  #
     23  #  For use of this library in commercial applications, please contact
     24  #  project-camelot@conceptive.be
     25  #
     26  #  ============================================================================
     27
     28  """left navigation pane"""
     29
     30  import logging
     31  logger = logging.getLogger( 'camelot.view.controls.navpane' )
     32
     33  from PyQt4.QtCore import Qt
     34  from PyQt4 import QtGui, QtCore
     35
     36  from camelot.view.model_thread import post
     37  from camelot.action import addActions, createAction
     38  from camelot.view.controls.modeltree import ModelItem, ModelTree
     39  from appscheme import scheme
     40
     41  QT_MAJOR_VERSION = float( '.'.join( str( QtCore.QT_VERSION_STR ).split( '.' )[0:2] ) )
     42
     43  _ = lambda x:x
     44
     45  from camelot.view.controls.user_translatable_label import UserTranslatableLabel
     46
     47 -class PaneCaption( UserTranslatableLabel ):
     48      """Navigation pane Caption"""
     49 -    def __init__( self,
     50                   text,
     51                   textbold = True,
     52                   textindent = 3,
     53                   width = 160,
     54                   height = 32,
     55                   objectname = 'PaneCaption',
     56                   parent = None ):
     57
     58          super(UserTranslatableLabel, self).__init__(text, parent)
     59
     60          if textbold:
     61              self.textbold()
     62
     63          font = self.font()
     64          font.setPointSize( font.pointSize() + 2 )
     65          self.setFont( font )
     66
     67          self.setIndent( textindent )
     68
     69          self.setObjectName( objectname )
     70
     71          style = """
     72          QLabel#PaneCaption {
     73            margin: 3px 0 0 3px;
     74            border: 1px solid %s;
     75            color: %s;
     76            background-color: %s;
     77          }
     78          """ % ( scheme.bordercolor(),
     79                 scheme.captiontextcolor(),
     80                 scheme.captionbackground() )
     81
     82          self.setStyleSheet( style );
     83          self.setFixedHeight( height )
     84          self.resize( width, height )
     85
     86 -    def textbold( self ):
     87          font = self.font()
     88          font.setBold( True )
     89          font.setPointSize( font.pointSize() + 1 )
     90          self.setFont( font )
     91
     92
     93 -class PaneButton( QtGui.QWidget ):
     94      """Custom made navigation pane pushbutton"""
     95
     96 -    def __init__( self,
     97                   text,
     98                   buttonicon = '',
     99                   textbold = True,
    100                   textleft = True,
    101                   width = 160,
    102                   height = 32,
    103                   objectname = 'PaneButton',
    104                   parent = None,
    105                   index = 0 ):
    106
    107          QtGui.QWidget.__init__( self, parent )
    108
    109          if textleft:
    110              option = QtGui.QBoxLayout.LeftToRight
    111          else:
    112              option = QtGui.QBoxLayout.RightToLeft
    113          self.layout = QtGui.QBoxLayout( option )
    114          self.layout.setSpacing( 0 )
    115          self.layout.setContentsMargins( 3, 0, 0, 0 )
    116
    117          if buttonicon:
    118              self.icon = QtGui.QLabel()
    119              self.icon.setPixmap( QtGui.QPixmap( buttonicon ) )
    120              self.layout.addWidget( self.icon )
    121
    122          self.label = UserTranslatableLabel(text, parent)
    123
    124          self.layout.addWidget( self.label, 2 )
    125
    126          self.setLayout( self.layout )
    127
    128          if textbold:
    129              self.textbold()
    130
    131          self.setObjectName( objectname )
    132
    133          self.stylenormal = """
    134          QWidget#PaneButton * {
    135            margin: 0;
    136            padding-left: 3px;
    137            color : %s;
    138            border-color : %s;
    139            background-color : %s;
    140          }
    141          """ % ( scheme.textcolor(),
    142                 scheme.bordercolor(),
    143                 scheme.normalbackground() )
    144
    145          self.stylehovered = """
    146          QWidget#PaneButton * {
    147            margin: 0;
    148            padding-left: 3px;
    149            color : %s;
    150            background-color : %s;
    151          }
    152          """ % ( scheme.textcolor(),
    153                 scheme.hoveredbackground() )
    154
    155          self.styleselected = """
    156          QWidget#PaneButton * {
    157            margin: 0;
    158            padding-left: 3px;
    159            color : %s;
    160            background-color : %s;
    161          }
    162          """ % ( scheme.selectedcolor(),
    163                 scheme.selectedbackground() )
    164
    165          self.styleselectedover = """
    166          QWidget#PaneButton * {
    167            margin: 0;
    168            padding-left: 3px;
    169            color : %s;
    170            background-color : %s;
    171          }
    172          """ % ( scheme.selectedcolor(),
    173                 scheme.selectedbackground( inverted = True ) )
    174
    175          self.setStyleSheet( self.stylenormal )
    176          self.setFixedHeight( height )
    177          self.resize( width, height )
    178          self.selected = False
    179          self.index = index
    180
    181 -    def textbold( self ):
    182          font = self.label.font()
    183          font.setBold( True )
    184          self.label.setFont( font )
    185
    186 -    def enterEvent( self, event ):
    187          if self.selected:
    188              self.setStyleSheet( self.styleselectedover )
    189          else:
    190              self.setStyleSheet( self.stylehovered )
    191
    192 -    def leaveEvent( self, event ):
    193          if self.selected:
    194              self.setStyleSheet( self.styleselected )
    195          else:
    196              self.setStyleSheet( self.stylenormal )
    197
    198 -    def mousePressEvent( self, event ):
    199          if self.selected:
    200              return
    201          else:
    202              self.selected = True
    203              self.setStyleSheet( self.styleselectedover )
    204              # Python shortcut SIGNAL, any object can be passed
    205              self.emit( QtCore.SIGNAL( 'indexselected' ),
    206                        ( self.index, self.label.text() ) )
    207
    208
    209 -class NavigationPane( QtGui.QDockWidget ):
    210      """ms office-like navigation pane in Qt"""
    211
    212 -    def __init__( self, app_admin, objectname = 'NavigationPane', parent = None ):
    213          QtGui.QDockWidget.__init__( self, parent )
    214          self.app_admin = app_admin
    215          self.setFeatures( QtGui.QDockWidget.NoDockWidgetFeatures )
    216          self.parent = parent
    217          self.currentbutton = -1
    218          self.caption = PaneCaption( '' )
    219          self.setTitleBarWidget( self.caption )
    220          self.setObjectName( objectname )
    221          self.buttons = []
    222          self.content = QtGui.QWidget()
    223          self.content.setObjectName( 'NavPaneContent' )
    224          header_labels = ['']
    225          layout = QtGui.QVBoxLayout()
    226          layout.setSpacing( 1 )
    227          layout.setContentsMargins( 1, 1, 1, 1 )
    228          self.treewidget = ModelTree( header_labels, self )
    229          layout.addWidget( self.treewidget )
    230          self.setMinimumWidth(QtGui.QFontMetrics(QtGui.QApplication.font()).averageCharWidth()*40)
    231          self.content.setLayout( layout )
    232          self.setWidget( self.content )
    233          #
    234          # set minimum with to 0 as long as we are using the navigation pane as a
    235          # dockwidget, because this dockwidget is not collapsible
    236          #
    237          self.setMinimumWidth(0)
    238          # Tried selecting QDockWidget but it's not working
    239          # so we must undo this margin in children stylesheets :)
    240          #style = 'margin: 0 0 0 3px;'
    241          #self.setStyleSheet(style)
    242          self.connect( self.app_admin, self.app_admin.auth_changed_signal, self.auth_update )
    243          self.auth_update()
    244
    245 -    def auth_update(self):
    246          post(self.app_admin.get_sections, self.set_sections)
    247
    248 -    def get_sections(self):
    249          return self.sections
    250
    251 -    def set_sections(self, sections):
    252          logger.debug('set sections')
    253          from PyQt4.QtTest import QTest
    254          #
    255          # current button might no longer exisst once we set
    256          # the new sections
    257          #
    258          self.currentbutton = -1
    259          for b in self.buttons:
    260              b.deleteLater()
    261          self.sections = sections
    262          self.buttons = [PaneButton( section.get_verbose_name(), section.get_icon().getQPixmap(), index=i ) for i,section in enumerate(sections)]
    263          self.setcontent( self.buttons )
    264          # use QTest to auto select first button :)
    265          if len( self.buttons ):
    266              firstbutton = self.buttons[0]
    267              QTest.mousePress( firstbutton, Qt.LeftButton )
    268
    269 -    def setcontent( self, buttons ):
    270          logger.debug( 'setting up pane content' )
    271
    272          style = """
    273          QWidget#NavPaneContent {
    274            margin-left: 3px;
    275            background-color: %s;
    276          }
    277          """ % scheme.bordercolor()
    278
    279          self.content.setStyleSheet( style )
    280
    281          # TODO: Should a separator be added between the tree
    282          #       and the buttons?
    283          #self.treewidget = PaneTree(self)
    284
    285
    286          self.treewidget.setObjectName( 'NavPaneTree' )
    287
    288          style = """
    289          QWidget#NavPaneTree {
    290            margin-left: 3px;
    291            border: 1px solid %s;
    292            background-color: rgb(255, 255, 255);
    293          }
    294          """ % scheme.bordercolor()
    295
    296          self.treewidget.setStyleSheet( style )
    297
    298          # context menu
    299          self.treewidget.contextmenu = QtGui.QMenu( self )
    300          newWindowAct = createAction( parent = self,
    301                                      text = _( 'Open in New Window' ),
    302                                      slot = self.popWindow,
    303                                      shortcut = 'Ctrl+Enter' )
    304
    305          addActions( self.treewidget.contextmenu, ( newWindowAct, ) )
    306          self.treewidget.setContextMenuPolicy( Qt.CustomContextMenu )
    307          self.connect( self.treewidget,
    308                       QtCore.SIGNAL( 'customContextMenuRequested(const QPoint &)' ),
    309                       self.createContextMenu )
    310
    311          if buttons:
    312              for b in buttons:
    313                  self.content.layout().addWidget( b )
    314                  self.connect( b, QtCore.SIGNAL( 'indexselected' ), self.change_current )
    315              self.buttons = buttons
    316          else:
    317              self.buttons = []
    318
    319 -    def set_items_in_tree( self, items ):
    320          self.treewidget.clear()
    321          self.treewidget.clear_model_items()
    322          self.items = items
    323
    324          if not items:
    325              return
    326
    327          for item in items:
    328              model_item = ModelItem( self.treewidget, [item.get_verbose_name()] )
    329              self.treewidget.modelitems.append( model_item )
    330
    331          self.treewidget.update()
    332
    333 -    def change_current( self, ( index, text ) ):
    334          logger.debug( 'set current to %s' % text )
    335          if self.currentbutton != -1:
    336              button = self.buttons[self.currentbutton]
    337              button.setStyleSheet( button.stylenormal )
    338              button.selected = False
    339          self.caption.setText( text )
    340          self.currentbutton = index
    341
    342          def get_models_for_tree():
    343              """Return pairs of (Admin, query) classes for items in the tree"""
    344              if index<len(self.sections):
    345                  section = self.sections[index]
    346                  return section.get_items()
    347              return []
    348
    349          post( get_models_for_tree, self.set_items_in_tree )
    350
    351 -    def createContextMenu( self, point ):
    352          logger.debug( 'creating context menu' )
    353          item = self.treewidget.itemAt( point )
    354          if item:
    355              self.treewidget.setCurrentItem( item )
    356              self.treewidget.contextmenu.popup( self.cursor().pos() )
    357
    358 -    def popWindow( self ):
    359          """pops a model window in parent's workspace"""
    360          logger.debug( 'poping a window in parent' )
    361          item = self.treewidget.currentItem()
    362          self.parent.createMdiChild( item )
    363