Example #1
0
    def menu_button(self, main_action_id, ids, widget):
        '''
            Creates an :obj:`.OWButton` with a popup-menu and adds it to the parent ``widget``.
        '''
        id, name, attr_name, attr_value, callback, icon_name = self._expand_id(main_action_id)
        b = OWButton(parent=widget)
        m = QMenu(b)
        b.setMenu(m)
        b._actions = {}

        QObject.connect(m, SIGNAL("triggered(QAction*)"), b, SLOT("setDefaultAction(QAction*)"))

        if main_action_id:
            main_action = OWAction(self._plot, icon_name, attr_name, attr_value, callback, parent=b)
            QObject.connect(m, SIGNAL("triggered(QAction*)"), main_action, SLOT("trigger()"))

        for id in ids:
            id, name, attr_name, attr_value, callback, icon_name = self._expand_id(id)
            a = OWAction(self._plot, icon_name, attr_name, attr_value, callback, parent=m)
            m.addAction(a)
            b._actions[id] = a

        if m.actions():
            b.setDefaultAction(m.actions()[0])
        elif main_action_id:
            b.setDefaultAction(main_action)


        b.setPopupMode(QToolButton.MenuButtonPopup)
        b.setMinimumSize(40, 30)
        return b
Example #2
0
    def menu_button(self, main_action_id, ids, widget):
        '''
            Creates an :obj:`.OWButton` with a popup-menu and adds it to the parent ``widget``. 
        '''
        id, name, attr_name, attr_value, callback, icon_name = self._expand_id(main_action_id)
        b = OWButton(parent=widget)
        m = QMenu(b)
        b.setMenu(m)
        b._actions = {}
        
        QObject.connect(m, SIGNAL("triggered(QAction*)"), b, SLOT("setDefaultAction(QAction*)"))

        if main_action_id:
            main_action = OWAction(self._plot, icon_name, attr_name, attr_value, callback, parent=b)
            QObject.connect(m, SIGNAL("triggered(QAction*)"), main_action, SLOT("trigger()"))
        
        for id in ids:
            id, name, attr_name, attr_value, callback, icon_name = self._expand_id(id)
            a = OWAction(self._plot, icon_name, attr_name, attr_value, callback, parent=m)
            m.addAction(a)
            b._actions[id] = a
            
        if m.actions():
            b.setDefaultAction(m.actions()[0])
        elif main_action_id:
            b.setDefaultAction(main_action)
            
        
        b.setPopupMode(QToolButton.MenuButtonPopup)
        b.setMinimumSize(40, 30)
        return b
Example #3
0
def show(position, panel, link, cursor):
    """Shows a context menu.
    
    position: The global position to pop up
    panel: The music view panel, giving access to mainwindow and view widget
    link: a popplerqt4 LinkBrowse instance or None
    cursor: a QTextCursor instance or None
    
    """
    m = QMenu(panel)

    # selection? -> Copy
    if panel.widget().view.surface().hasSelection():
        m.addAction(panel.actionCollection.music_copy_image)

    if cursor:
        a = m.addAction(icons.get("document-edit"), _("Edit in Place"))

        @a.triggered.connect
        def edit():
            from . import editinplace
            editinplace.edit(panel.widget(), cursor, position)
    elif link:
        a = m.addAction(icons.get("window-new"), _("Open Link in &New Window"))

        @a.triggered.connect
        def open_in_browser():
            import helpers
            helpers.openUrl(QUrl(link.url()))

        a = m.addAction(icons.get("edit-copy"), _("Copy &Link"))

        @a.triggered.connect
        def copy_link():
            QApplication.clipboard().setText(link.url())

    # no actions yet? insert Fit Width/Height
    if not m.actions():
        m.addAction(panel.actionCollection.music_fit_width)
        m.addAction(panel.actionCollection.music_fit_height)
        m.addAction(panel.actionCollection.music_zoom_original)
        m.addSeparator()
        m.addAction(panel.actionCollection.music_sync_cursor)

    # help
    m.addSeparator()
    a = m.addAction(icons.get("help-contents"), _("Help"))

    @a.triggered.connect
    def help():
        import userguide
        userguide.show("musicview")

    # show it!
    if m.actions():
        m.exec_(position)
    m.deleteLater()
Example #4
0
def show(position, panel, link, cursor):
    """Shows a context menu.
    
    position: The global position to pop up
    panel: The music view panel, giving access to mainwindow and view widget
    link: a popplerqt4 LinkBrowse instance or None
    cursor: a QTextCursor instance or None
    
    """
    m = QMenu(panel)
    
    # selection? -> Copy
    if panel.widget().view.surface().hasSelection():
        m.addAction(panel.actionCollection.music_copy_image)
    
    if cursor:
        a = m.addAction(icons.get("document-edit"), _("Edit in Place"))
        @a.triggered.connect
        def edit():
            from . import editinplace
            editinplace.edit(panel.widget(), cursor, position)
    elif link:
        a = m.addAction(icons.get("window-new"), _("Open Link in &New Window"))
        @a.triggered.connect
        def open_in_browser():
            import helpers
            helpers.openUrl(QUrl(link.url()))
        
        a = m.addAction(icons.get("edit-copy"), _("Copy &Link"))
        @a.triggered.connect
        def copy_link():
            QApplication.clipboard().setText(link.url())

    # no actions yet? insert Fit Width/Height
    if not m.actions():
        m.addAction(panel.actionCollection.music_fit_width)
        m.addAction(panel.actionCollection.music_fit_height)
        m.addAction(panel.actionCollection.music_zoom_original)
        m.addSeparator()
        m.addAction(panel.actionCollection.music_sync_cursor)
    
    # help
    m.addSeparator()
    a = m.addAction(icons.get("help-contents"), _("Help"))
    @a.triggered.connect
    def help():
        import userguide
        userguide.show("musicview")
    
    # show it!
    if m.actions():
        m.exec_(position)
    m.deleteLater()
Example #5
0
class TableView(QTableView):
    def __init__(self, parent):
        QTableView.__init__(self, parent)

        # Set the title header
        self.header_column_count = 0
        self.header = HeaderView(Qt.Horizontal, self)
        self.header.setClickable(True)
        self.connect(self.header, SIGNAL("right_clicked"), self.displayHeadersActionsMenu)
        self.setHorizontalHeader(self.header)
        self.setMouseTracking(True)
        self.header_menu = QMenu(self)

        self.setAlternatingRowColors(True)

    def updateHeadersActions(self):
        # clean the current actions list:

        if self.header_column_count == self.header.count():
            # column didn't change
            return

        self.header_column_count = self.header.count()

        for action in self.header_menu.actions():
            self.removeAction(action)

        for col in xrange(self.header.count()):
            col_label = self.model().headerData(col, Qt.Horizontal).toString()
            action = QAction(col_label, self.header)
            action.setCheckable(True)
            action.setChecked(not self.header.isSectionHidden(col))
            self.connect(action, SIGNAL("triggered()"), self.updateDisplayedColumns)
            self.header_menu.addAction(action)

    def displayHeadersActionsMenu(self, event):
        self.header_menu.exec_(event.globalPos())

    def updateDisplayedColumns(self):

        for menu_item_no, menu_item in enumerate(self.header_menu.actions()):
            if menu_item.isChecked():
                self.header.showSection(menu_item_no)
            else:
                self.header.hideSection(menu_item_no)

        print self.sizeHint()

    def parentResizeEvent(self, event):
        pass
Example #6
0
 def slotShowContextMenu(self, pos):
     hit = self.webview.page().currentFrame().hitTestContent(pos)
     menu = QMenu()
     if hit.linkUrl().isValid():
         a = self.webview.pageAction(QWebPage.CopyLinkToClipboard)
         a.setIcon(icons.get("edit-copy"))
         a.setText(_("Copy &Link"))
         menu.addAction(a)
         menu.addSeparator()
         a = menu.addAction(icons.get("window-new"),
                            _("Open Link in &New Window"))
         a.triggered.connect(
             (lambda url: lambda: self.slotNewWindow(url))(hit.linkUrl()))
     else:
         if hit.isContentSelected():
             a = self.webview.pageAction(QWebPage.Copy)
             a.setIcon(icons.get("edit-copy"))
             a.setText(_("&Copy"))
             menu.addAction(a)
             menu.addSeparator()
         a = menu.addAction(icons.get("window-new"),
                            _("Open Document in &New Window"))
         a.triggered.connect((lambda url: lambda: self.slotNewWindow(url))(
             self.webview.url()))
     if menu.actions():
         menu.exec_(self.webview.mapToGlobal(pos))
Example #7
0
    def customContextMenu(self, point):
        popup_menu = self.createStandardContextMenu()

        # Select the word under the cursor.
        cursor = self.cursorForPosition(point)
        cursor.select(QTextCursor.WordUnderCursor)
        self.setTextCursor(cursor)

        # Check if the selected word is misspelled and offer spelling
        # suggestions if it is.
        if self.textCursor().hasSelection():
            text = unicode(self.textCursor().selectedText())
            if not self.spell_dict.check(text):
                spell_menu = QMenu('Spelling Suggestions')
                for word in self.spell_dict.suggest(text):
                    action = SpellAction(word, spell_menu)
                    action.correct.connect(self.correctWord)
                    spell_menu.addAction(action)
                # Only add the spelling suggests to the menu if there are
                # suggestions.
                if len(spell_menu.actions()) != 0:
                    popup_menu.insertSeparator(popup_menu.actions()[0])
                    popup_menu.insertMenu(popup_menu.actions()[0], spell_menu)

        popup_menu.exec_(self.mapToGlobal(point))
Example #8
0
def menu_sessions(parent):
    m = QMenu(parent)
    m.setTitle(_('menu title', '&Session'))
    m.triggered.connect(slot_session_action)
    import sessions
    for name in sessions.sessionNames():
        a = m.addAction(name.replace('&', '&&'))
        a.setObjectName(name)
    qutil.addAccelerators(m.actions())
    return m    
Example #9
0
def menu_sessions(parent):
    m = QMenu(parent)
    m.setTitle(_('menu title', '&Session'))
    m.triggered.connect(slot_session_action)
    import sessions
    for name in sessions.sessionNames():
        a = m.addAction(name.replace('&', '&&'))
        a.setObjectName(name)
    qutil.addAccelerators(m.actions())
    return m
Example #10
0
def menu_file_open_recent(parent):
    m = QMenu(parent)
    m.setTitle(_("Open &Recent"))
    m.triggered.connect(slot_file_open_recent_action)
    import recentfiles
    for url in recentfiles.urls():
        f = url.toLocalFile()
        dirname, basename = os.path.split(f)
        text = "{0}  ({1})".format(basename, util.homify(dirname))
        m.addAction(text).url = url
    qutil.addAccelerators(m.actions())
    return m
Example #11
0
def menu_file_open_recent(parent):
    m = QMenu(parent)
    m.setTitle(_("Open &Recent"))
    m.triggered.connect(slot_file_open_recent_action)
    import recentfiles
    for url in recentfiles.urls():
        f = url.toLocalFile()
        dirname, basename = os.path.split(f)
        text = "{0}  ({1})".format(basename, util.homify(dirname))
        m.addAction(text).url = url
    qutil.addAccelerators(m.actions())
    return m
Example #12
0
def menu_file_new_from_template(parent):
    m = QMenu(parent)
    m.setTitle(_("New from &Template"))
    m.triggered.connect(slot_file_new_from_template_action)
    from snippet import model, actions, snippets
    groups = {}
    for name in sorted(model.model().names()):
        variables = snippets.get(name).variables
        group = variables.get('template')
        if group:
            action = actions.action(name, m)
            if action:
                groups.setdefault(group, []).append(action)
    for group in sorted(groups):
        for action in groups[group]:
            m.addAction(action)
        m.addSeparator()
    qutil.addAccelerators(m.actions())
    return m
Example #13
0
def menu_file_new_from_template(parent):
    m = QMenu(parent)
    m.setTitle(_("New from &Template"))
    m.triggered.connect(slot_file_new_from_template_action)
    from snippet import model, actions, snippets
    groups = {}
    for name in sorted(model.model().names()):
        variables = snippets.get(name).variables
        group = variables.get('template')
        if group:
            action = actions.action(name, m)
            if action:
                groups.setdefault(group, []).append(action)
    for group in sorted(groups):
        for action in groups[group]:
            m.addAction(action)
        m.addSeparator()
    qutil.addAccelerators(m.actions())
    return m
Example #14
0
 def slotShowContextMenu(self, pos):
     hit = self.webview.page().currentFrame().hitTestContent(pos)
     menu = QMenu()
     if hit.linkUrl().isValid():
         a = self.webview.pageAction(QWebPage.CopyLinkToClipboard)
         a.setIcon(icons.get("edit-copy"))
         a.setText(_("Copy &Link"))
         menu.addAction(a)
         menu.addSeparator()
         a = menu.addAction(icons.get("window-new"), _("Open Link in &New Window"))
         a.triggered.connect((lambda url: lambda: self.slotNewWindow(url))(hit.linkUrl()))
     else:
         if hit.isContentSelected():
             a = self.webview.pageAction(QWebPage.Copy)
             a.setIcon(icons.get("edit-copy"))
             a.setText(_("&Copy"))
             menu.addAction(a)
             menu.addSeparator()
         a = menu.addAction(icons.get("window-new"), _("Open Document in &New Window"))
         a.triggered.connect((lambda url: lambda: self.slotNewWindow(url))(self.webview.url()))
     if menu.actions():
         menu.exec_(self.webview.mapToGlobal(pos))
class NgiiDataUtils:
    """QGIS Plugin Implementation."""
    mainMenuTitle = u"NGII"
    mainMenu = None
    menuBar = None

    menuActions = []
    toolbarActions = []

    def __init__(self, iface):
        # Save reference to the QGIS interface
        self.iface = iface

        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)

        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(self.plugin_dir, 'i18n',
                                   'NgiiDataUtils_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        self.pluginIsActive = False
        self.dockwidget = None

    def initGui(self):
        # 메뉴와 툴바에 추가할 항목 정의
        menuIcons = ['icon.png']
        menuTexts = [u'국토지리정보원 공간정보 중첩 검사']
        menuActions = [self.togglePanel]

        assert (len(menuIcons) == len(menuTexts))
        assert (len(menuTexts) == len(menuActions))

        # 기존 NGII 메뉴가 있으면 재사용. 없으면 추가
        self.addNgiiMenu(menuIcons, menuTexts, menuActions)
        # self.togglePanel()

    def addNgiiMenu(self, menuIcons, menuTexts, menuActions):
        # https://gis.stackexchange.com/questions/227876/finding-name-of-qgis-toolbar-in-python
        qgisMenuBar = self.iface.mainWindow().menuBar()

        # 이미 NGII 메뉴 있는지 찾아보기
        ngiiMenu = None
        for action in qgisMenuBar.actions():
            if action.text() == self.mainMenuTitle:
                ngiiMenu = action.menu()
                break

        # 없음 만들고 있음 그냥 사용
        if ngiiMenu is None:
            self.mainMenu = QMenu(self.iface.mainWindow())
            self.mainMenu.setTitle(self.mainMenuTitle)
            qgisMenuBar.insertMenu(
                self.iface.firstRightStandardMenu().menuAction(),
                self.mainMenu)
        else:
            self.mainMenu = ngiiMenu

        # 이미 NGII 툴바 있는지 찾아보기
        ngiiToolbar = None
        for toolbar in self.iface.mainWindow().findChildren(QToolBar):
            # if toolbar.objectName() == self.mainMenuTitle:
            if toolbar.windowTitle() == self.mainMenuTitle:
                ngiiToolbar = toolbar
                break

        # 없음 만들고 있음 그냥 사용
        if ngiiToolbar is None:
            self.toolbar = self.iface.addToolBar(self.mainMenuTitle)
            self.toolbar.setObjectName(self.mainMenuTitle)
        else:
            self.toolbar = ngiiToolbar

        # 세부 메뉴, 버튼 추가
        self.menuActions = []
        self.toolbarActions = []
        for i in range(0, len(menuTexts)):
            icon = QIcon(
                os.path.join(os.path.dirname(__file__), 'icons', menuIcons[i]))
            text = menuTexts[i]
            action = QAction(icon, text, self.iface.mainWindow())
            self.mainMenu.addAction(action)
            action.triggered.connect(menuActions[i])
            button = self.toolbar.addAction(icon, text, menuActions[i])

            self.menuActions.append(action)
            self.toolbarActions.append(button)

    def removeNgiiMenu(self):
        if self.toolbar is not None:
            # 내가 등록한 툴바 아이템 제거
            for action in self.toolbarActions:
                self.toolbar.removeAction(action)
            # 더이상 항목이 없으면 부모 제거
            if len(self.toolbar.actions()) == 0:
                self.toolbar.deleteLater()

        if self.mainMenu is not None:
            for action in self.menuActions:
                self.mainMenu.removeAction(action)
            # print len(self.mainMenu.actions())
            if len(self.mainMenu.actions()) == 0:
                self.mainMenu.deleteLater()

    #--------------------------------------------------------------------------

    def onClosePlugin(self):
        """Cleanup necessary items here when plugin dockwidget is closed"""

        # print "** CLOSING NgiiDataUtils"

        # disconnects
        self.dockwidget.closingPlugin.disconnect(self.onClosePlugin)

        # remove this statement if dockwidget is to remain
        # for reuse if plugin is reopened
        # Commented next statement since it causes QGIS crashe
        # when closing the docked window:
        # self.dockwidget = None

        self.pluginIsActive = False

    def unload(self):
        if self.dockwidget:
            self.iface.removeDockWidget(self.dockwidget)
        self.removeNgiiMenu()

    #--------------------------------------------------------------------------
    def togglePanel(self):
        if not self.pluginIsActive:
            self.pluginIsActive = True

            # print "** STARTING NgiiDataUtils"

            # dockwidget may not exist if:
            #    first run of plugin
            #    removed on close (see self.onClosePlugin method)
            if self.dockwidget == None:
                # Create the dockwidget (after translation) and keep reference
                self.dockwidget = NgiiDataUtilsDockWidget(self.iface)

            # connect to provide cleanup on closing of dockwidget
            self.dockwidget.closingPlugin.connect(self.onClosePlugin)

            # show the dockwidget
            self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget)
            # 좌우로 붙게 수정
            self.dockwidget.setAllowedAreas(Qt.LeftDockWidgetArea
                                            | Qt.RightDockWidgetArea)

            self.dockwidget.show()
        else:
            if self.dockwidget:
                self.dockwidget.close()
Example #16
0
class MSView(QSplitter):
    modifiedContext = pyqtSignal(object)
    
    def __init__(self, widget, parent=None, **kw):
        QSplitter.__init__(self, Qt.Horizontal, parent)
        self.setFocusPolicy(Qt.StrongFocus)
        self.mainWidget = widget        
        self.addWidget(self.mainWidget)
        
        self.showHide = None        
        
        self.subsidiaryWidget = MSQtCanvas([], "", flags='spectrum')#, subsidiaryWidget=True)
        self.subsidiaryWidget.pw.plotItem.toolBar.hide()
        
        self.subsidiaryWidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.connect(self.subsidiaryWidget, SIGNAL("customContextMenuRequested(const QPoint &)"), self.showContextMenu)
        self.menu=QMenu(self.subsidiaryWidget)
        self.menu.addAction("&Hide...")        
        self.connect(self.menu.actions()[0], SIGNAL("triggered()"), self.subsidiaryWidget.hide)
        
        self.addWidget(self.subsidiaryWidget)
        self.subsidiaryWidget.hide()
        self.barplotdrawn = False
        
        self.connect(self.mainWidget, SIGNAL('drawSpectraRequested'), self.drawSpectrum)
        self.connect(self.mainWidget, SIGNAL('drawSpectra(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), self.drawSpectra)
        self.connect(self.mainWidget, SIGNAL('drawSpectrumByTime'), self.drawSpectrumByTime)        
        self.connect(self.mainWidget, SIGNAL('hideRequested'), self.subsidiaryWidget.hide)
    
    
    def showContextMenu(self, pos):
        if self.subsidiaryWidget.pw.plotItem.vb.hasMoved:
            return self.menu.exec_(QCursor.pos())
        
    @pyqtSlot()
    def drawSpectrum(self, p):
        if p is None:
            return
        mergedSpectra=p.merge(p.spectra)
        self.subsidiaryWidget.pw.clear()        
        self.subsidiaryWidget._plotting([mergedSpectra])
        self.subsidiaryWidget.pw.setTitle("Merged Spectrum@%s-%s"%(str(p.rtmin), str(p.rtmax)))        
        self.subsidiaryWidget.show()
    
    def drawSpectrumByTime(self, t, sample):
        if not sample or not t:
            print "unknown error..."            
            return
        spectra = sample.spectraInRTRange(t.x(), t.x()-2., t.x()+2.)
        if not spectra:
            print "No spectrum found at this retention time"
            return
        closest = sorted(spectra, key=lambda x: abs(t.x()-x.rtmin))[0]
        self.subsidiaryWidget.pw.clear()        
        self.subsidiaryWidget._plotting([closest])
        self.subsidiaryWidget.pw.setTitle("Spectrum@%s"%(str(closest.rtmin)))                        
        self.subsidiaryWidget.show()

    def drawSpectra(self, inf, sup, sample):
        if not sample:
            return
        spectra = sample.spectraInRTRange((inf+sup)/2., inf, sup)
        print [s.rtmin for s in spectra]
Example #17
0
    def registerAction(self, action, menuName, callback=None):
        """ register an action to the manager's main menu """
        if not hasattr(self, '_registeredDbActions'):
            self._registeredDbActions = {}

        if callback is not None:
            invoke_callback = lambda x: self.invokeCallback(callback)

        if menuName is None or menuName == "":
            self.addAction(action)

            if menuName not in self._registeredDbActions:
                self._registeredDbActions[menuName] = list()
            self._registeredDbActions[menuName].append(action)

            if callback is not None:
                QObject.connect(action, SIGNAL("triggered(bool)"), invoke_callback)
            return True

        # search for the menu
        actionMenu = None
        helpMenuAction = None
        for a in self.menuBar.actions():
            if not a.menu() or a.menu().title() != menuName:
                continue
            if a.menu() != self.menuHelp:
                helpMenuAction = a

            actionMenu = a
            break

        # not found, add a new menu before the help menu
        if actionMenu is None:
            menu = QMenu(menuName, self)
            if helpMenuAction is not None:
                actionMenu = self.menuBar.insertMenu(helpMenuAction, menu)
            else:
                actionMenu = self.menuBar.addMenu(menu)

        menu = actionMenu.menu()
        menuActions = menu.actions()

        # get the placeholder's position to insert before it
        pos = 0
        for pos in range(len(menuActions)):
            if menuActions[pos].isSeparator() and menuActions[pos].objectName().endswith("_placeholder"):
                menuActions[pos].setVisible(True)
                break

        if pos < len(menuActions):
            before = menuActions[pos]
            menu.insertAction(before, action)
        else:
            menu.addAction(action)

        actionMenu.setVisible(True)  # show the menu

        if menuName not in self._registeredDbActions:
            self._registeredDbActions[menuName] = list()
        self._registeredDbActions[menuName].append(action)

        if callback is not None:
            QObject.connect(action, SIGNAL("triggered(bool)"), invoke_callback)

        return True
Example #18
0
class QuestionDlg(QDialog):
    def __init__(self, parent=None):
        super(QuestionDlg,self).__init__(parent)
        # self.setStyleSheet("background-image:url('image/panelbg.jpg'); border: 2px; border-radius 2px;")
        # self.createDb()
        # return

        self.db = QSqlDatabase.addDatabase("QSQLITE");  
        self.db.setDatabaseName("studentNew.db")
        if not self.db.open():
            QMessageBox.warning(None, "错误",  "数据库连接失败: %s" % self.db.lastError().text())
            sys.exit(1)

        self.g_curClassName = ""
        self.deleteTmpdata()

        self.setWindowFlags(Qt.CustomizeWindowHint)
        # self.setStyleSheet("border: 2px; border-radius 2px;")
        # self.setWindowFlags(Qt.FramelessWindowHint)
        self.setStyleSheet("background-color: rgba(132, 171, 208, 200);")

        self.tabWidget=QTabWidget(self)
        self.tabWidget.currentChanged.connect(self.changeTab)
        # tabWidget.setTabShape(QTabWidget.Triangular)
        self.tabWidget.setStyleSheet("QTabWidget::pane{border-width:1px;border-color:rgb(48, 104, 151);\
            border-style: outset;background-color: rgb(132, 171, 208);\
            background: transparent;} \
            QTabWidget::tab-bar{border-width:0px;}\
            QTabBar::tab { height: 60px; width: 260px; color:rgb(0, 0, 255); font-size:20px; font-weight:bold;} \
            QTabBar::tab:hover{background:rgb(255,255, 255, 100);} \
            QTabBar::tab:selected{border-color:green;background-color:white;color:green;}")
        # tabWidget.setStyleSheet("QTabBar::tab:hover{background:rgb(255,255, 255, 100);}")
        self.btngroup = QButtonGroup()
        self.popMenu = QMenu(self)
        entry1 = self.popMenu.addAction("正确")
        self.connect(entry1,SIGNAL('triggered()'), lambda : self.answerRight())
        entry2 = self.popMenu.addAction("错误")
        self.connect(entry2,SIGNAL('triggered()'), lambda : self.answerWrong())
        entry3 = self.popMenu.addAction("替换")
        self.connect(entry3,SIGNAL('triggered()'), lambda : self.resetStudent())

        # Create the first tab page.
        self.w1=QWidget()
        self.w1.setAccessibleName("w1tab")
        self.genOneTab()
        
        # Create the second tab page.
        self.w2=QWidget()
        self.w2.setAccessibleName("w2tab")        
        self.genTwoTab()

        self.tabWidget.addTab(self.w1,"")
        self.tabWidget.addTab(self.w2,"班级学生信息管理")
        self.tabWidget.resize(940,700)

        btnclose = QPushButton(self)
        btnclose.setToolTip("关闭")
        btnclose.setText("╳")
        btnclose.setGeometry(915, 5, 20, 20)
        btnclose.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255)")
        btnclose.clicked.connect(self.close)
        btnMinimized = QPushButton(self)
        btnMinimized.setToolTip("最小化")
        btnMinimized.setText("▁")
        btnMinimized.setGeometry(890, 5, 20, 20)
        btnMinimized.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255)")
        btnMinimized.clicked.connect(lambda: self.showMinimized())
        self.btnSysMenu = QPushButton(self)
        # self.btnSysMenu.setText("▼")
        self.btnSysMenu.setGeometry(865, 5, 20, 20)
        self.btnSysMenu.setToolTip("系统设置")
        self.btnSysMenu.clicked.connect(lambda: self.showMinimized())
        menufont = QFont("宋体", 10)
        popMenu = QMenu(self)
        entry1 = popMenu.addAction("所有学生提问信息清零")
        entry1.setFont(menufont)
        self.connect(entry1,SIGNAL('triggered()'), self.initStudent)
        entry2 = popMenu.addAction("清除本堂课提问人员")
        entry2.setFont(menufont)
        self.connect(entry2,SIGNAL('triggered()'), self.deleteTmpdata)
        entry3 = popMenu.addAction("关于...")
        entry3.setFont(menufont)
        self.connect(entry3,SIGNAL('triggered()'), self.aboutMe)
        entry4 = popMenu.addAction("导出...")
        entry4.setFont(menufont)
        self.connect(entry4,SIGNAL('triggered()'), self.exportNotice)

        self.btnSysMenu.setMenu(popMenu)
        self.btnSysMenu.setStyleSheet("QPushButton::menu-indicator {image: url('image/sysmenu.png');subcontrol-position: right center;} ")
        # self.btnSysMenu.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255);")

        authorinfo = QLabel(self.tabWidget)
        # authorinfo.setToolTip("关闭")
        authorinfo.setText("程序设计:汕头市大华路第一小学 赵小娜,有任何问题请反馈至[email protected]。")
        authorinfo.setGeometry(20, 665, 470, 26)
        authorinfo.setFont(QFont('Courier New'))
        authorinfo.setStyleSheet("background-color:rgba(255, 255, 255,160); font-size:12px;border: 1px solid rgb(60,200,255,200);color:rgba(0,0,0,220);border-radius:12px;")

        self.setWindowTitle("课堂随机提问")
        self.setWindowIcon(QIcon("image/start.ico"))
        self.setGeometry(100, 20, 940, 700)

        # self.changeTab()

        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2)

        self.btn_start.setMyarg('start')
        
        # print(self.btn_start.getMyarg())

        self.connect(self.btn_start, SIGNAL("clicked()"), self.startChoice)
        # self.connect(self.w1title, SIGNAL("currentIndexChanged(int)"), self.changeTitle)
        # self.connect(self.btn_start2, SIGNAL("clicked()"), self.startChoice)
        # self.connect(self.w2title, SIGNAL("currentIndexChanged(int)"), self.changeTitle)
        self.btngroup.buttonClicked[int].connect(self.btns_click)
        # self.connect(self.btn_start,  SIGNAL("myslot(PyQt_PyObject)"), self.myslot)  
        # self.connect(self.btngroup, SIGNAL("buttonClicked(int)"), lambda:self.btns_click())

    def myslot(self, text):  
        # print(text, self.dict_choices)
        self.g_curbtn = text
        if self.g_curbtn not in self.dict_choices:
            self.btnSysMenu.setFocus()
            return

        # print(self.btngroup.button(int(self.g_curbtn)).parent())
        # print(type(self.btngroup.button(int(self.g_curbtn)).parentWidget()))
        pos = self.btngroup.button(int(self.g_curbtn)).parent().mapToGlobal(self.btngroup.button(int(self.g_curbtn)).pos())
        width = self.btngroup.button(int(self.g_curbtn)).rect().height()
        # print("-----", pos, width)
        pos.setY(pos.y()+width-5)

        indx = 0
        for istate in self.dict_choices[self.g_curbtn]:
            if istate == '1':
                self.popMenu.actions()[indx].setEnabled(True)
            elif istate == '0':
                self.popMenu.actions()[indx].setEnabled(False)
            indx += 1
        self.popMenu.exec_(pos)
        self.btnSysMenu.setFocus()
    # def on_context_menu(self, point):
    #     print(point)
    #     self.popMenu.exec_(self.button.mapToGlobal(point)) 

    def btns_click(self, btnid):
        # curclassname = self.tabWidget.tabText(0)
        query = QSqlQuery(self.db)
        # cur = conn.cursor()
        today = datetime.date.today()
        self.g_curbtn = str(btnid).zfill(2)
        if self.g_curbtn not in self.dict_choices:
            self.btngroup.button(int(self.g_curbtn)).setStyleSheet(stylesheetstr_new)
            query.exec_("select count(*) from tmprecord where stusn='" + str(self.g_curbtn) + "'")
            query.next()            
            if query.value(0) == 0:
                query.prepare("insert into tmprecord (classname, stusn, datequestion) values (:classname, :stusn, :datequestion)")
                query.bindValue(":classname", self.g_curClassName)
                query.bindValue(":stusn", self.g_curbtn)
                query.bindValue(":datequestion", today)
                query.exec_() 
                
            self.dict_choices[self.g_curbtn] = "111"
        else:
            self.btngroup.button(int(self.g_curbtn)).setStyleSheet(stylesheetstr_old)
            self.btngroup.button(int(self.g_curbtn)).setIcon(QIcon())            
            query.exec_("delete from tmprecord where stusn='"+ str(self.g_curbtn) + "'")            
            self.dict_choices.pop(self.g_curbtn)

        self.btnSysMenu.setFocus()

    def exportNotice(self):
        query = QSqlQuery(self.db)
        query.exec_("select stusn, stuname, classname, rightquestions, wrongquestions from student" ) 
        lstInfo = [["学号","姓名", "班级", "回答正确次数", "回答错误次数"]]
        while(query.next()):
            lstInfo.append([query.value(0),query.value(1),query.value(2),query.value(3),query.value(4)])

        from xlwt import Workbook,easyxf
        book = Workbook(encoding='ascii')
            # 'pattern: pattern solid,  fore_colour white;'
        style = easyxf(
            'font: height 280, name 黑体;'
            'align: vertical center, horizontal center;'
            )
        style2 = easyxf('font: height 260, name 仿宋_GB2312, bold True; align: vertical center, horizontal left;')
        style3 = easyxf('font: height 260, name 仿宋_GB2312, bold True; align: vertical center, horizontal left, wrap True;')

        sheet1 = book.add_sheet('学生提问情况汇总',cell_overwrite_ok=True)
        # sheet1.write(0,7,flagtxt, easyxf('font: height 200, name 黑体;align: vertical center, horizontal right;'))
        sheet1.write_merge(0,0,0,4, '学生提问情况汇总表',style)
        sheet1.row(0).height_mismatch = 1
        sheet1.row(0).height = 5*256

        sheet1.col(0).width = 10*256
        sheet1.col(1).width = 25*256
        sheet1.col(2).width = 25*256
        sheet1.col(3).width = 20*256
        sheet1.col(4).width = 20*256
        
        tmprows = 1
        for item in lstInfo:
            stusn               = item[0]
            stuname             = item[1]
            classname           = item[2]
            rightquestions      = item[3]
            wrongquestions      = item[4]

            sheet1.write(tmprows,0,stusn, style2)
            sheet1.write(tmprows,1,stuname, style2)
            sheet1.write(tmprows,2,classname, style2)
            sheet1.write(tmprows,3,rightquestions, style2)
            sheet1.write(tmprows,4,wrongquestions, style2)
            tmprows += 1
        # print(tmprows)
        sheet1.header_str = "".encode()
        sheet1.footer_str = "".encode()

        # book.save('d:/simple.xls')
        # print(QDir.home().dirName() , QDir.homePath ())
        filename = QDir.homePath () + "\学生提问情况汇总表.xls" 
        try:
            book.save(filename)
        except  Exception as e:
            QMessageBox.warning(self, "写入错误", "错误号:"+str(e.errno)+"\n错误描述:"+e.strerror+"\n请关闭已经打开的%s文档!" % filename)
        QMessageBox.about (self, "导出成功", "请查看文档:%s" % filename)

    def aboutMe(self):
        strinfo = """本软件采用python3.4编写,界面采用qt4.8的python绑定。
                    \n版本所有:汕头市大华路第一小学赵小娜老师。
                    \n有任何问题请反馈至[email protected]。
                    """
        QMessageBox.information(None, "关于", strinfo)
        
    def initStudent(self):
        query = QSqlQuery(self.db)
        ret = query.exec_("update student set wrongquestions=0") 
        ret = query.exec_("update student set rightquestions=0")  
        QMessageBox.information(None, "提示", "已清除所有学生的累计提问情况。")


    def deleteTmpdata(self):
        query = QSqlQuery(self.db)
        ret = query.exec_("delete from tmprecord where 1=1" )   
        if self.g_curClassName != "":     
            QMessageBox.information(None, "提示", "已清除本次软件启动后的所有已提问过的学生。")
  
    def changeTab(self):
        # pass
        curtab = self.tabWidget.currentIndex()
        # print(curtab, "-")
        if curtab == 1:  ## when click the second tab page ,then pass.
            return
            
        # cur = conn.cursor()
        query = QSqlQuery(self.db)

        ## if current classname is null, then set current tabpage display the first class of classtable
        if self.g_curClassName == "":
            ret = query.exec_("select classname from classtable")
            query.next()
            self.g_curClassName = query.value(0)
            
        self.tabWidget.setTabText(0, self.g_curClassName)
        # print(1)
        strwhere = " and classname like '" + self.g_curClassName + "' ORDER BY stusn"

        self.g_curbtn = ""
        self.dict_choices = {}
        self.studentSnlst = []

        ## clearn the question data of temp record .
        ret= query.exec_("delete from tmprecord where 1=1")
        ret = query.exec_("select stusn, stuname from student where 1=1 " + strwhere)

        ## now update the global data "self.btngroup"
        for indx in range(0, 56):
            self.btngroup.button(indx+1).setText("")
            self.btngroup.button(indx+1).setMyarg(None)       
            self.btngroup.button(indx+1).setStyleSheet(stylesheetstr_old)
            self.btngroup.button(indx+1).setIcon(QIcon())
            self.btngroup.button(indx+1).setEnabled(False)
            self.studentSnlst.append([indx+1,])

        inum = 0
        while (query.next()): 
            inum += 1            
            self.btngroup.button(inum).setText(query.value(1))
            self.btngroup.button(inum).setMyarg(query.value(0))       
            self.btngroup.button(inum).setStyleSheet(stylesheetstr_old)
            self.btngroup.button(inum).setIcon(QIcon())
            self.btngroup.button(inum).setEnabled(True)

        # print(inum, len(self.btngroup.buttons()))        

        self.group_animation = groupAnimation(self.studentSnlst, self.btngroup)

    def mousePressEvent(self, event):
        # print('a')
        if event.button() == Qt.RightButton:
            QDialog.mousePressEvent(self,event)
            return
        # print(event.sender(), event.button())
        self.offset = event.pos()
        # print(self.offset)

    def mouseMoveEvent(self, event):
        # print('sss')
        if hasattr(self, 'offset'):
            x=event.globalX()
            y=event.globalY()
            x_w = self.offset.x()
            y_w = self.offset.y()
            self.move(x-x_w, y-y_w)
        else:
            pass

    #######======= studentModel ============###############
    def newStudent(self):
        # Calc the missing number:
        row = self.StudentModel.rowCount()

        if row > 0:
            oldNumList = []
            for i in range(0, row):
                oldNumList.append(int(self.StudentModel.index(i,2).data()))
            
            allNumberList = list(range(1, oldNumList[-1]+1))
            for i in range(0, allNumberList[-1]):
                if oldNumList[i] != allNumberList[i]:
                    missingNum = allNumberList[i]
                    break
            if len(oldNumList) == len(allNumberList):
                missingNum = allNumberList[i] +1
        else:
            missingNum = 1

        self.StudentModel.insertRow(row)
        self.StudentView.scrollToBottom()
        self.StudentModel.setData(self.StudentModel.index(row, 1), self.g_curClassName)
        self.StudentModel.setData(self.StudentModel.index(row, 2), str(missingNum).zfill(2))
        self.StudentModel.setData(self.StudentModel.index(row, 4), 0)
        self.StudentModel.setData(self.StudentModel.index(row, 5), 0)

    def removeStudent(self):
        index = self.StudentView.currentIndex()
        row = index.row()             
        if QMessageBox.question(self, "删除确认", "是否要删除当前选中记录?", "确定", "取消") == 0:
            self.StudentModel.removeRows(row, 1)
            self.StudentModel.submitAll()
            self.StudentModel.database().commit()

    def revertStudent(self):
        self.StudentModel.revertAll()
        self.StudentModel.database().rollback()

    def saveStudent(self):
        self.StudentModel.database().transaction()
        if self.StudentModel.submitAll():
            self.StudentModel.database().commit()
            # print("save success!  ->commit")
        else:
            self.StudentModel.revertAll()
            self.StudentModel.database().rollback()

    #######======= classModel ============###############
    def newClass(self):
        row = self.ClassnameModel.rowCount()
        self.ClassnameModel.insertRow(row)

    def removeClass(self):
        index = self.ClassnameView.currentIndex()
        row = index.row()   
        curClassname =  index.sibling(index.row(),0).data()
        strwhere = "classname like '" + curClassname + "'"
        self.StudentModel.setFilter(strwhere)
        self.StudentModel.select()
        # print(self.StudentModel.rowCount(), "----", )
        if QMessageBox.question(self, "删除确认", "删除班级意味着会删除本班所有人员信息。是否要删除当前选中记录?", "确定", "取消") == 0:
            self.ClassnameModel.removeRows(row, 1)
            self.ClassnameModel.submitAll()
            self.ClassnameModel.database().commit()

            self.StudentModel.removeRows(0, self.StudentModel.rowCount())
            self.StudentModel.submitAll()
            self.StudentModel.database().commit()

    def revertClass(self):
        self.ClassnameModel.revertAll()
        self.ClassnameModel.database().rollback()

    def saveClass(self):
        query = QSqlQuery(self.db)

        # record the old class name
        lstOldClassName = {}
        lstOldClassid = []
        query.exec_("select rowid, classname from classtable" )        
        while(query.next()):
            lstOldClassName[query.value(0)] = query.value(1)
            lstOldClassid.append(query.value(0))
        # print(lstOldClassName)

        # Update the class Table
        self.ClassnameModel.database().transaction()
        if self.ClassnameModel.submitAll():
            self.ClassnameModel.database().commit()
            # print("save success!  ->commit")
        else:
            QMessageBox.warning(None, "错误",  "请检查班级中名称,不能出现同名班级!")
            self.ClassnameModel.revertAll()
            self.ClassnameModel.database().rollback()

        # print(lstOldClassid)

        lstNewClassName = {}
        query.exec_("select rowid, classname from classtable where rowid in " + str(tuple(lstOldClassid)) )        
        while(query.next()):
            lstNewClassName[query.value(0)] = query.value(1)            

        # print(lstOldClassName, '=========')
        # print(lstNewClassName, '~~~~~~~~~')

        for i in lstOldClassName:
            oldclassname = lstOldClassName[i]
            newclassname = lstNewClassName[i]
            if oldclassname != newclassname:
                # print(oldclassname, newclassname, '++++++++')
                # print("update student set classname=" + newclassname + " where classname='" + oldclassname + "'")
                query.exec_("update student set classname='" + newclassname + "' where classname='" + oldclassname + "'")
                self.StudentModel.setFilter("classname = '" + newclassname + "'")
                self.StudentModel.select()

        lstClassName = []      
        query.exec_("select classname from classtable" ) 
        while(query.next()):
            lstClassName.append(query.value(0))
        self.StudentView.setItemDelegateForColumn(1,  ComboBoxDelegate(self, lstClassName, self.db))

    def dbclick(self, indx):
        if type(indx.sibling(indx.row(),0).data()) != QPyNullVariant:
            classname = indx.sibling(indx.row(),0).data()
            
            strwhere = "classname like '" + classname + "'"
            self.StudentModel.setFilter(strwhere)
            self.StudentModel.setSort(2, Qt.AscendingOrder)
            self.StudentModel.select()
            
            self.g_curClassName = classname
            self.tabWidget.setTabText(0, self.g_curClassName)

    def dbclick2(self, indx):
        if indx.column() == 2:
            self.StudentView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        else:
            self.StudentView.setEditTriggers(QAbstractItemView.DoubleClicked)
        

    def genTwoTab(self, tabtitle=""):
        # Create the tab title sytle.
        tabtitle = QLabel()
        tabtitle.setFont(QFont('Courier New', 20))
        tabtitle.setText("班级学生信息管理")
        tabtitle.setStyleSheet("border: 1px solid blue; color:rgba(0,0,255, 220);\
            background-color:rgba(201,201,201,60);\
            border-radius: 6px; \
            padding: 1px 18px 1px 20px;\
            min-width: 8em;")
        tabtitle.setMinimumHeight(50);
        titleLayout = QHBoxLayout()
        titleLayout.addWidget(tabtitle)
        titleLayout.setAlignment(tabtitle, Qt.AlignCenter)

       
        # Create the classnameView
        self.ClassnameView = QTableView()
        self.ClassnameModel = QSqlTableModel(self.ClassnameView)
        self.ClassnameModel.setTable("classtable")
        # self.ClassnameModel.setRelation(2, QSqlRelation("mentalmodel", "id", "name"));
        self.ClassnameModel.setEditStrategy(QSqlTableModel.OnManualSubmit)
        self.ClassnameModel.select()

        self.ClassnameModel.setHeaderData(0, Qt.Horizontal, "班级名称")

        # for indx, iheader in enumerate(["classid", "classname"]):
        #     self.ClassnameModel.setHeaderData(indx+1, Qt.Horizontal, iheader)
    
        self.ClassnameView.setModel(self.ClassnameModel)
        # self.ClassnameView.setColumnHidden(0, True)
        # self.ClassnameView.show()
        self.ClassnameView.verticalHeader().setFixedWidth(30)
        self.ClassnameView.verticalHeader().setStyleSheet("color: red;font-size:20px; ");
        self.ClassnameView.setStyleSheet("QTableView{background-color: rgb(250, 250, 200, 0);"  
                    "alternate-background-color: rgb(141, 163, 0);}"
                    "QTableView::item:hover {background-color: rgba(100,200,220,100);} ") 
        self.ClassnameView.setStyleSheet("font-size:16px; ");
        self.ClassnameView.setSelectionMode(QAbstractItemView.SingleSelection)
        # self.ClassnameView.dataChanged.connect(self.dataChanged)

        # self.ClassnameView.setSizePolicy(QSizePolicy.Expanding,     QSizePolicy.Expanding)

        # the second list
        self.StudentView = QTableView()
        self.StudentModel = QSqlTableModel(self.StudentView)
        self.StudentModel.setTable("student")
        # self.StudentModel.setRelation(2, QSqlRelation("mentalmodel", "id", "name"));
        self.StudentModel.setEditStrategy(QSqlTableModel.OnManualSubmit)
        # self.StudentModel.select()

        query = QSqlQuery(self.db)
        strwhere = " 1=1 "
        if self.g_curClassName == "":
            ret = query.exec_("select classname from classtable")
            query.next()
            firstClassName = query.value(0)
            strwhere += " and classname like '" + firstClassName + "'"
            
        self.StudentModel.setFilter(strwhere)
        self.StudentModel.select()

        for indx, iheader in enumerate(["班级名称", "学生编号", "学生姓名", "答对次数", "答错次数"]):
            self.StudentModel.setHeaderData(indx+1, Qt.Horizontal, iheader)
    
        self.StudentView.setModel(self.StudentModel)
        self.StudentView.setColumnHidden(0, True)

        # query = QSqlQuery(self.db)  
        lstClassName = []      
        query.exec_("select classname from classtable" ) 
        while(query.next()):
            lstClassName.append(query.value(0))

        self.StudentView.setItemDelegateForColumn(1,  ComboBoxDelegate(self, lstClassName, self.db))
        # self.StudentView.show()
        self.StudentView.verticalHeader().setFixedWidth(30)
        self.StudentView.verticalHeader().setStyleSheet("color: red;font-size:20px; background-color: rgb(250, 250, 200, 100)");
        self.StudentView.setStyleSheet("QTableView{background-color: rgb(250, 250, 200, 0);"  
                    "alternate-background-color: rgb(141, 163, 250);}"
                    "QTableView::item:hover {background-color: rgba(10,200,100,200);} "
                    ) 
        self.StudentView.setStyleSheet("font-size:16px;")
        self.StudentView.setSelectionMode(QAbstractItemView.SingleSelection)
        self.StudentView.doubleClicked.connect(self.dbclick2)

        btn_lst1_layout = QGridLayout()
        newusrbtn       = QPushButton("新增")
        savebtn         = QPushButton("保存")
        revertbtn       = QPushButton("撤销")
        removebtn       = QPushButton("删除")
        btn_lst1_layout.addWidget(newusrbtn, 0, 0)
        btn_lst1_layout.addWidget(savebtn, 0, 1)
        btn_lst1_layout.addWidget(revertbtn, 1, 0)
        btn_lst1_layout.addWidget(removebtn, 1, 1)

        newusrbtn.clicked.connect(self.newClass)
        savebtn.clicked.connect(self.saveClass)
        revertbtn.clicked.connect(self.revertClass)
        removebtn.clicked.connect(self.removeClass)

        self.ClassnameView.doubleClicked.connect(self.dbclick)
        

        btnbox2 = QDialogButtonBox(Qt.Horizontal)
        newusrbtn2       = QPushButton("新增")
        savebtn2         = QPushButton("保存")
        revertbtn2       = QPushButton("撤销")
        removebtn2       = QPushButton("删除")
        btnbox2.addButton(newusrbtn2, QDialogButtonBox.ActionRole);
        btnbox2.addButton(savebtn2, QDialogButtonBox.ActionRole);
        btnbox2.addButton(revertbtn2, QDialogButtonBox.ActionRole);
        btnbox2.addButton(removebtn2, QDialogButtonBox.ActionRole);

        newusrbtn2.clicked.connect(self.newStudent)
        savebtn2.clicked.connect(self.saveStudent)
        revertbtn2.clicked.connect(self.revertStudent)
        removebtn2.clicked.connect(self.removeStudent)

        # left list layout
        lst_layout_1 = QVBoxLayout()
        lst_layout_1.addWidget(self.ClassnameView)
        lst_layout_1.addLayout(btn_lst1_layout)

        lst_layout_2 = QVBoxLayout()
        lst_layout_2.addWidget(self.StudentView)
        lst_layout_2.addWidget(btnbox2)
        
        lstlayout = QHBoxLayout()
        lstlayout.setMargin(5)
        # lstlayout.addLayout(findbox)
        lstlayout.addLayout(lst_layout_1, 2)
        lstlayout.setMargin(5)
        lstlayout.addLayout(lst_layout_2, 5)
            
        labelClass = QLabel("")
        labelClass.setStyleSheet("background-color:rgba(255, 255, 255,0); color:rgba(0,0,0,0);")
        labelClass.setFixedHeight(40)
        # labelClass.setFixedWidth(100)
        # labelClass.setFont(QFont('宋体', 10))

        bottomlayout = QHBoxLayout()        
        bottomlayout.addWidget(labelClass)        

        tab2layout = QVBoxLayout()
        tab2layout.addLayout(titleLayout)       
        tab2layout.addLayout(lstlayout)
        tab2layout.addLayout(bottomlayout)
        self.w2.setLayout(tab2layout)
        self.w2.setStyleSheet("background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #228888);")
      
    def genOneTab(self):

        tabtitle = QLabel()
        # tabtitle.setFixedHeight(40)
        # tabtitle.setFixedWidth(160)        
        self.btn_start = MyButton("开始")
        self.choicenum_text = QComboBox()
        self.choicenum_text.setObjectName('w1combonums')
        # self.w1title.setStyleSheet("background-image:url('image/panelbg.jpg');")
        
        # Set the title style                
        tabtitle.setFont(QFont('Courier New', 20))
        tabtitle.setText("随堂提问演板")
        tabtitle.setStyleSheet("border: 1px solid blue; color:rgba(0,0,255, 220);\
            background-color:rgba(201,201,201,60);\
            border-radius: 6px; \
            padding: 1px 18px 1px 20px;\
            min-width: 8em;")
        tabtitle.setMinimumHeight(50);
        titleLayout = QHBoxLayout()
        titleLayout.addWidget(tabtitle)
        titleLayout.setAlignment(tabtitle, Qt.AlignCenter)
       
        btnlayout = QGridLayout()
        tmpnum = 0
        for inum in range(0,56):
            irow = tmpnum // g_cols
            icol = tmpnum % g_cols
            tmpnum += 1
            btnlayout.setRowMinimumHeight(irow, 80)
            tmpbtn = MyButton("")
            tmpbtn.setMyarg(None)
            # tmpbtn.setFixedHeight(20)
            tmpbtn.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding))
            tmpbtn.setStyleSheet("border: 1px solid rgb(55,55,255,100);background-color: rgba(255,255,255,20);font-size:16px;")
            self.connect(tmpbtn,  SIGNAL("myslot(PyQt_PyObject)"), self.myslot)
            tmpbtn.setAutoDefault(False)
            self.btngroup.addButton(tmpbtn, inum+1) # stusn is from 1 start

            btnlayout.addWidget(tmpbtn, irow, icol)


        self.btn_start.setIcon(QIcon("image/start.png"))
        self.btn_start.setStyleSheet("border: 1px solid yellow;")
        self.btn_start.setFixedHeight(40)
        self.btn_start.setFixedWidth(100)
        self.btn_start.setFont(QFont('宋体', 18))
        # self.choicenum_text.setFixedHeight(45)
        # self.choicenum_text.setFixedWidth(60)

        ## Set the combox number style
        self.choicenum_text.setFont(QFont('Courier New', 20))
        self.choicenum_text.setFixedHeight(45)
        self.choicenum_text.setStyleSheet("border: 2px solid blue; color:red;font-weight:light;font-size:26px;\
            border-radius: 6px; \
            min-width: 2em; ")
        self.choicenum_text.setEditable(True)
        self.choicenum_text.lineEdit().setReadOnly(True);
        self.choicenum_text.lineEdit().setAlignment(Qt.AlignCenter);

        model = self.choicenum_text.model()
        for row in list(range(1, 7)):
            item = QStandardItem(str(row))
            item.setTextAlignment(Qt.AlignCenter)
            item.setForeground(QColor('red'))
            item.setBackground(QColor(0,200,50, 130))
            model.appendRow(item)
        self.choicenum_text.setCurrentIndex(2)
        # self.choicenum_text.setStyleSheet ("QComboBox::drop-down {border-width: 100px;}")
        # self.choicenum_text.setStyleSheet ("QComboBox::down-arrow {image: url(image/downarrow.png);top: 10px;left: 1px;}")

        bottomlayout = QHBoxLayout()
        bottomlayout.setSizeConstraint(QLayout.SetFixedSize)
        bottomlayout.addStretch(10)
        bottomlayout.addWidget(self.btn_start)
        bottomlayout.setSpacing(5)
        bottomlayout.addWidget(self.choicenum_text)

        tab1layout = QVBoxLayout()
        tab1layout.addLayout(titleLayout)       
        tab1layout.addLayout(btnlayout)
        tab1layout.addLayout(bottomlayout)
                
        self.w1.setLayout(tab1layout)
        self.w1.setStyleSheet("background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #228888);")
         
    def startChoice(self, usernum="", oldbtn=""): 
        # print(oldbtn, 1)

        if oldbtn == "":
            self.dict_choices = {}

        strwhere = " and classname like '" + self.g_curClassName + "'"

        allstudent = []
        lstrecord = []
        query = QSqlQuery(self.db)        
        query.exec_("select stusn from tmprecord where 1=1 " + strwhere) 
        while(query.next()):
            lstrecord.append(query.value(0))
        # print(lstrecord, 'record', "select stusn from student where stusn not in " + str(tuple(lstrecord)))

        query.exec_("select stusn from student where stusn not in " + str(tuple(lstrecord)) + strwhere)
        while(query.next()):
            allstudent.append(query.value(0))

        if usernum == "":
            nums = int(self.choicenum_text.currentText())
        else:
            nums = usernum
        if nums >= len(allstudent):
            query.exec_("delete from tmprecord where 1=1 " + strwhere) #delete tmp date no today            
            allstudent = []
            query.exec_("select stusn from student where 1=1 " + strwhere)
            while(query.next()):
                allstudent.append(query.value(0))
        
        if oldbtn == "":
            random.seed()
            lstchoices = random.sample(allstudent, nums)
            for ibtn in lstchoices:
                self.dict_choices[ibtn] = "111"

            self.group_animation.start()
            QTimer.singleShot(1200, self.stopmovie)
        else:
            random.seed()
            otherbtn = random.sample(allstudent, 1)[0]
            # self.btngroup.button(int(otherbtn)).setFocus()
            self.dict_choices.pop(oldbtn)
            self.dict_choices[otherbtn] = '111'
            self.stopmovie()
        self.btnSysMenu.setFocus()

    def stopmovie(self):
        self.group_animation.stop()
        for isn in self.studentSnlst:
            # print(isn)
            self.btngroup.button(int(isn[0])).setStyleSheet(stylesheetstr_old)
            self.btngroup.button(int(isn[0])).setIcon(QIcon())
        
        classname = self.tabWidget.tabText(0)
        query = QSqlQuery(self.db)        
        today = datetime.date.today()
        for ibtn in self.dict_choices:
            self.btngroup.button(int(ibtn)).setStyleSheet(stylesheetstr_new)
            query.exec_("select count(*) from tmprecord where stusn='" + str(ibtn) + "'")
            query.next()
            if query.value(0) == 0:               
                query.prepare("insert into tmprecord (classname, stusn, datequestion) values (:classname, :stusn, :datequestion)")
                query.bindValue(":classname", classname)
                query.bindValue(":stusn", ibtn)
                query.bindValue(":datequestion", today)
                query.exec_()
    
    def answerRight(self):
        # print(self.g_curbtn)
        value = self.g_curbtn
        if value not in self.dict_choices:
            return

        self.btngroup.button(int(value)).setIcon(QIcon("image/smile.png"))
        self.btngroup.button(int(value)).setIconSize(QSize(20,20))
        
        query = QSqlQuery(self.db)
        query.exec_("select rightquestions from student where stusn='" + value + "'")
        query.next()
        studentRightQuestions = query.value(0) + 1
        query.exec_("update student set rightquestions=" + str(studentRightQuestions) + " where stusn='" + value + "'")
                
        ###########
        if self.dict_choices[value] == "101":
            query.exec_("select wrongquestions from student where stusn='" + value + "'")
            query.next()
            studentWrongQuestions = query.value(0) - 1
            query.exec_("update student set wrongquestions=" + str(studentWrongQuestions) + " where stusn='" + value + "'")
            
        self.dict_choices[value] = "011"

    def answerWrong(self):
        value = self.g_curbtn
        if value not in self.dict_choices:
            return

        self.btngroup.button(int(value)).setIcon(QIcon("image/cry.png"))
        self.btngroup.button(int(value)).setIconSize(QSize(20,20))
        # self.btngroup.button(int(value)).setStyleSheet("border-image: url(image/ex_stu.png);")
        
        query = QSqlQuery(self.db)
        query.exec_("select wrongquestions from student where stusn='" + value + "'")
        query.next()
        studentWrongQuestions = query.value(0) + 1
        query.exec_("update student set wrongquestions=" + str(studentWrongQuestions) + " where stusn='" + value + "'")
        
        if self.dict_choices[value] == "011":
            query.exec_("select rightquestions from student where stusn='" + value + "'")
            query.next()
            studentRightQuestions = query.value(0) - 1
            query.exec_("update student set rightquestions=" + str(studentRightQuestions) + " where stusn='" + value + "'")
            
        self.dict_choices[value] = "101"

    def resetStudent(self):
        value = self.g_curbtn
        if value not in self.dict_choices:
            return

        query = QSqlQuery(self.db)

        if self.dict_choices[value] == "011":        
            query.exec_("select rightquestions from student where stusn='" + value + "'")
            query.next()
            studentRightQuestions = query.value(0) - 1
            query.exec_("update student set rightquestions=" + str(studentRightQuestions) + " where stusn='" + value + "'")

        if self.dict_choices[value] == "101":
            query.exec_("select wrongquestions from student where stusn='" + value + "'")
            query.next()
            studentWrongQuestions = query.value(0) - 1
            query.exec_("update student set wrongquestions=" + str(studentWrongQuestions) + " where stusn='" + value + "'")
            
        self.startChoice(usernum=1, oldbtn=value)
        # print("---reset___")

        # curmenu.actions()[0].setEnabled(True)
        # curmenu.actions()[1].setEnabled(True)
        # self.choiceOneStudent(value)

    def createDb(self):
        conn = sqlite3.connect("studentNew.db") 
        cur = conn.cursor()
        sqlstr = 'create table student (id integer primary key, \
            classname varchar(20), \
            stusn varchar(20), \
            stuname varchar(20), \
            rightquestions integer, \
            wrongquestions integer, \
            FOREIGN KEY(classname) REFERENCES classtable(classname))'
        # print(sqlstr)

        sqlstr2 = 'create table tmprecord (id integer primary key, \
            classname varchar(20), \
            stusn varchar(20), \
            datequestion date)'

        sqlstr3 = 'create table classtable (classname varchar(20) PRIMARY KEY)'
        
        cur.execute(sqlstr3)
        conn.commit()
        cur.execute(sqlstr2)
        conn.commit()
        cur.execute(sqlstr)
        conn.commit()

        strdelete = "delete from student where 1=1"
        cur.execute(strdelete)
        conn.commit()
        strdelete = "delete from tmprecord where 1=1"
        cur.execute(strdelete)
        conn.commit()
        # print(sqlstr2)

        # cur.execute(sqlstr) 
        # conn.commit()
        # cur.execute(sqlstr2) 
        # conn.commit()

        # insert example data
        strsql = "insert into classtable values (?)"
        cur.execute(strsql, ("三(3)班",))
        conn.commit()
        cur.execute(strsql, ("三(4)班",))
        conn.commit()


        a03lst = ["曾忆谊","赵佳泉","翁文秀","林珑","郑铭洁","林泽思","吴崇霖","陈思嘉","欧阳月孜","郭展羽","詹伟哲","黄佳仪","杨秋霞","周奕子","林楚杰","欧伊涵","许腾誉","陈唯凯","陈树凯","林彦君","张钰佳","高锴","杨博凯","林妙菲","林楚鸿","陈展烯","姚静茵","吴欣桐","范思杰","肖佳","马思广","许一帆","姚奕帆","陈海珣","吴黛莹","吴育桐","肖凯帆","林欣阳","叶茂霖","姚楷臻","陈嘉豪","陈琦","杨子楷","陈炎宏","陈幸仪","杨景畅","罗暖婷","郑馨"]
        a04lst = ["罗恩琪","王可","曾祥威","谢濡婷","温嘉凯","许洁仪","肖欣淇","陈凯佳","林天倩","李乐海","吴文慧","黄文婷","万誉","陈进盛","张裕涵","陈振嘉","王巧玲","林珮琪","陈炜楷","杨健","赵泽锴","张凤临","蔡子丹","陈烨杰","廖妍希","林树超","夏培轩","陈锦森","李星","蔡依婷","姚容创","姚凯扬","沈嘉克","周凡","张玉川","邱金迅","陈菲敏","陈星翰","朱煜楷","郑泽洪","钱剑非","罗奕丰","陈杜炜","林知钦"]
        strsql = "insert into student values (?, ?, ?, ?,?,?)" 
        for i in list(range(0,len(a03lst))):
            cur.execute(strsql, (None, "三(3)班", str(i+1).zfill(2), a03lst[i], 0, 0))
            conn.commit()
        strsql = "insert into student values (?, ?, ?, ?,?,?)" 
        for i in list(range(0,len(a04lst))):
            cur.execute(strsql, (None, "三(4)班", str(i+1).zfill(2), a04lst[i], 0, 0))
            conn.commit()
        cur.close()
Example #19
0
class QDataTableView(QTableView):
    """
    This is an actual table of waves.
    """

    def __init__(self, model=None, title="Table", *args):
        """
        Initialize the view.

        model is the DataTableModel to use.
        title is the window title.
        """

        QTableView.__init__(self, *args)
        self._app = QApplication.instance().window

        if model is None:
            model = DataTableModel()
        self.setModel(model)
        self.setWindowTitle(title)
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setSelectionMode(QAbstractItemView.ContiguousSelection) # contiguous instead of extended so that we can easily insert/delete cells more easily.  See note below.
        self.setEditTriggers(QAbstractItemView.AnyKeyPressed | QAbstractItemView.SelectedClicked | QAbstractItemView.DoubleClicked)
        self.horizontalHeader().setMovable(True)

        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.showCellContextMenu)
        
        self.verticalHeader().setContextMenuPolicy(Qt.CustomContextMenu)
        self.verticalHeader().customContextMenuRequested.connect(self.showVerticalHeaderMenu)
        
        self.setupHorizontalHeaderMenu()

    def name(self):
        """Return the name of the table."""
        return self.windowTitle()

    def renameWave(self, wave):
        """
        Create a dialog box to rename a wave.  When the dialog box is filled out and submitted, try to rename the wave.
        """

        # Setup dialog box
        renameWaveDialog = QDialog(self)
        renameWaveUi = Ui_RenameWaveDialog()
        renameWaveUi.setupUi(renameWaveDialog)
        renameWaveUi.oldWaveName.setText(wave.name())
        renameWaveDialog.setVisible(True)
        
        def saveRename():
            """Save button pressed.  Do work to save new name."""
            newName = wave.validateWaveName(str(renameWaveUi.newWaveNameLineEdit.text()))
            if str(renameWaveUi.newWaveNameLineEdit.text()) == "":
                failedMessage = QMessageBox(renameWaveDialog)
                failedMessage.setText("Cannot use a blank name.")
                failedMessage.exec_()
                renameWaveDialog.setVisible(True)
            elif self._app.waves().goodWaveName(newName) and wave.setName(newName):
                renameWaveDialog.close()
            else:
                failedMessage = QMessageBox()
                failedMessage.setText("Unable to rename wave.")
                failedMessage.exec_()
                renameWaveDialog.setVisible(True)
        
        def cancelRename():
            """Cancel button pressed."""
            renameWaveDialog.close()
        
        # connect actions
        renameWaveUi.buttons.accepted.connect(saveRename)
        renameWaveUi.buttons.rejected.connect(cancelRename)
        
    def removeWave(self, visualIndex):
        self.model().removeColumn(visualIndex)

    def addWave(self, wave, visualIndex):
        if self.model().addColumn(wave):
            # The wave was added (i.e. it did not already exist in the table)
            # We need to move the newly added column from the end to where the user clicked
            self.horizontalHeader().moveSection(self.model().columnCount() - 1, visualIndex + 1)

    def insertCells(self):
        """Insert cells into waves based on selected cells in this table."""

        # Sort by rows, so that we start at the top of the waves
        # This is the reason we only do contiguous selections, because
        # tracking which cells to insert into is really difficult otherwise
        selectedCells = self.selectedIndexes()
        selectedCells.sort(None, QModelIndex.row, False)

        # Disconnect the dataModified signal before changing anything, then connect
        # it after changing everything. This way, multiple calls are not emitted
        # in the middle, for no reason.
        # We create the waves list just in case the selectedCells indexes aren't valid
        # aftewards.
        waves = Util.uniqueList(map(lambda x: x.internalPointer(), selectedCells))
        for wave in waves:
            wave.blockSignals(True)

        for cell in selectedCells:
            try:
                cell.internalPointer().insert(cell.row(), "")
            except:
                # The cell did not exist (i.e. the wave does not extend this far)
                # but another wave does, so do not fail completely
                pass
        
        for wave in waves:
            wave.blockSignals(False)
            wave.dataModified.emit()
            wave.lengthChanged.emit()

    def deleteCells(self):
        """Delete cells from waves based on selected cells in this table."""

        # Sort by rows, inverted, so that we start by deleting at the
        # bottom of the waves, and don't screw up index values along
        # the way
        selectedCells = self.selectedIndexes()
        selectedCells.sort(None, QModelIndex.row, True)

        # Disconnect the dataModified signal before changing anything, then connect
        # it after changing everything. This way, multiple calls are not emitted
        # in the middle, for no reason.
        # We create the waves list just in case the selectedCells indexes aren't valid
        # aftewards.
        waves = Util.uniqueList(map(lambda x: x.internalPointer(), selectedCells))
        for wave in waves:
            wave.blockSignals(True)

        for cell in selectedCells:
            try:
                cell.internalPointer().pop(cell.row())
            except:
                # The cell did not exist (i.e. the wave does not extend this far)
                # but another wave does, so do not fail completely
                pass
    
        for wave in waves:
            wave.blockSignals(False)
            wave.dataModified.emit()
            wave.lengthChanged.emit()

    def showCellContextMenu(self, point):
        """Display the menu that occurs when right clicking on a table cell."""
        
        clickedCell = self.indexAt(point)

        if not clickedCell.isValid():
            # User clicked on a part of the table without a cell
            return False

        cellMenu = QMenu(self)
        insertCellAction = QAction("Insert Cells", cellMenu)
        deleteCellAction = QAction("Delete Cells", cellMenu)
        
        cellMenu.addAction(insertCellAction)
        cellMenu.addAction(deleteCellAction)

        # Connect signals
        insertCellAction.triggered.connect(self.insertCells)
        deleteCellAction.triggered.connect(self.deleteCells)

        # Display menu
        cellMenu.exec_(self.mapToGlobal(point))

        # Disconnect signals
        insertCellAction.triggered.disconnect(self.insertCells)
        deleteCellAction.triggered.disconnect(self.deleteCells)

    def showVerticalHeaderMenu(self, point):
        """Display the menu that occurs when right clicking on a vertical header."""

        rowMenu = QMenu(self)
        insertRowAction = QAction("Insert Rows", rowMenu)
        deleteRowAction = QAction("Delete Rows", rowMenu)
        
        rowMenu.addAction(insertRowAction)
        rowMenu.addAction(deleteRowAction)

        # Connect signals
        insertRowAction.triggered.connect(self.insertCells)
        deleteRowAction.triggered.connect(self.deleteCells)

        # Display menu
        rowMenu.exec_(self.mapToGlobal(point))

        # Disconnect signals
        insertRowAction.triggered.disconnect(self.insertCells)
        deleteRowAction.triggered.disconnect(self.deleteCells)

    def setupHorizontalHeaderMenu(self):
        self.horizontalHeader().setContextMenuPolicy(Qt.CustomContextMenu)
        self.horizontalHeader().customContextMenuRequested.connect(self.showHorizontalHeaderMenu)

        self.horizontalHeaderMenu = QMenu(self.horizontalHeader())
        
        # Create actions
        self.renameWaveAction = QAction("Rename Wave", self.horizontalHeaderMenu)
        self.removeWaveAction = QAction("Remove Wave", self.horizontalHeaderMenu)
        self.addWaveMenu = QMenu("Add Wave", self.horizontalHeaderMenu)

        # Add actions to menu
        self.horizontalHeaderMenu.addAction(self.addWaveMenu.menuAction())
        self.horizontalHeaderMenu.addAction(self.renameWaveAction)
        self.horizontalHeaderMenu.addAction(self.removeWaveAction)


    def showHorizontalHeaderMenu(self, point):
        """Display the menu that occurs when right clicking on a column header."""

        logicalIndex = self.horizontalHeader().logicalIndexAt(point)
        visualIndex = self.horizontalHeader().visualIndex(logicalIndex)
        
        self.selectColumn(logicalIndex)

        #print "l: " + str(logicalIndex)
        #print "v: " + str(visualIndex)
        selectedWave = self.model().waves()[logicalIndex]
        
        # Create helper functions, defined for this specific menu location
        def renameWaveHelper():
            self.renameWave(selectedWave)
        def removeWaveHelper():
            #self.removeWave(selectedWave)
            self.removeWave(visualIndex)
        def addWaveHelper(wave):
            self.addWave(wave, visualIndex)
        def addNewWaveHelper():
            wave = Wave(self._app.waves().findGoodWaveName())
            self._app.waves().addWave(wave)
            self.addWave(wave, visualIndex)


        self.addWaveMenu.clear()
        
        # Add "New Wave" entry
        newWaveAction = QAction("New Wave", self.addWaveMenu)
        self.addWaveMenu.addAction(newWaveAction)
        newWaveAction.triggered.connect(addNewWaveHelper)
        
        # Get current list of waves for "add wave to table" menu
        #for wave in self._app.waves().waves().values():
        for wave in self._app.model('appWaves').waves():
            waveAction = AddWaveAction(wave, self.addWaveMenu)
            self.addWaveMenu.addAction(waveAction)
            waveAction.addWaveClicked.connect(addWaveHelper)

        # Connect actions
        self.renameWaveAction.triggered.connect(renameWaveHelper)
        self.removeWaveAction.triggered.connect(removeWaveHelper)
        
        self.horizontalHeaderMenu.exec_(self.mapToGlobal(point))

        # Disconnect actions.  We need to do this or else there will be multiple connections
        # when we open the menu again, and the old connections will have strange visualIndex values
        self.renameWaveAction.triggered.disconnect(renameWaveHelper)
        self.removeWaveAction.triggered.disconnect(removeWaveHelper)
        for waveAction in self.addWaveMenu.actions():
            try:
                waveAction.addWaveClicked.disconnect(addWaveHelper)
            except:
                waveAction.triggered.disconnect(addNewWaveHelper)
   
    def reset(self):
        QTableView.reset(self)
        self.resizeRowsToContents()
        self.resizeColumnsToContents()

    def keyPressEvent(self, event):
        """Capture certain types of keypress events and handle them different ways."""
        # When data has been edited, move to the next row in the column and continue editing.
        currentIndex = self.currentIndex()

        #print "row: " + str(currentIndex.row()) + ", col: " + str(currentIndex.column())
        
        if currentIndex.isValid():
            if self.state() == QAbstractItemView.EditingState:
                if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
                    Util.debug(3, "DataTableView.keyPressEvent", "Enter key pressed in table")
                    newIndex = self.model().createIndex(currentIndex.row() + 1, currentIndex.column())
                    self.setCurrentIndex(newIndex)
                    self.edit(newIndex)
                    self.setCurrentIndex(newIndex)
                    return
                elif event.key() == Qt.Key_Up:
                    Util.debug(3, "DataTableView.keyPressEvent", "Up key pressed in table")
                    newIndex = self.model().createIndex(currentIndex.row() - 1, currentIndex.column())
                    #print "nrow: " + str(newIndex.row()) + ", ncol: " + str(newIndex.column())
                    #self.setCurrentIndex(newIndex)
                    self.setState(QAbstractItemView.NoState)
                elif event.key() == Qt.Key_Down:
                    Util.debug(3, "DataTableView.keyPressEvent", "Down key pressed in table")
                    newIndex = self.model().createIndex(currentIndex.row() + 1, currentIndex.column())
                    #print "nrow: " + str(newIndex.row()) + ", ncol: " + str(newIndex.column())
                    #self.setCurrentIndex(newIndex)
                    self.setState(QAbstractItemView.NoState)
        
        # Nothing found, so resort to default behavior
        QTableView.keyPressEvent(self, event)
Example #20
0
class Dummy:
    instance = None

    def __init__(self, iface):
        from createunbeffl import application as createunbeffl
        from importdyna import application as importdyna
        from exportdyna import application as exportdyna
        from linkflaechen import application as linkflaechen
        from tools import application as tools
        self.plugins = [
            createunbeffl.CreateUnbefFl(iface),
            importdyna.ImportFromDyna(iface),
            exportdyna.ExportToKP(iface),
            linkflaechen.LinkFl(iface),
            tools.QKanTools(iface)
        ]
        Dummy.instance = self

        # Plugins
        self.instances = []

        # QGIS
        self.iface = iface
        self.plugin_dir = os.path.dirname(__file__)
        self.actions = []

        actions = self.iface.mainWindow().menuBar().actions()
        self.menu = None
        for menu in actions:
            if menu.text() == 'QKan':
                self.menu = menu.menu()
                self.menu_action = menu
                break

        self.toolbar = self.iface.addToolBar('QKan')
        self.toolbar.setObjectName('QKan')

    def initGui(self):
        # Create and insert QKan menu after the 3rd menu
        if self.menu is None:
            self.menu = QMenu('QKan', self.iface.mainWindow().menuBar())

            actions = self.iface.mainWindow().menuBar().actions()
            prepend = actions[3]
            self.menu_action = self.iface.mainWindow().menuBar().insertMenu(prepend, self.menu)

        # Calls initGui on all known QKan plugins
        for plugin in self.plugins:
            plugin.initGui()

        self.sort_actions()

    def sort_actions(self):
        # Finally sort all actions
        self.actions.sort(key=lambda x: x.text().lower())
        self.menu.clear()
        self.menu.addActions(self.actions)

    def unload(self):
        from qgis.utils import unloadPlugin
        # Unload all other instances
        for instance in self.instances:
            print('Unloading ', instance.name)
            if not unloadPlugin(instance.name):
                print('Failed to unload plugin!')

        # Remove entries from own menu
        for action in self.menu.actions():
            self.menu.removeAction(action)

        # Remove entries from Plugin menu and toolbar
        for action in self.actions:
            self.iface.removeToolBarIcon(action)

        # Remove the toolbar
        del self.toolbar

        # Remove menu
        self.iface.mainWindow().menuBar().removeAction(self.menu_action)

        # Call unload on all loaded plugins
        for plugin in self.plugins:
            plugin.unload()

    def register(self, instance):
        self.instances.append(instance)

        self.plugins += instance.plugins

    def unregister(self, instance):
        self.instances.remove(instance)

        for plugin in instance.plugins:
            self.plugins.remove(plugin)

    def add_action(self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True,
                   status_tip=None, whats_this=None, parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.__actions list.
        :rtype: QAction
        """

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            self.toolbar.addAction(action)

        if add_to_menu:
            self.menu.addAction(action)

        self.actions.append(action)

        return action
class CFSceneContextMenuMixin:
    " Encapsulates the context menu handling "

    def __init__(self):
        self.menu = None
        self.individualMenus = {}

        # Scene menu preparation
        self.sceneMenu = QMenu()
        self.sceneMenu.addAction(getIcon("filesvg.png"), "Save as SVG...", self.parent().onSaveAsSVG)
        self.sceneMenu.addAction(getIcon("filepdf.png"), "Save as PDF...", self.parent().onSaveAsPDF)
        self.sceneMenu.addAction(getIcon("filepixmap.png"), "Save as PNG...", self.parent().onSaveAsPNG)
        self.sceneMenu.addSeparator()
        self.sceneMenu.addAction(getIcon("copymenu.png"), "Copy to clipboard", self.parent().copyToClipboard)

        # Common menu for all the individually selected items
        self.commonMenu = QMenu()
        # self.commonMenu.addAction(
        #    getIcon( "cutmenu.png" ), "Cut (Ctrl+X)", self.onCut )
        # self.commonMenu.addAction(
        #    getIcon( "copymenu.png" ), "Copy (Ctrl+C)", self.onCopy )
        # self.commonMenu.addSeparator()
        # self.commonMenu.addAction(
        #    getIcon( "trash.png" ), "Delete (Del)", self.onDelete )

        # Non-comment common menu for the individually selected items
        self.nonCommentCommonMenu = QMenu()
        # self.nonCommentCommonMenu.addAction(
        #    getIcon( "customcolors.png" ), "Custom colors...",
        #    self.onCustomColors )
        # self.nonCommentCommonMenu.addAction(
        #    getIcon( "replacetitle.png" ), "Replace text...",
        #    self.onReplaceText )

        # Individual items specific menu: begin
        ifContextMenu = QMenu()
        ifContextMenu.addAction(getIcon("switchbranches.png"), "Switch branch layout", self.onSwitchIfBranch)

        self.individualMenus[IfCell] = ifContextMenu
        # Individual items specific menu: end

        # Menu for a group of selected items
        self.groupMenu = QMenu()
        # self.groupMenu.addAction(
        #    getIcon( "cfgroup.png" ), "Group...",
        #    self.onGroup )
        # self.groupMenu.addAction(
        #    getIcon( "customcolors.png" ), "Custom colors...",
        #    self.onCustomColors )
        # self.groupMenu.addSeparator()
        # self.groupMenu.addAction(
        #    getIcon( "trash.png" ), "Delete (Del)", self.onDelete )

        return

    def onContextMenu(self, event):
        " Triggered when a context menu should be shown "
        selectedItems = self.selectedItems()
        selectionCount = len(selectedItems)
        if selectionCount == 0:
            self.sceneMenu.popup(event.screenPos())
            return

        if selectionCount == 1:
            self.__buildIndividualMenu(selectedItems[0])
        else:
            self.__buildGroupMenu(selectedItems)
        self.menu.popup(event.screenPos())
        return

    def __buildIndividualMenu(self, item):
        " Builds a context menu for the given item "
        self.menu = QMenu()
        if type(item) in self.individualMenus:
            individualPart = self.individualMenus[type(item)]
            self.menu.addActions(individualPart.actions())
            self.menu.addSeparator()
        if not item.isComment():
            self.menu.addActions(self.nonCommentCommonMenu.actions())
            self.menu.addSeparator()
        self.menu.addActions(self.commonMenu.actions())

        # Note: if certain items need to be disabled then it should be done
        #       here

        return

    def __buildGroupMenu(self, items):
        " Builds a context menu for the group of items "
        self.menu = QMenu()
        self.menu.addActions(self.groupMenu.actions())

        # Note: if certain items need to be disabled then it should be done
        #       here

        return

    def onSwitchIfBranch(self):
        " If primitive should switch the branches "
        selectedItems = self.selectedItems()
        for item in selectedItems:
            if item.kind == CellElement.IF:
                item.switchBranches()
        return

    def onCustomColors(self):
        " Custom background and foreground colors "
        print "Custom colors"

    def onReplaceText(self):
        " Replace the code with a title "
        print "Replace title"

    def onDelete(self):
        " Delete the item "
        print "Delete"

    def onGroup(self):
        " Groups items into a single one "
        print "Group"

    def onCopy(self):
        print "Copy"

    def onCut(self):
        print "Cut"
Example #22
0
class MSMainWindow(QMainWindow):
    """Gui of the main window"""

    # MAX_RECENT_FILES = 10
    # start putting links spyder numpy scipy et tutti quanti
    links = (
        "http://numpy.scipy.org/",
        "http://packages.python.org/spyder/",
        "http://www.riverbankcomputing.co.uk/software/pyqt/intro",
    )

    pluginPath = path.normcase("pluginmanager/plugins/")

    def __init__(self, availablePlugins):
        """
        Constructor with all the models needed setup menus
        
        """
        QMainWindow.__init__(self)
        self.setDockOptions(QMainWindow.VerticalTabs | QMainWindow.AnimatedDocks)
        self.plugins = availablePlugins
        self.pluginsInst = []
        settings = QSettings(
            "INRA/INSA", "-".join([QApplication.instance().APPLICATION_NAME_STR, QApplication.instance().VERSION_STR])
        )
        self.recentFiles = list(settings.value("RecentFiles").toStringList())
        self.setStyleSheet(stylesheet)
        self.pipeline = MSPipelineToolBar("Pipeline toolbar", parent=self)
        self.addToolBar(0x1, self.pipeline)

        self._setupModels()
        self._setupUi()
        self._setupMenus()

    def _setupModels(self):
        """
        Warning:Causes segfault when horizontal labels set to True
        
        on aura peu etre a la fin un model par sampleList c'est ce qui parait
        le plus logique
        
        """
        # drag and drop table sample
        self.sampleModel = QStandardItemModel(self)
        self.sampleModel.setHorizontalHeaderLabels(["Sample", "Class"])
        # treeView1
        self.spectraModel = QStandardItemModel(self)
        # treeview2
        self.peakModel = QStandardItemModel(self)
        # treeview3
        self.clusterModel = QStandardItemModel(self)

    def _setupMenus(self):
        # file
        self.fileMenu = QMenu("&File")
        self.fileMenu.setTearOffEnabled(True)
        self.op = QMenu("&Open...", self.fileMenu)
        self.op.setIcon(QIcon(path.normcase("gui/icons/fileopen.png")))

        open_ = QAction("&Open rawfiles", self)
        open_.setToolTip("Open an mzXML or netCDF file")
        open_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_O))
        open_icon = QIcon(path.normcase("gui/icons/fileopen.png"))
        open_.setIcon(open_icon)
        self.op.addAction(open_)

        load_ = QAction("&Open projects...", self)
        load_.setToolTip("load binary file containing saved objects")
        load_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S))
        load_icon = QIcon(QPixmap(path.normcase("gui/icons/project_open.png")))
        load_.setIcon(load_icon)
        self.op.addAction(load_)

        self.fileMenu.addMenu(self.op)

        save_ = QAction("&Save...", self)
        save_.setToolTip("save the actual application model")
        save_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S))
        save_icon = QIcon(path.normcase("gui/icons/save_all.png"))
        save_.setIcon(save_icon)
        self.fileMenu.addAction(save_)

        pkl = QAction("&load a peaklist", self)  # TODO:load peaklist
        pkl.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_P))
        pkl.setToolTip("load a peaklist and process it")
        pkl.setIcon(QIcon(path.normcase("gui/icons/featuredetect.png")))
        self.fileMenu.addAction(pkl)

        convert_ = QAction("&Convert...", self)
        convert_.setEnabled(False)
        convert_.setToolTip("Convert a .wiff file if Analyst(c) is installed")
        convert_icon = QIcon(path.normcase("gui/icons/goto.png"))
        convert_.setIcon(convert_icon)
        self.fileMenu.addAction(convert_)

        a = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Launch a batch")
        a.setEnabled(False)

        b = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Merge")
        b.setToolTip("Merge MRM file")
        # b.setEnabled(False)

        self.fileMenu.addSeparator()
        #
        #        for i in xrange(self.MAX_RECENT_FILES):
        #            a = QAction('', self)
        #            a.setVisible(False)
        #            self.fileMenu.addAction(a)
        #
        #        for i in xrange(min(self.MAX_RECENT_FILES, len(self.recentFiles))):
        #            self.fileMenu.actions()[5+i].setVisible(True)
        #            self.fileMenu.actions()[5+i].setText(self.recentFiles[i].split('/')[-1])

        exit_action = QAction("&Exit", self)
        exit_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Q))
        exit_action.setIcon(QIcon(QPixmap(path.normcase("gui/icons/exit.png"))))
        self.fileMenu.addAction(exit_action)

        self.menuBar().addMenu(self.fileMenu)

        self.editMenu = QMenu("&Edit")
        self.editMenu.setTearOffEnabled(True)
        self.editMenu.addAction(QIcon(path.normcase("gui/icons/edit_undo.png")), "&Undo...")
        self.editMenu.addAction(QIcon(path.normcase("gui/icons/edit_redo.png")), "&Redo...")
        self.editMenu.actions()[0].setEnabled(False)
        self.editMenu.actions()[1].setEnabled(False)
        self.editMenu.addSeparator()
        self.editMenu.addAction(QIcon(path.normcase("gui/icons/run.png")), "&Preferences")
        self.exportMenu = QMenu("&Export...")
        self.exportMenu.setIcon(QIcon(path.normcase("gui/icons/file_export.png")))
        self.exportMenu.addAction("&Peaklist")
        self.exportMenu.addAction("&Clusters intensity matrix")
        self.editMenu.addMenu(self.exportMenu)
        self.menuBar().addMenu(self.editMenu)

        # view
        self.viewMenu = QMenu("&View")
        self.viewMenu.setTearOffEnabled(True)
        self.viewMenu.addAction(
            QIcon(path.normcase("gui/icons/window_duplicate")),
            "&Cascade View",
            self.mdiArea.cascadeSubWindows,
            QKeySequence(Qt.CTRL + Qt.Key_K),
        )
        self.viewMenu.addAction(
            QIcon(path.normcase("gui/icons/view_icon")),
            "&Title View",
            self.mdiArea.tileSubWindows,
            QKeySequence(Qt.CTRL + Qt.Key_N),
        )
        self.viewMenu.addAction(
            QIcon(path.normcase("gui/icons/stop_process.png")),
            "&Close all subWindows",
            self.mdiArea.closeAllSubWindows,
            QKeySequence(Qt.CTRL + Qt.Key_W),
        )

        self.plotting = QMenu("&Plotting...")
        self.plotting.setIcon(QIcon(QPixmap(path.normcase("gui/icons/plot.png"))))
        self.plotting.addAction("&3D Plot")
        # self.plotting.addAction("&Cytoscape web")
        self.plotting.addAction("&Spectrogram Plot")

        # self.multiplePlot = QAction("&Visualize Raw/Treated Data", self)
        # self.multiplePlot.setCheckable(True)
        # self.multiplePlot.setEnabled(False)
        # self.sub_plot_.addAction(self.multiplePlot)

        self.viewMenu.addMenu(self.plotting)
        self.viewMenu.addSeparator()
        self.show_hide = QMenu("&Show/Hide")
        m = self.createPopupMenu()
        m.setTitle("&Show/Hide")
        self.viewMenu.addMenu(m)
        # self.pref = QMenu("&Preferences")

        # self.pref.addAction(self.multiplePlot)
        # self.viewMenu.addMenu(self.pref)
        self.menuBar().addMenu(self.viewMenu)

        # algorithm
        self.algoMenu = QMenu("&Algorithm")
        self.algoMenu.setTearOffEnabled(True)
        self.preProcessing = QMenu("&PreProcessing(experimental)")
        self.preProcessing.addAction("&Smoothing raw data...")
        self.preProcessing.addAction("&Cut off raw data...")
        self.preProcessing.addAction("&Calibration (mz dimension)")
        self.preProcessing.addAction("&Resize sample...")

        self.algoMenu.addMenu(self.preProcessing)

        self.peakPickingMenu = QMenu("&Peack Picking & Alignement(XCMS)", self)
        self.peakPickingMenu.setIcon(QIcon(path.normcase("gui/icons/pickedpeakicon.png")))

        matched = QAction("&MatchedFiltered", self)
        matched.setIcon(QIcon(path.normcase("gui/icons/RLogo")))
        matched.setToolTip("Peak Detection and Integration using MatchedFiltered algorithm")
        self.peakPickingMenu.addAction(matched)

        centwave = QAction("&CentWave", self)
        centwave.setIcon(QIcon(path.normcase("gui/icons/RLogo")))
        centwave.setToolTip("Peak Detection and Integration using CentWave algorithm")
        self.peakPickingMenu.addAction(centwave)
        # peak_.setShortcut(.QKeySequence(CTRL + Key_P))
        # peak_icon=.QIcon(.QPixmap(path.normcase("gui/icons/pickedpeakicon.png")))
        # peak_.setIcon(peak_icon)
        self.algoMenu.addMenu(self.peakPickingMenu)

        self.alignment = QMenu("&Alignment")
        self.alignment.setIcon(QIcon(path.normcase("gui/icons/format_indent_more.png")))
        self.alignment.addAction("&Polynomial fitting(exp)")
        self.alignment.addAction("&DynamicTimeWarping")
        self.alignment.addAction("&ObiWarp")
        self.alignment.actions()[2].setEnabled(False)
        self.algoMenu.addMenu(self.alignment)

        self.algoMenu.addAction("Normalization")

        clust_ = QAction("&Clustering", self)
        clust_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_L))
        clust_icon = QIcon(QPixmap(path.normcase("gui/icons/cluster.png")))
        clust_.setIcon(clust_icon)
        self.algoMenu.addAction(clust_)

        id_ = QAction("&Identification", self)
        id_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_I))
        id_.setToolTip("Try to identify peaks with several methods")
        id_.setIcon(QIcon(QPixmap(path.normcase("gui/icons/findcompound.png"))))
        self.algoMenu.addAction(id_)
        self.menuBar().addMenu(self.algoMenu)

        # tools
        self.toolsMenu = QMenu("&Tools")
        self.toolsMenu.setTearOffEnabled(True)
        web = QAction("&Web Browser", self)
        web.setIcon(QIcon(QPixmap(path.normcase("gui/icons/applications_internet.png"))))
        self.toolsMenu.addAction(web)
        # cyto = QAction("&cytoscape", self)
        # cyto_icon =QIcon(QPixmap(path.normcase("gui/icons/cytoscape.jpeg")))
        # cyto.setIcon(cyto_icon)
        # self.toolsMenu.addAction(cyto)
        editor = QAction("&Editor", self)
        editor.setIcon(QIcon(QPixmap(path.normcase("gui/icons/document_sign.png"))))
        self.toolsMenu.addAction(editor)
        pet = QAction("&Short Periodic Table", self)
        pet.setIcon(QIcon(QPixmap(path.normcase("gui/icons/pet.jpg"))))
        self.toolsMenu.addAction(pet)
        self.menuBar().addMenu(self.toolsMenu)

        # plugins
        self.pluginMenu = QMenu("&Plugins")
        self.pluginMenu.setTearOffEnabled(True)
        instPl = QAction("&Install a plugin", self)
        instPl.setIcon(QIcon(path.normcase("gui/icons/pluginInstall.png")))
        self.pluginMenu.addAction(instPl)
        self.launchingMenu = QMenu("&Launch PLugins", self)
        self.launchingMenu.setIcon(QIcon(path.normcase("gui/icons/plugin")))

        for plug in self.plugins:
            # fullname="".join([self.pluginPath, str(plug)])
            mod = imp.load_source(self.__module__, plug)
            if mod.autoActivation:
                qApp = QApplication.instance()
                name = getattr(mod, "className")
                cls = getattr(mod, name)
                p = cls(qApp.model, self, parent=self)
                # p=qApp.pluginManager.loadPlugin(qApp.model, self, plug.split('/')[-1])
                self.pluginsInst.append(p)
            else:
                self.launchingMenu.addAction(plug.split("/")[-1])
        self.pluginMenu.addMenu(self.launchingMenu)
        self.pluginMenu.addAction(QIcon(path.normcase("gui/icons/process_stop.png")), "&Remove loaded Plugin")
        self.menuBar().addMenu(self.pluginMenu)

        # about
        self.aboutMenu = QMenu("&About")
        self.aboutMenu.setTearOffEnabled(True)
        metms = QAction(QIcon(path.normcase("gui/icons/deluge.png")), "&about metMS...", self)
        self.aboutMenu.addAction(metms)

        pyqt = QAction("&about PyQt4...", self)
        pyqt_icon = QIcon(QPixmap(path.normcase("gui/icons/logo_QT4.png")))
        pyqt.setIcon(pyqt_icon)
        self.aboutMenu.addAction(pyqt)
        metms = QAction("&metMS Documentation", self)
        metms_icon = QIcon(QPixmap(path.normcase("gui/icons/deluge.png")))
        metms.setIcon(metms_icon)
        self.aboutMenu.addAction(metms)
        self.menuBar().addMenu(self.aboutMenu)

    def _setupUi(self, background=None):
        """        
        Make the GUI
        
        """
        # mdi
        self.mdiArea = MSMdiArea(self)
        self.mdiArea.setBackground(QBrush(QPixmap(path.normcase("gui/icons/blac2.png"))))  # QColor(Qt.blue).darker()))
        self.setCentralWidget(self.mdiArea)

        # sample dock widget
        self.sampleDockWidget = QDockWidget("Samples", self)
        # sampleWidget = QWidget()
        self.sampleTableView = MSDragFromTableView()
        self.sampleTableView.setModel(self.sampleModel)
        self.sampleTableView.setSelectionBehavior(1)
        self.sampleTableView.verticalHeader().hide()
        self.sampleTableView.verticalHeader().setDefaultSectionSize(15)
        self.sampleTableView.horizontalHeader().setDefaultSectionSize(150)

        self.sampleDockWidget.setWidget(self.sampleTableView)  # sampleWidget)
        self.sampleDockWidget.visible = True

        # workflow dock
        self.workflowDockWidget = QDockWidget("Visualizer", self)
        self.workflowDockWidget.visible = True

        a = QWidget(self)
        v = QVBoxLayout(a)
        q = QToolBar()
        # self.workingSample = QLabel("Working Sample:None")
        # q.addWidget(self.workingSample)
        q.addWidget(QLabel("ppm :"))
        self.ppmEditer = QDoubleSpinBox()
        self.usePpm = QCheckBox("use ?")
        q.addWidget(self.ppmEditer)
        q.addWidget(self.usePpm)

        q.addSeparator()

        self.removeButton = QToolButton(self)
        self.removeButton.setIcon(QIcon(path.normcase("gui/icons/delete.png")))
        q.addWidget(self.removeButton)

        self.markAsGood = QAction(QIcon(path.normcase("gui/icons/button_ok.png")), "mark peak as good", self)
        self.markAsBad = QAction(QIcon(path.normcase("gui/icons/stop.png")), "mark peak as bad", self)
        self.hideItem = QAction(QIcon(path.normcase("gui/icons/list_remove.png")), "Hide Item", self)

        q.addAction(self.markAsGood)
        q.addAction(self.markAsBad)
        q.addAction(self.hideItem)
        v.addWidget(q)

        self.tabWidget = QTabWidget()
        self.tab = QWidget()
        verticalLayout = QVBoxLayout(self.tab)
        self.treeView = MSToDropTableView()
        self.treeView.verticalHeader().setDefaultSectionSize(20)

        self.treeView.setModel(self.spectraModel)
        self.spectraLabel = QLabel("Sample: None")
        verticalLayout.addWidget(self.treeView)
        verticalLayout.addWidget(self.spectraLabel)
        self.tabWidget.addTab(self.tab, QIcon(path.normcase("gui/icons/spectrumicon.png")), "Spectra")

        self.tab_2 = QWidget()
        verticalLayout_4 = QVBoxLayout(self.tab_2)
        self.treeView_2 = MSToDropTableView()  # MSTreeView(self.tab_2)# QTableView(self)#
        self.treeView_2.verticalHeader().setDefaultSectionSize(20)
        self.treeView_2.setModel(self.peakModel)
        self.peakLabel = QLabel("Sample: None")
        verticalLayout_4.addWidget(self.treeView_2)
        verticalLayout_4.addWidget(self.peakLabel)
        self.tabWidget.addTab(self.tab_2, QIcon(path.normcase("gui/icons/peakicon.png")), "Peaks List")

        self.tab_3 = QWidget()
        verticalLayout_5 = QVBoxLayout(self.tab_3)
        self.treeView_3 = MSToDropTreeView()
        self.treeView_3.setAnimated(True)
        self.treeView_3.setModel(self.clusterModel)
        self.clusterLabel = QLabel("Sample: None")
        verticalLayout_5.addWidget(self.treeView_3)
        verticalLayout_5.addWidget(self.clusterLabel)
        self.tabWidget.addTab(self.tab_3, QIcon(path.normcase("gui/icons/clustering.png")), "Clusters")

        self.tabWidget.setCurrentIndex(0)

        for l in (self.spectraLabel, self.peakLabel, self.clusterLabel):
            l.setAutoFillBackground(True)

        v.addWidget(self.tabWidget)
        self.workflowDockWidget.setWidget(a)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.workflowDockWidget)

        from gui.MetBaseGui import MSIsoCalculator

        self.isoCalc = MSIsoCalculator(self)
        self.isoCalcDockWidget = QDockWidget("isotopes calculation", self)
        self.isoCalcDockWidget.setWidget(self.isoCalc)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.isoCalcDockWidget)
        self.isoCalcDockWidget.setVisible(False)
        self.isoCalcDockWidget.visible = False

        from gui.MetBaseGui import FormulaGenerator

        self.generator = FormulaGenerator(self)
        self.generatorDockWidget = QDockWidget("formula generator", self)
        self.generatorDockWidget.setWidget(self.generator)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.generatorDockWidget)
        self.generatorDockWidget.setVisible(False)
        self.generatorDockWidget.visible = False

        self.compoundTreeView = MSCompoundTreeView(self)
        self.compoundDockWidget = QDockWidget("Compounds", self)
        self.compoundDockWidget.setWidget(self.compoundTreeView)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.compoundDockWidget)
        self.compoundDockWidget.setVisible(False)
        self.compoundDockWidget.visible = False

        self.comparativeTableView = QTableView(self)
        self.comparativeTableView.horizontalHeader().setStretchLastSection(True)
        self.comparativeTableView.verticalHeader().setDefaultSectionSize(20)
        self.comparativeDock = QDockWidget("Comparative View", self)
        self.comparativeDock.setWidget(self.comparativeTableView)
        self.addDockWidget(Qt.DockWidgetArea(0x8), self.comparativeDock)
        self.comparativeDock.setVisible(False)
        self.comparativeDock.visible = False

        self.tabifyDockWidget(self.compoundDockWidget, self.isoCalcDockWidget)
        self.tabifyDockWidget(self.isoCalcDockWidget, self.workflowDockWidget)
        self.tabifyDockWidget(self.workflowDockWidget, self.generatorDockWidget)
        # set the end

        # WARNING: possible that the internal shell widget cause random segfault
        # with the error of QObject::killTimers...? not sure !
        self.shell = QWidget()  # InternalShell(namespace={'metms': QApplication.instance()},
        #              parent=self,
        #              multithreaded=False)
        self.shellDock = QDockWidget("Python Shell", self)
        self.shellDock.setWindowIcon(QIcon(path.normcase("gui/icons/stop.png")))
        self.shellDock.setWidget(self.shell)
        self.shellDock.setMinimumWidth(255)
        self.shellDock.visible = True
        self.addDockWidget(0x2, self.shellDock)

        self.addDockWidget(0x2, self.sampleDockWidget)
        self.tabifyDockWidget(self.shellDock, self.sampleDockWidget)

        self.pb = QProgressBar(self)
        self.pb.setMaximumWidth(245)

        self.stopProcess = QToolButton(self)
        self.stopProcess.setIcon(QIcon(path.normcase("gui/icons/process_stop.png")))
        m = QMenu()
        # self.connect(m, SIGNAL('triggered(QAction*'), QApplication.instance().taskManager.abortByName)
        self.stopProcess.setMenu(m)
        self.stopProcess.setPopupMode(1)  # Menu Button
        # self.connect(self.stopProcess, SIGNAL("clicked()"), self.stopThread)

        self.statusBar().addPermanentWidget(self.stopProcess)
        self.statusBar().addPermanentWidget(self.pb)

    def updateStopProcessMenu(self):
        """
        update the menu of the stop process
        button, based directly on the processes
        stored by the task manager
        
        """
        self.stopProcess.menu().clear()
        for c in QApplication.instance().taskManager:
            self.stopProcess.menu().addAction(c.title)

        # QApplication.instance().taskManager.abort(QApplication.instance().taskManager[-1])

    def addMdiSubWindow(self, plot, title="", showMaximized=False):
        """ 
        Allow addition of new window in the mdiarea
        
        """
        win = self.mdiArea.addSubWindow(plot)
        # print "widget parent", plot.parent()
        win.setAttribute(Qt.WA_DeleteOnClose)
        # win.connect(win, SIGNAL('destroyed(QObject *)'), self.testdestroy)
        # plot.setParent(win)
        win.setWindowTitle(title)
        if showMaximized:
            win.showMaximized()
        else:
            win.resize(400, 300)
        win.show()
        return win

    def updateTreeView(self):
        """
        Tree View update switch spectre/chromato
        
        """
        if self.treeView.model() == self.spectraModel:
            self.treeView.setModel(self.chromaModel)
            self.tabWidget.setTabText(0, "Chroma")
        else:
            self.treeView.setModel(self.spectraModel)
            # self.treeView.setSelectionMode(1)
            self.tabWidget.setTabText(0, "Spectra")

    def addTreeViewModel(self, model1, model2):
        """Add a model """
        self.chromaModel.appendRow(model1)
        self.spectraModel.appendRow(model2)

    def _actionHovered(self, action):
        """emulate tooltip cause they do not work that much"""
        tip = action.toolTip()
        QToolTip.showText(QCursor.pos(), tip)

    def showErrorMessage(self, title, string):
        QMessageBox.critical(self, title, string, 0, 0)

    def showWarningMessage(self, title, string):
        return QMessageBox.warning(self, title, string, QMessageBox.Ok | QMessageBox.Cancel)

    def showInformationMessage(self, title, string):
        QMessageBox.information(self, title, string, 0)

    def updateProgressBar(self, i):
        """update the value of the progress bar for all the treatment"""

        self.pb.setValue(min(i, 100))

    def to_indetermined_mode(self):
        self.pb.setMaximum(0)

    def to_determined_mode(self):
        self.pb.setMaximum(100)

    def showInStatusBar(self, string, time=5000):
        self.statusBar().showMessage(string, time)

    def addInterpreterDock(self, shell):
        self.shellDock = QDockWidget(self)
        self.shellDock.setWidget(shell)
        self.shellDock.setWindowTitle("shell")
        self.addDockWidget(0x2, self.shellDock)

    def showMetMSInformation(self):

        QMessageBox.about(
            self,
            self.tr("About %1").arg("metMS"),
            self.tr(
                """<b>%1 %2</b>
            <br>metabolite Mass Spectrometry
            <p>Copyright &copy; 2010 Marco INSA, INRA
            <br>Licensed under the terms of the CeciLL License
            <p>Developed and maintained by Marco
            <br>Bug reports and feature requests: 
            <a href="http://github.com/jerkos/metms">metMS site</a><br>
            Discussions around the project: 
            <a href="http://groups.google.com/group/spyderlib">Google Group</a>
            <p>This project is part of the BRIDGE project
            <p>Python %3, Qt %4, PyQt %5"""
            )
            .arg("metMS")
            .arg(__version__)
            .arg(platform.python_version())
            .arg(QT_VERSION_STR)
            .arg(PYQT_VERSION_STR),
        )
Example #23
0
class MSQtCanvas(QWidget, MSDialogController):
    """
    DONE:the current peak is not updated while the user press up and down key on the treeView
    TODO: think about a mjor redesign of those classes
    
    """
    
    #linePlotted = pyqtSignal(object, str)
    #lineRemoved = pyqtSignal(object)
    
    def __init__(self, data, title, flags="chroma", parent=None, **k):
        QWidget.__init__(self, parent)
        MSDialogController.__init__(self, 0, parent)
        
        self.model = self.qApp.model
        self.view =  self.qApp.view
      
        self.data=data
        self.title=title
        self.flags=flags
        
        if self.flags == 'peak':
            if self.acTree not in (self.view.treeView_2, self.view.treeView_3):
                print "Unknown Error"
                return
            idx=self.acTree.selectedIndexes()[0]
            s = qApp.instance().dockControl.currentSample[1 if self.acTree is self.view.treeView_2 else 2]
            if s is None:
                print "unknow error"
                return            
            values = map(float, idx.data().toString().split('/')[:2])
            self.currentPeak = s.peakAt(*values)
            #connection to update the selected Peak object
            self.connect(self.acTree, SIGNAL("changedLine"), self.updateCurrentPeak)
        
        self.minX, self.maxX, self.maxY  = [0] * 3
        #if flags != 'peak':
        #    self.minX, self.maxX, self.maxY = self.getMax()
        self.pw = PlotWidget(self.minX, self.maxX, self.maxY,  parent=self, **k)#parent=self,
        #self.pw.setAttribute(Qt.WA_DeleteOnClose)#plotItem.setAttribute(Qt.WA_PaintOnScreen & Qt.WA_PaintUnclipped)
        if k.get('antialiased', False):
            self.pw.setRenderHint(0x01)#antialiasing i suppose
        self.pw.setTitle(title)
        self.pw.updateGrid()

        
        self._setupUi()        
        
        self.connect(self, SIGNAL('linePlotted'), self.updateContextMenu)
        self.connect(self.view.sampleTableView, SIGNAL("disHighlightRequested(QModelIndex)"), self.disHighlightOne)
        self.connect(self.view.sampleTableView, SIGNAL("highlightRequested(QModelIndex)"), self.highlight)
        self.connect(self.view.sampleTableView, SIGNAL("noHighlightRequested()"), self.disHighlight)
        self.connect(self.view.ppmEditer, SIGNAL('valueChanged(double)'), self.redrawAll)
        
        self.drawnItems = {} 
        self.trashItems=[]#why unecessary? nope to collect annotation stuff
        self.textLabels = []
        self.pixmaps = []
        self.dataPoints = None
        
        self._plotting(self.data)#initial plotting
          

    def getMax(self):
        localXmin =[]        
        localXmax = []
        localYmax = []        
        for el in self.data:
            if el is None:
                continue
            localXmin.append(min_f(el.x_data))
            localXmax.append(max_f(el.x_data))
            localYmax.append(max_l(el.y_data))
        return min_f(np.array(localXmin)), max_f(np.array(localXmax)), max_l(np.array(localYmax)) 
    
    
    
    def _plotting(self, data):
        """
        refactor this shit
        c = Line(chrom.x_data, chrom.y_data, 
                 QColor.fromRgbF(*(self.ref.sample.color+(.7,))),
                 parent=self.pw.plotItem.vb, 
                 scene=self.pw.scene())
        
        #test scatter plot
        self.scatter = ScatterPlotItem(x=chrom.x_data, y=chrom.y_data)
        self.pw.addDataItem(self.scatter)
        self.scatter.sigClicked.connect(self.requestSpectra)
        
        """
        if self.flags == 'peak':
            
            self.connect(self.pw.plotItem.vb, SIGNAL('showDiffOrSpectra(PyQt_PyObject)'), self.drawSpectra)
            self.ref = sorted([e for e in data if e is not None], key=lambda x:x.height)[-1]
            ppm = self.view.ppmEditer.value() if self.view.usePpm.isChecked() else self.ref.sample.ppm
            chrom = self.ref.sample.massExtraction(self.ref.mass(), 
                                                   ppm, 
                                                   asChromatogram=True) 
            #show labels
            self.textLabels += self.showTextLabel(chrom.x_data, chrom.y_data)
            #drawing
            color = QColor.fromRgbF(*self.ref.sample.color +(.5, ))

            c = self.pw.plotItem.plot(chrom.x_data, chrom.y_data, pen=color)
            self.drawnItems[self.ref.sample] = c
            # peak's pixmap on the ref peak
            pix= PeakArrowItem(self.ref, 
                               pen=color,
                               brush=color,
                               pos=(self.ref.rt, self.ref.height + (self.ref.height * 6) / 100.),
                               angle=-90,
                               parent=self.pw.plotItem.vb)
            pix.setZValue(1000)
            self.pw.addItem(pix)
            #both these connections are emitted 
            #in peak Indicator by effictivamente qApp
            self.connect(qApp.instance(), SIGNAL("highlightRequested"), c.setHighlighted)
            self.connect(qApp.instance(), SIGNAL('updateBarPlot'), self.barPlot.setPeakGroup) #
            self.emit(SIGNAL('linePlotted'), self.ref.sample.shortName())
     
            #if qApp.instance().lowMemory:
            #    chromatograms=[el.sample.loadAndExtract(el.mass(), el.sample.ppm, asChromatogram=True) \
            #                  for el in data if el != ref and el is not None]
            #else:
            ppm = self.view.ppmEditer.value() if self.view.usePpm.isChecked() else self.ref.sample.ppm
            chromatograms=[el.sample.massExtraction(el.mass(), ppm, asChromatogram=True) \
                          for el in data if el is not None and el != self.ref]
            self.drawEics(chromatograms)
            #initialisation zoom on the peak
            self.pw.setYRange(0., self.ref.height + (self.ref.height * 12) / 100.)
            self.pw.setXRange(self.ref.rtmin - 20, self.ref.rtmax + 20)
            
        elif self.flags == 'chroma':
            ref = [d for d in data if d is not None]
            if not ref:
                print "Error, empty data to plot"
                return 
            self.ref = ref[0] 
            self.textLabels+=self.showTextLabel(self.ref.x_data, self.ref.y_data)
            self.drawEics(data)
                        
        else:#spectrum
            if not data:
                #print "NOTHING TO PLOT"
                return
            self.ref = data[0]
            for el in data:
                c=SpectrumItem(el, centroid=True, scene=self.pw.scene())
                self.pw.addItem(c)
                self.drawnItems[el.sample] = c
                self.pw.plotItem.curves.append(c)    
                self.emit(SIGNAL('linePlotted'), el.sample.shortName()) 
            #just put time information
            if data:
                i=0
                while data[i] is None and i < len(data):
                    i+=1
                self.textLabels+=self.showTextLabel(data[i].x_data, data[i].y_data)
            #setting the range
            #warning: autoRange pw function does not work well
            #on spectrum item
            maxY = max([el.y_data.max() for el in data])
            minX, maxX = min([el.x_data.min() for el in data]), max([el.x_data.max() for el in data])
            self.pw.setXRange(minX, maxX, padding=0) 
            self.pw.setYRange(0., maxY, padding=0)

    
    def drawEics(self, data):
        for chrom in data:
            color = QColor.fromRgbF(*(chrom.sample.color+(.5,))) 
            c=self.pw.plotItem.plot(x=chrom.x_data, y=chrom.y_data, pen=color)
            #c = Line(chrom.x_data, chrom.y_data, 
            #         color,
            #         parent=self.pw.plotItem.vb, 
            #         scene=self.pw.scene())
            self.drawnItems[chrom.sample] = c
            #self.pw.addItem(c)
            #self.pw.plotItem.curves.append(c)
            self.emit(SIGNAL('linePlotted'), chrom.sample.shortName())
        if self.flags != 'peaks':
            self.pw.autoRange()
#===========================================================================
# UI stuffs
#===========================================================================
 

    def _setupUi (self):    
      
#        self.stop = QToolButton()
#        self.stop.setIcon(QIcon('gui/icons/tools_wizard.png'))
#        self.stop.setToolTip('Enable or disable the appearance of the contextMenu')
        layout=QVBoxLayout(self)
        
        self.smoothButton=QToolButton()
        #self.smoothButton.setToolButtonStyle(2)
        self.smoothButton.setPopupMode(2)
        self.smoothButton.setToolTip("Smooth the visualized data")
        #self.smoothButton.setText("Smooth...")
        self.smoothButton.setIcon(QIcon(os.path.normcase('gui/icons/smooth.png')))
        self.smoothMenu = QMenu()
        self.connect(self.smoothMenu, SIGNAL('triggered(QAction*)'), self.smooth)
        self.smoothButton.setMenu(self.smoothMenu)
        self.pw.plotItem.toolBar.addWidget(self.smoothButton)

        self.flipButton=QToolButton()
        #self.flipButton.setToolButtonStyle(2)
        self.flipButton.setIcon(QIcon(os.path.normcase('gui/icons/flip.png')))
        self.flipButton.setToolTip("Flip the visualized data")
        #self.flipButton.setText("Flip...")
        self.flipButton.setPopupMode(2)
        self.flipMenu = QMenu()
        self.connect(self.flipMenu, SIGNAL('triggered(QAction*)'), self.flip)
        self.flipButton.setMenu(self.flipMenu)
        self.pw.plotItem.toolBar.addWidget(self.flipButton)
                
        self.annotButton=QToolButton()
        #self.annotButton.setToolButtonStyle(2)
        self.annotButton.setPopupMode(2)
        #self.annotButton.setText("&Annotate...")
        self.annotButton.setIcon(QIcon(os.path.normcase('gui/icons/attach.png')))
        self.annotMenu = QMenu()
        self.annotMenu.addAction("&Add Annotation")
        self.annotMenu.addAction("&Remove last Annotation")
        self.annotMenu.addAction("&Remove All Annotation")
        self.annotButton.setMenu(self.annotMenu)
        self.connect(self.annotMenu.actions()[0], SIGNAL("triggered()"), self.annotate)
        self.connect(self.annotMenu.actions()[1], SIGNAL("triggered()"), self.removeLastAnnot)
        self.connect(self.annotMenu.actions()[2], SIGNAL("triggered()"), self.removeAllAnnot)
        self.pw.plotItem.toolBar.addWidget(self.annotButton)
        
        self.addPlotButton=QToolButton()
        #self.addPlotButton.setToolButtonStyle(2)
        self.addPlotButton.setText("Add...")
        self.addPlotButton.setIcon(QIcon(os.path.normcase('gui/icons/list_add.png')))
        self.addPlotButton.setToolTip("Add a new plot to the current figure")
        #self.addPlotButton.setText('&Add Plot')
        self.pw.plotItem.toolBar.addWidget(self.addPlotButton)
        
        self.showSpectra=QToolButton()
        self.showSpectra.setPopupMode(2)  #instant popup
        #self.showSpectra.setToolButtonStyle(2)   
        self.showSpectra.setIcon(QIcon(os.path.normcase('gui/icons/file_export.png')))   
        #self.showSpectra.setText('&Show /hide...')
        self.showSpectra.setToolTip('Show/hide ...')
        self.showMenu=QMenu()
        self.showTextLabels=QAction("&Show Labels", self.showMenu)
        self.showTextLabels.setCheckable(True)
        self.showTextLabels.setChecked(True)
        self.showMenu.addAction(self.showTextLabels)
        self.connect(self.showMenu.actions()[0], SIGNAL('toggled(bool)'), self.setTextLabelsVisibility)
        showSpectrum=QAction("&Merged Spectrum", self.showMenu)
        showSpectrum.setCheckable(True)
        if self.flags == 'chroma' or self.flags == 'spectra':
            showSpectrum.setEnabled(False)
        self.showMenu.addAction(showSpectrum)
        self.connect(self.showMenu.actions()[1], SIGNAL('toggled(bool)'), self.drawSpectraRequested)
        
        showNonXCMSPeak=QAction("&Show Non XCMS Peak", self.showMenu)
        showNonXCMSPeak.setCheckable(True)
        if self.flags == 'spectra':
            showNonXCMSPeak.setEnabled(False)
        self.showMenu.addAction(showNonXCMSPeak)
        self.connect(self.showMenu.actions()[2], 
                     SIGNAL('toggled(bool)'), 
                     self.setPixmapVisibility)
        
        showDataPoints = QAction("&Show DataPoints", self.showMenu)
        showDataPoints.setCheckable(True)
        showDataPoints.setChecked(False)
        self.showMenu.addAction(showDataPoints)
        self.connect(self.showMenu.actions()[3], 
                     SIGNAL('toggled(bool)'), 
                     self.setDataPointsVisibility)
        self.showSpectra.setMenu(self.showMenu)
        self.pw.plotItem.toolBar.addWidget(self.showSpectra)
        
        self.saveToPng = QToolButton()
        self.saveToPng.setIcon(QIcon(os.path.normcase('gui/icons/thumbnail.png')))
        #self.saveToPng.setToolButtonStyle(2)
        #self.saveToPng.setText("Save to Png...")
        self.pw.plotItem.toolBar.addWidget(self.saveToPng)
        self.connect(self.saveToPng, SIGNAL('clicked()'), self.pw.writeImage)
        #add bar plot even if we are plotting chroma
        #cause we can find non xcms peaks
        self.barPlot = BarPlot(scene=self.pw.sceneObj)
        #self.barPlot.rotate(-90.)
        if self.flags == 'peak':
            self.barPlot.setPeakGroup(self.data)
        #TODO modify to get this close to us
        #on the left part
        xpos = self.barPlot.scene().width()*3.5#-bwidth;
        ypos = self.barPlot.scene().height()*1.1
        self.barPlot.setPos(xpos,ypos)
        self.barPlot.setZValue(1000)

        layout.addWidget(self.pw)
        layout.addWidget(self.pw.plotItem.toolBar)

    
    
    def showTextLabel(self, x, y, secure=25):
        """
        add labels of principle peaks of spectrum or chroma
        on the plot, return the labels, that we can show hide
        
        """
        maxis=[]#will contain tuple(rt, intens)
        indexes=[]
        #from core.MetObjects import MSAbstractTypes
        from scipy.ndimage import gaussian_filter1d as gauss        
        z=gauss(y, 1)
        #z = MSAbstractTypes.computeBaseLine(z, 92., 0.8)
        i=0
        while i <len(z)-1:
            while z[i+1] >= z[i] and i < len(y)-2:
                i+=1
            maxis.append((x[i], y[i])) 
            indexes.append(i)
            while z[i+1] <= z[i] and i<len(z)-2:
                i+=1
            i+=1
        labels=[]    
        for t in sorted(maxis, key=lambda x:x[1])[-5:]:
            g=QGraphicsTextItem(str(t[0]))
            g.setFlag(QGraphicsItem.ItemIgnoresTransformations)
            font=QApplication.font()
            font.setPointSizeF(6.5)
            g.setFont(font)
            g.setDefaultTextColor(Qt.black)
            g.setPos(t[0], t[1])
            labels.append(g)
            self.pw.addItem(g)
        return labels
            

#===============================================================================
#SLOTS 
#===============================================================================
    def redrawAll(self, value):
        self.pw.clear()
        self._plotting(self.data)

    def disHighlightOne(self, idx):
        if not idx.isValid():
            return
        sample = self.model.sample(idx.data().toString(), fullNameEntry=False)
        if sample is None:
            return
        try:
            self.drawnItems[sample].setHighlighted(False)
        except KeyError:
            pass
        
    def highlight(self, idx):
        if not idx.isValid():
            return
        sample = self.model.sample(idx.data().toString(), fullNameEntry=False)
        if sample is None:
            return
        try:
            self.drawnItems[sample].setHighlighted(True)
        except KeyError:
            pass
            #print "sample not found"
        self.pw.plotItem.update()#works
    
    def disHighlight(self):
        for key in self.drawnItems.iterkeys():
            self.drawnItems[key].setHighlighted(False)
        self.pw.plotItem.update()
    

    def setTextLabelsVisibility(self, bool_):
        for t in self.textLabels:
            t.setVisible(bool_)
    
    
    def setDataPointsVisibility(self, b):
        if self.dataPoints is None:
            if self.flags == 'peak':
                chrom = self.ref.sample.massExtraction(self.ref.mass(), self.ref.sample.ppm, asChromatogram=True)
                self.dataPoints = ScatterPlotItem(x=chrom.x_data, y=chrom.y_data)
            else:
                self.dataPoints = ScatterPlotItem(x=self.ref.x_data, y=self.ref.y_data)
            if self.flags != 'spectra':
                self.dataPoints.sigClicked.connect(self.requestSpectra)
            self.pw.addDataItem(self.dataPoints)
        self.dataPoints.setVisible(b)
    
    
    def setPixmapVisibility(self, bool_):
        """
        draw other peaks than the xcms peak
        
        """
        if not self.pixmaps and bool_:
            ppm = 1. if self.ref.sample.kind=='MRM' else self.ref.sample.ppm
            chrom = self.ref.sample.massExtraction(self.ref.mass(), ppm, asChromatogram=True) \
            if self.flags == 'peak' else self.ref
            chrom.findNonXCMSPeaks()
            for p in chrom.peaks.ipeaks():
                if self.flags == 'peak':
                    diff=(p.height*10)/100
                    if abs(p.height-self.ref.height) < diff:
                        continue #we assume that they are the same peaks
                pix=PeakIndicator(p, icon='flags')
                #self.connect(pix, SIGNAL("highlightRequested"), c.setHighlighted)
                self.connect(pix, SIGNAL('updateBarPlot'), self.barPlot.setPeakGroup)
                pix.setPos(p.rt, p.height + (p.height * 10) / 100.)
                pix.setZValue(1000)
                self.pixmaps.append(pix)
                self.pw.addItem(pix)                
        if self.pixmaps:
            for t in self.pixmaps:
                t.setVisible(bool_)
    
    @pyqtSlot()
    def updateCurrentPeak(self):
        idx=self.acTree.selectedIndexes()[0]
        s=self.model.sample(idx.parent().data().toString(), fullNameEntry=False)
        if s is not None:
            self.currentPeak=s.peakAt(*map(float, idx.data().toString().split('/')))
    
    
    def requestSpectra(self, scatter, l):
        """
        idea plot all spectra between a time range
        and not only with only one spectra
        
        """
        if not l:
            return
        ref = l[0]
        self.emit(SIGNAL("drawSpectrumByTime"), ref.pos(), self.ref.sample)
        
        
    
    
    @pyqtSlot()
    def drawSpectraRequested(self, bool_):
        """
        i think this is for plotting merged spectrum
        
        """
        if bool_:
            self.emit(SIGNAL('drawSpectraRequested'), self.currentPeak)
        else:
            self.hideRequested()
    
    def drawSpectra(self, l):
        self.emit(SIGNAL('drawSpectra(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), l[0], l[1], self.ref.sample)        
    
    @pyqtSlot()
    def hideRequested(self):
        self.emit(SIGNAL('hideRequested'))
        self.showMenu.actions()[1].setChecked(False)
        
  

    @pyqtSlot()
    def redraw(self):
        """
        this is for updating the view port
        when hiding or not samples
        
        """
        chromas =[]
        for spl in self.model:
            if spl.checked:
                if spl in self.drawnItems.keys():
                    self.drawnItems[spl].setVisible(True)
                else:
                    chromas.append(spl.chroma[0])
            else:
                self.drawnItems[spl].setVisible(False)
        self._plotting(chromas)
        self.pw.plotItem.update()#works
   
   
    
    def cleanScene(self):
        """
        remove all items in the trash
        
        """
        for element in self.trashItems:
            self.pw.sceneObj.removeItem(element)
            

    @pyqtSlot()
    def updateContextMenu(self, line): 
        self.flipMenu.addAction(line)
        self.smoothMenu.addAction(line)
    


#===============================================================================
# CONTEXT MENU SLOTS
#===============================================================================
    @pyqtSlot(str)
    def flip(self, action):
        spl=self.model.sample(self.fullXmlPath(action.text()))
        if spl is None:
            print "can not flip, can not recognize the selected sample"
            return
        try:
            self.drawnItems[spl].updateData(-self.drawnItems[spl].getData()[1], 
                                            self.drawnItems[spl].getData()[0])
        except KeyError:
            pass
        if len(self.data) == 1:
            #we are flipping the text labels only
            #if only one dataset is flipped
            for item in self.textLabels:
                item.setPos(item.pos().x(), -item.pos().y())
    
    @pyqtSlot(str)
    def smooth(self, action):
        """
        TODO:
        would be good to reuse the widget in the menuControl
        
        """
        from core.MetObjects import MSAbstractTypes
        class Dial(QDialog):
            choices =['flat', 'hanning', 'hamming', 'bartlett', 'blackman']
            def __init__(self, parent):
                QDialog.__init__(self, parent)
                f =QFormLayout(self)
                self.a =QSpinBox(self)
                self.a.setValue(30)
                self.b = QComboBox(self)
                self.b.addItems(self.choices)
                self.c= QDialogButtonBox(self)
                self.c.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok)
                f.addRow("window:" ,self.a)
                f.addRow("method:", self.b)
                f.addRow("", self.c)
                self.connect(self.c, SIGNAL("accepted()"), self.sendData)
                self.connect(self.c, SIGNAL("rejected()"), self.reinitialize)
            
            def sendData(self):
                self.parent().window = self.a.value()
                self.parent().method = self.b.currentText()
                self.close()
            
            def reinitialize(self):
                self.parent().window = None
                self.parent().method = None
                self.close()
                
        Dial(self).exec_()
        if self.window and self.method:
            for spl in self.drawnItems.keys():
                if action.text() == spl.shortName():
                    self.drawnItems[spl].updateData(
                    MSAbstractTypes.averageSmoothing(self.drawnItems[spl].getData()[1],self.window , self.method),
                    self.drawnItems[spl].getData()[0])
           

    @pyqtSlot()
    def plotEIC(self):
        if self.flags == 'spectra':
            
            #show double combobox
            #select the good spectra then draw
            pass
        else:
            mass, ok = QInputDialog.getText(self.view, "EIC query", "mass:")
            if not (mass and ok):
                return
            xmlfile = self.fullXmlPath(self.selection[0].data().toString())
            if not xmlfile:
                xmlfile = self.fullXmlPath(self.selection[0].parent().data().toString())
            if not xmlfile:
                print "item clicked not recognized..."
                return
            sample = self.model.sample(xmlfile)
            if sample.kind =='HighRes':
                error=(sample.ppm/1e6)*float(mass)
                x, y = massExtraction(sample, float(mass), error)
                from core.MetObjects import MSChromatogram
                chrom = MSChromatogram(x_data=x, y_data=y, sample=sample)
            else:
                chrom = sample.getChromWithTrans(math.ceil(float(mass)))
        self.view.addMdiSubWindow(MSQtCanvas([chrom], "EIC %s"%str(mass), 
                                             labels={'bottom':'RT(s)', 'left':'INTENSITY'}))
        
    
    #===========================================================================
    # annotate stuff
    #===========================================================================
    @pyqtSlot()
    def annotate(self):
        text, bool_ = QInputDialog.getText(self.view, "Annotation dialog", "Annotation:")
        g=QGraphicsTextItem(str(text))
        g.setFlag(QGraphicsItem.ItemIgnoresTransformations)
        g.setFlag(QGraphicsItem.ItemIsMovable)
        g.setTextInteractionFlags(Qt.TextEditorInteraction)
        font=qApp.instance().font()
        font.setPointSizeF(10.)
        g.setFont(font)
        g.setDefaultTextColor(Qt.blue)
        g.setPos(500,1e4)
        self.trashItems.append(g)
        self.pw.addItem(g)
    
    def removeAllAnnot(self):
        if not self.trashItems:
            self.view.showErrorMessage("Error", "No annotation detected")
            return
        for i in self.trashItems:
            self.pw.removeItem(i)
    
    def removeLastAnnot(self):
        if not self.trashItems:
            self.view.showErrorMessage("Error", "No annotation detected")
        self.pw.removeItem(self.trashItems[-1])
Example #24
0
class MSMainWindow(QMainWindow):
    """Gui of the main window"""
    
    #MAX_RECENT_FILES = 10
    #start putting links spyder numpy scipy et tutti quanti
    links=('http://numpy.scipy.org/',
           'http://packages.python.org/spyder/',
           'http://www.riverbankcomputing.co.uk/software/pyqt/intro')
    
    pluginPath=path.normcase('pluginmanager/plugins/')    
    
    def __init__(self, availablePlugins):
        """
        Constructor with all the models needed setup menus
        
        """
        QMainWindow.__init__(self)
        self.setDockOptions(QMainWindow.VerticalTabs | QMainWindow.AnimatedDocks)
        self.plugins = availablePlugins
        self.pluginsInst=[]   
        settings=QSettings('INRA/INSA', '-'.join([QApplication.instance().APPLICATION_NAME_STR, 
                                                  QApplication.instance().VERSION_STR]))  
        self.recentFiles = list(settings.value("RecentFiles").toStringList())
        self.setStyleSheet(stylesheet)
        self.pipeline = MSPipelineToolBar("Pipeline toolbar", parent=self)
        self.addToolBar(0x1,self.pipeline)
        
        self._setupModels()
        self._setupUi()        
        self._setupMenus()

    def _setupModels(self):
        """
        Warning:Causes segfault when horizontal labels set to True
        
        on aura peu etre a la fin un model par sampleList c'est ce qui parait
        le plus logique
        
        """        
        #drag and drop table sample
        self.sampleModel = QStandardItemModel(self)      
        self.sampleModel.setHorizontalHeaderLabels(["Sample", "Class"])
        #treeView1
        self.spectraModel = QStandardItemModel(self)
        #treeview2
        self.peakModel = QStandardItemModel(self)
        #treeview3
        self.clusterModel = QStandardItemModel(self)
 
    def _setupMenus(self):
        #file
        self.fileMenu = QMenu('&File')
        self.fileMenu.setTearOffEnabled(True)
        self.op=QMenu("&Open...",self.fileMenu)
        self.op.setIcon(QIcon(path.normcase("gui/icons/fileopen.png")))
        
        open_=QAction("&Open rawfiles", self)
        open_.setToolTip("Open an mzXML or netCDF file")
        open_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_O))
        open_icon=QIcon(path.normcase("gui/icons/fileopen.png"))
        open_.setIcon(open_icon)
        self.op.addAction(open_)
        
        load_=QAction("&Open projects...", self)
        load_.setToolTip("load binary file containing saved objects")
        load_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S))
        load_icon=QIcon(QPixmap(path.normcase("gui/icons/project_open.png")))
        load_.setIcon(load_icon)
        self.op.addAction(load_)
        
        self.fileMenu.addMenu(self.op)
        
        save_=QAction("&Save...", self)
        save_.setToolTip("save the actual application model")
        save_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S))
        save_icon=QIcon(path.normcase("gui/icons/save_all.png"))
        save_.setIcon(save_icon)
        self.fileMenu.addAction(save_)
        
        pkl = QAction("&load a peaklist", self) #TODO:load peaklist
        pkl.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_P))
        pkl.setToolTip("load a peaklist and process it")
        pkl.setIcon(QIcon(path.normcase("gui/icons/featuredetect.png")))
        self.fileMenu.addAction(pkl)
        
        convert_=QAction("&Convert...", self)
        convert_.setEnabled(False)
        convert_.setToolTip("Convert a .wiff file if Analyst(c) is installed")        
        convert_icon=QIcon(path.normcase("gui/icons/goto.png"))
        convert_.setIcon(convert_icon)
        self.fileMenu.addAction(convert_)
        
        a = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Launch a batch")
        a.setEnabled(False)
        
        b = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Merge")
        b.setToolTip("Merge MRM file")
        #b.setEnabled(False)
        
        self.fileMenu.addSeparator()
#        
#        for i in xrange(self.MAX_RECENT_FILES):
#            a = QAction('', self)
#            a.setVisible(False)
#            self.fileMenu.addAction(a)
#        
#        for i in xrange(min(self.MAX_RECENT_FILES, len(self.recentFiles))):
#            self.fileMenu.actions()[5+i].setVisible(True)
#            self.fileMenu.actions()[5+i].setText(self.recentFiles[i].split('/')[-1])
            
        
        exit_action =QAction("&Exit", self)
        exit_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Q))
        exit_action.setIcon(QIcon(QPixmap(path.normcase('gui/icons/exit.png'))))
        self.fileMenu.addAction(exit_action)
        
        self.menuBar().addMenu(self.fileMenu)
        
        self.editMenu=QMenu("&Edit")
        self.editMenu.setTearOffEnabled(True)
        self.editMenu.addAction(QIcon(path.normcase('gui/icons/edit_undo.png')), '&Undo...')
        self.editMenu.addAction(QIcon(path.normcase('gui/icons/edit_redo.png')), '&Redo...')
        self.editMenu.actions()[0].setEnabled(False)
        self.editMenu.actions()[1].setEnabled(False)
        self.editMenu.addSeparator()
        self.editMenu.addAction(QIcon(path.normcase('gui/icons/run.png')), '&Preferences')
        self.exportMenu = QMenu("&Export...")
        self.exportMenu.setIcon(QIcon(path.normcase('gui/icons/file_export.png')))
        self.exportMenu.addAction("&Peaklist")        
        self.exportMenu.addAction("&Clusters intensity matrix")
        self.editMenu.addMenu(self.exportMenu)        
        self.menuBar().addMenu(self.editMenu)
        
        
        #view
        self.viewMenu =QMenu("&View")
        self.viewMenu.setTearOffEnabled(True)
        self.viewMenu.addAction(QIcon(path.normcase('gui/icons/window_duplicate')),
                                "&Cascade View", 
                                self.mdiArea.cascadeSubWindows, 
                                QKeySequence(Qt.CTRL + Qt.Key_K))
        self.viewMenu.addAction(QIcon(path.normcase('gui/icons/view_icon')),
                                "&Title View", 
                                self.mdiArea.tileSubWindows, 
                                QKeySequence(Qt.CTRL + Qt.Key_N))
        self.viewMenu.addAction(QIcon(path.normcase("gui/icons/stop_process.png")),
                                "&Close all subWindows",
                                self.mdiArea.closeAllSubWindows,
                                QKeySequence(Qt.CTRL+Qt.Key_W))
        
        self.plotting =QMenu("&Plotting...")
        self.plotting.setIcon(QIcon(QPixmap(path.normcase("gui/icons/plot.png"))))
        self.plotting.addAction("&3D Plot")
        #self.plotting.addAction("&Cytoscape web")
        self.plotting.addAction("&Spectrogram Plot")
        
        #self.multiplePlot = QAction("&Visualize Raw/Treated Data", self)
        #self.multiplePlot.setCheckable(True)
        #self.multiplePlot.setEnabled(False)
        #self.sub_plot_.addAction(self.multiplePlot)
       
        self.viewMenu.addMenu(self.plotting)
        self.viewMenu.addSeparator()
        self.show_hide=QMenu("&Show/Hide")
        m=self.createPopupMenu()
        m.setTitle("&Show/Hide")
        self.viewMenu.addMenu(m)
        #self.pref = QMenu("&Preferences")
       
        #self.pref.addAction(self.multiplePlot)
        #self.viewMenu.addMenu(self.pref)
        self.menuBar().addMenu(self.viewMenu)

        #algorithm
        self.algoMenu= QMenu("&Algorithm")
        self.algoMenu.setTearOffEnabled(True)
        self.preProcessing=QMenu("&PreProcessing(experimental)")
        self.preProcessing.addAction("&Smoothing raw data...")
        self.preProcessing.addAction("&Cut off raw data...")
        self.preProcessing.addAction('&Calibration (mz dimension)')
        self.preProcessing.addAction("&Resize sample...")
        
        self.algoMenu.addMenu(self.preProcessing)
        
        self.peakPickingMenu = QMenu("&Peack Picking & Alignement(XCMS)", self)
        self.peakPickingMenu.setIcon(QIcon(path.normcase("gui/icons/pickedpeakicon.png")))
        
        matched = QAction("&MatchedFiltered", self)
        matched.setIcon(QIcon(path.normcase('gui/icons/RLogo')))
        matched.setToolTip("Peak Detection and Integration using MatchedFiltered algorithm")
        self.peakPickingMenu.addAction(matched)        
        
        centwave=QAction("&CentWave", self)
        centwave.setIcon(QIcon(path.normcase('gui/icons/RLogo')))
        centwave.setToolTip("Peak Detection and Integration using CentWave algorithm")
        self.peakPickingMenu.addAction(centwave)
        #peak_.setShortcut(.QKeySequence(CTRL + Key_P))
       # peak_icon=.QIcon(.QPixmap(path.normcase("gui/icons/pickedpeakicon.png")))
        #peak_.setIcon(peak_icon)
        self.algoMenu.addMenu(self.peakPickingMenu)
        
        self.alignment = QMenu("&Alignment")
        self.alignment.setIcon(QIcon(path.normcase('gui/icons/format_indent_more.png')))
        self.alignment.addAction("&Polynomial fitting(exp)")
        self.alignment.addAction("&DynamicTimeWarping")
        self.alignment.addAction("&ObiWarp")
        self.alignment.actions()[2].setEnabled(False)
        self.algoMenu.addMenu(self.alignment)
        
        self.algoMenu.addAction("Normalization")
        
        clust_ =  QAction("&Clustering", self)
        clust_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_L))
        clust_icon=QIcon(QPixmap(path.normcase("gui/icons/cluster.png")))
        clust_.setIcon(clust_icon)
        self.algoMenu.addAction(clust_)
        
        id_ =  QAction("&Identification", self)
        id_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_I))
        id_.setToolTip("Try to identify peaks with several methods")
        id_.setIcon(QIcon(QPixmap(path.normcase("gui/icons/findcompound.png"))))
        self.algoMenu.addAction(id_)
        self.menuBar().addMenu(self.algoMenu)        
        
     
        
        #tools
        self.toolsMenu =QMenu("&Tools")
        self.toolsMenu.setTearOffEnabled(True)
        web =  QAction("&Web Browser", self)
        web.setIcon(QIcon(QPixmap(path.normcase("gui/icons/applications_internet.png"))))
        self.toolsMenu.addAction(web)
        #cyto = QAction("&cytoscape", self)
        #cyto_icon =QIcon(QPixmap(path.normcase("gui/icons/cytoscape.jpeg")))
        #cyto.setIcon(cyto_icon)
        #self.toolsMenu.addAction(cyto)
        editor = QAction("&Editor", self)
        editor.setIcon(QIcon(QPixmap(path.normcase("gui/icons/document_sign.png"))))
        self.toolsMenu.addAction(editor)
        pet=QAction("&Short Periodic Table", self)  
        pet.setIcon(QIcon(QPixmap(path.normcase("gui/icons/pet.jpg"))))
        self.toolsMenu.addAction(pet)
        self.menuBar().addMenu(self.toolsMenu)
        
        #plugins
        self.pluginMenu = QMenu('&Plugins')
        self.pluginMenu.setTearOffEnabled(True)
        instPl=  QAction("&Install a plugin", self)
        instPl.setIcon(QIcon(path.normcase('gui/icons/pluginInstall.png')))
        self.pluginMenu.addAction(instPl)
        self.launchingMenu = QMenu("&Launch PLugins", self)
        self.launchingMenu.setIcon(QIcon(path.normcase('gui/icons/plugin')))
        
        for plug in self.plugins:
            #fullname="".join([self.pluginPath, str(plug)])
            mod=imp.load_source(self.__module__, plug)
            if mod.autoActivation:
                qApp=QApplication.instance()
                name=getattr(mod, 'className')
                cls=getattr(mod, name)
                p=cls(qApp.model, self, parent=self)                
                #p=qApp.pluginManager.loadPlugin(qApp.model, self, plug.split('/')[-1])
                self.pluginsInst.append(p)
            else:
                self.launchingMenu.addAction(plug.split('/')[-1])
        self.pluginMenu.addMenu(self.launchingMenu)
        self.pluginMenu.addAction(QIcon(path.normcase("gui/icons/process_stop.png")),
                                        "&Remove loaded Plugin")
        self.menuBar().addMenu(self.pluginMenu)
        
        #about
        self.aboutMenu= QMenu("&About")
        self.aboutMenu.setTearOffEnabled(True)
        metms = QAction(QIcon(path.normcase('gui/icons/deluge.png')), "&about metMS...", self)
        self.aboutMenu.addAction(metms)
        
        pyqt =  QAction("&about PyQt4...", self)
        pyqt_icon =QIcon(QPixmap(path.normcase("gui/icons/logo_QT4.png")))
        pyqt.setIcon(pyqt_icon)
        self.aboutMenu.addAction(pyqt)
        metms =  QAction("&metMS Documentation", self)
        metms_icon =QIcon(QPixmap(path.normcase("gui/icons/deluge.png")))
        metms.setIcon(metms_icon)
        self.aboutMenu.addAction(metms)
        self.menuBar().addMenu(self.aboutMenu)
        

    def _setupUi(self, background=None):
        """        
        Make the GUI
        
        """
        #mdi
        self.mdiArea = MSMdiArea(self)
        self.mdiArea.setBackground(QBrush(QPixmap(path.normcase('gui/icons/blac2.png'))))#QColor(Qt.blue).darker()))
        self.setCentralWidget(self.mdiArea)
        
        
        #sample dock widget
        self.sampleDockWidget = QDockWidget("Samples", self)
        #sampleWidget = QWidget()
        self.sampleTableView = MSDragFromTableView()
        self.sampleTableView.setModel(self.sampleModel)
        self.sampleTableView.setSelectionBehavior(1)
        self.sampleTableView.verticalHeader().hide()
        self.sampleTableView.verticalHeader().setDefaultSectionSize(15)        
        self.sampleTableView.horizontalHeader().setDefaultSectionSize(150)
        

        self.sampleDockWidget.setWidget(self.sampleTableView)#sampleWidget)
        self.sampleDockWidget.visible=True
        
        
        #workflow dock
        self.workflowDockWidget = QDockWidget("Visualizer", self)
        self.workflowDockWidget.visible = True

        a=QWidget(self)
        v=QVBoxLayout(a)
        q=QToolBar()
        #self.workingSample = QLabel("Working Sample:None")
        #q.addWidget(self.workingSample)
        q.addWidget(QLabel("ppm :"))
        self.ppmEditer=QDoubleSpinBox()
        self.usePpm=QCheckBox("use ?")  
        q.addWidget(self.ppmEditer)
        q.addWidget(self.usePpm)
        
        q.addSeparator()
        
        self.removeButton=QToolButton(self)
        self.removeButton.setIcon(QIcon(path.normcase("gui/icons/delete.png")))           
        q.addWidget(self.removeButton)
        
        self.markAsGood=QAction(QIcon(path.normcase("gui/icons/button_ok.png")),"mark peak as good", self)
        self.markAsBad=QAction(QIcon(path.normcase("gui/icons/stop.png")), "mark peak as bad", self)
        self.hideItem = QAction(QIcon(path.normcase("gui/icons/list_remove.png")), "Hide Item", self)
        
        q.addAction(self.markAsGood)
        q.addAction(self.markAsBad)
        q.addAction(self.hideItem)
        v.addWidget(q)        
        
        
        self.tabWidget = QTabWidget()
        self.tab = QWidget()
        verticalLayout = QVBoxLayout(self.tab)
        self.treeView = MSToDropTableView()
        self.treeView.verticalHeader().setDefaultSectionSize(20)
        
        self.treeView.setModel(self.spectraModel)
        self.spectraLabel = QLabel("Sample: None")
        verticalLayout.addWidget(self.treeView)
        verticalLayout.addWidget(self.spectraLabel)
        self.tabWidget.addTab(self.tab, QIcon(path.normcase("gui/icons/spectrumicon.png")),"Spectra")
        
        self.tab_2 = QWidget()
        verticalLayout_4 = QVBoxLayout(self.tab_2)
        self.treeView_2 = MSToDropTableView()#MSTreeView(self.tab_2)# QTableView(self)#
        self.treeView_2.verticalHeader().setDefaultSectionSize(20)
        self.treeView_2.setModel(self.peakModel)
        self.peakLabel = QLabel("Sample: None")
        verticalLayout_4.addWidget(self.treeView_2)
        verticalLayout_4.addWidget(self.peakLabel)
        self.tabWidget.addTab(self.tab_2,QIcon(path.normcase("gui/icons/peakicon.png")), "Peaks List")
        
        self.tab_3 = QWidget()
        verticalLayout_5 = QVBoxLayout(self.tab_3)
        self.treeView_3 = MSToDropTreeView()
        self.treeView_3.setAnimated(True)
        self.treeView_3.setModel(self.clusterModel)
        self.clusterLabel = QLabel("Sample: None")
        verticalLayout_5.addWidget(self.treeView_3)
        verticalLayout_5.addWidget(self.clusterLabel)
        self.tabWidget.addTab(self.tab_3, QIcon(path.normcase("gui/icons/clustering.png")), "Clusters")
        
        self.tabWidget.setCurrentIndex(0)
        
        for l in (self.spectraLabel, self.peakLabel, self.clusterLabel):
            l.setAutoFillBackground(True)
            
        v.addWidget(self.tabWidget)
        self.workflowDockWidget.setWidget(a)
        self.addDockWidget(Qt.DockWidgetArea(0x2),self.workflowDockWidget)        
        
                
        from gui.MetBaseGui import MSIsoCalculator
        self.isoCalc = MSIsoCalculator(self)
        self.isoCalcDockWidget=QDockWidget('isotopes calculation', self)
        self.isoCalcDockWidget.setWidget(self.isoCalc)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.isoCalcDockWidget)
        self.isoCalcDockWidget.setVisible(False)
        self.isoCalcDockWidget.visible=False
        
        from gui.MetBaseGui import FormulaGenerator
        self.generator=FormulaGenerator(self)
        self.generatorDockWidget=QDockWidget('formula generator', self)
        self.generatorDockWidget.setWidget(self.generator)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.generatorDockWidget)
        self.generatorDockWidget.setVisible(False)
        self.generatorDockWidget.visible=False
        
        self.compoundTreeView = MSCompoundTreeView(self)
        self.compoundDockWidget = QDockWidget("Compounds", self)
        self.compoundDockWidget.setWidget(self.compoundTreeView)
        self.addDockWidget(Qt.DockWidgetArea(0x2),self.compoundDockWidget)
        self.compoundDockWidget.setVisible(False)
        self.compoundDockWidget.visible=False
        
        self.comparativeTableView = QTableView(self)
        self.comparativeTableView.horizontalHeader().setStretchLastSection(True)
        self.comparativeTableView.verticalHeader().setDefaultSectionSize(20)
        self.comparativeDock = QDockWidget("Comparative View", self)
        self.comparativeDock.setWidget(self.comparativeTableView)
        self.addDockWidget(Qt.DockWidgetArea(0x8), self.comparativeDock)
        self.comparativeDock.setVisible(False)
        self.comparativeDock.visible = False
        
        self.tabifyDockWidget(self.compoundDockWidget, self.isoCalcDockWidget)
        self.tabifyDockWidget(self.isoCalcDockWidget, self.workflowDockWidget )
        self.tabifyDockWidget(self.workflowDockWidget, self.generatorDockWidget)
        #set the end
        
        #WARNING: possible that the internal shell widget cause random segfault
        #with the error of QObject::killTimers...? not sure !
        self.shell = QWidget()#InternalShell(namespace={'metms': QApplication.instance()}, 
                     #              parent=self, 
                     #              multithreaded=False)
        self.shellDock = QDockWidget("Python Shell", self)
        self.shellDock.setWindowIcon(QIcon(path.normcase('gui/icons/stop.png')))
        self.shellDock.setWidget(self.shell)
        self.shellDock.setMinimumWidth(255)
        self.shellDock.visible=True
        self.addDockWidget(0x2, self.shellDock)

        self.addDockWidget(0x2, self.sampleDockWidget)
        self.tabifyDockWidget(self.shellDock, self.sampleDockWidget)
        
        self.pb = QProgressBar(self)
        self.pb.setMaximumWidth(245)
        
        self.stopProcess = QToolButton(self)
        self.stopProcess.setIcon(QIcon(path.normcase("gui/icons/process_stop.png")))        
        m = QMenu()
        #self.connect(m, SIGNAL('triggered(QAction*'), QApplication.instance().taskManager.abortByName)
        self.stopProcess.setMenu(m)
        self.stopProcess.setPopupMode(1) #Menu Button
        #self.connect(self.stopProcess, SIGNAL("clicked()"), self.stopThread)
        
        self.statusBar().addPermanentWidget(self.stopProcess)
        self.statusBar().addPermanentWidget(self.pb)
    
    def updateStopProcessMenu(self):
        """
        update the menu of the stop process
        button, based directly on the processes
        stored by the task manager
        
        """
        self.stopProcess.menu().clear()
        for c in QApplication.instance().taskManager:
            self.stopProcess.menu().addAction(c.title)
        
        #QApplication.instance().taskManager.abort(QApplication.instance().taskManager[-1])
        
    def addMdiSubWindow(self, plot, title="", showMaximized=False):
        """ 
        Allow addition of new window in the mdiarea
        
        """        
        win=self.mdiArea.addSubWindow(plot)
        #print "widget parent", plot.parent()
        win.setAttribute(Qt.WA_DeleteOnClose)
        #win.connect(win, SIGNAL('destroyed(QObject *)'), self.testdestroy)
        #plot.setParent(win)
        win.setWindowTitle(title)
        if showMaximized:
            win.showMaximized()
        else:
            win.resize(400, 300)
        win.show()
        return win
   

           
    def updateTreeView(self):
        """
        Tree View update switch spectre/chromato
        
        """
        if self.treeView.model() == self.spectraModel:
            self.treeView.setModel(self.chromaModel)
            self.tabWidget.setTabText(0, "Chroma")
        else:
            self.treeView.setModel(self.spectraModel)
            #self.treeView.setSelectionMode(1)
            self.tabWidget.setTabText(0, "Spectra")
    
    def addTreeViewModel (self,model1, model2):
        """Add a model """
        self.chromaModel.appendRow(model1)
        self.spectraModel.appendRow(model2)
    
    
    def _actionHovered(self, action):
        """emulate tooltip cause they do not work that much"""
        tip = action.toolTip()
        QToolTip.showText(QCursor.pos(), tip)
    

    def showErrorMessage(self, title, string):
        QMessageBox.critical(self, title, string, 0, 0)
    
    
    def showWarningMessage(self, title, string):
        return QMessageBox.warning(self, title, string, QMessageBox.Ok|QMessageBox.Cancel)
    
    
    def showInformationMessage(self, title, string):
        QMessageBox.information(self, title, string, 0)
        
    
    def updateProgressBar(self, i):
        """update the value of the progress bar for all the treatment"""
        
        self.pb.setValue(min(i, 100))

    def to_indetermined_mode(self):
        self.pb.setMaximum(0)
        
    
    def to_determined_mode(self):
        self.pb.setMaximum(100)
        
    
    def showInStatusBar(self, string, time=5000):
        self.statusBar().showMessage(string, time)
    
    
    
    def addInterpreterDock(self, shell):
        self.shellDock = QDockWidget(self)
        self.shellDock.setWidget(shell)
        self.shellDock.setWindowTitle("shell")
        self.addDockWidget(0x2, self.shellDock)
        
    
    
    def showMetMSInformation(self):
        
        QMessageBox.about(self,
            self.tr("About %1").arg("metMS"),
            self.tr("""<b>%1 %2</b>
            <br>metabolite Mass Spectrometry
            <p>Copyright &copy; 2010 Marco INSA, INRA
            <br>Licensed under the terms of the CeciLL License
            <p>Developed and maintained by Marco
            <br>Bug reports and feature requests: 
            <a href="http://github.com/jerkos/metms">metMS site</a><br>
            Discussions around the project: 
            <a href="http://groups.google.com/group/spyderlib">Google Group</a>
            <p>This project is part of the BRIDGE project
            <p>Python %3, Qt %4, PyQt %5""") \
            .arg("metMS").arg(__version__) \
            .arg(platform.python_version()).arg(QT_VERSION_STR) \
            .arg(PYQT_VERSION_STR))
Example #25
0
    def registerAction(self, action, menuName, callback=None):
        """ register an action to the manager's main menu """
        if not hasattr(self, '_registeredDbActions'):
            self._registeredDbActions = {}

        if callback is not None:
            invoke_callback = lambda x: self.invokeCallback(callback)

        if menuName is None or menuName == "":
            self.addAction(action)

            if menuName not in self._registeredDbActions:
                self._registeredDbActions[menuName] = list()
            self._registeredDbActions[menuName].append(action)

            if callback is not None:
                QObject.connect(action, SIGNAL("triggered(bool)"),
                                invoke_callback)
            return True

        # search for the menu
        actionMenu = None
        helpMenuAction = None
        for a in self.menuBar.actions():
            if not a.menu() or a.menu().title() != menuName:
                continue
            if a.menu() != self.menuHelp:
                helpMenuAction = a

            actionMenu = a
            break

        # not found, add a new menu before the help menu
        if actionMenu is None:
            menu = QMenu(menuName, self)
            if helpMenuAction is not None:
                actionMenu = self.menuBar.insertMenu(helpMenuAction, menu)
            else:
                actionMenu = self.menuBar.addMenu(menu)

        menu = actionMenu.menu()
        menuActions = menu.actions()

        # get the placeholder's position to insert before it
        pos = 0
        for pos in range(len(menuActions)):
            if menuActions[pos].isSeparator() and menuActions[pos].objectName(
            ).endswith("_placeholder"):
                menuActions[pos].setVisible(True)
                break

        if pos < len(menuActions):
            before = menuActions[pos]
            menu.insertAction(before, action)
        else:
            menu.addAction(action)

        actionMenu.setVisible(True)  # show the menu

        if menuName not in self._registeredDbActions:
            self._registeredDbActions[menuName] = list()
        self._registeredDbActions[menuName].append(action)

        if callback is not None:
            QObject.connect(action, SIGNAL("triggered(bool)"), invoke_callback)

        return True
Example #26
0
class CFSceneContextMenuMixin:
    " Encapsulates the context menu handling "

    def __init__(self):
        self.menu = None
        self.individualMenus = {}

        # Scene menu preparation
        self.sceneMenu = QMenu()
        self.sceneMenu.addAction(getIcon('filesvg.png'), 'Save as SVG...',
                                 self.parent().onSaveAsSVG)
        self.sceneMenu.addAction(getIcon('filepdf.png'), 'Save as PDF...',
                                 self.parent().onSaveAsPDF)
        self.sceneMenu.addAction(getIcon('filepixmap.png'), 'Save as PNG...',
                                 self.parent().onSaveAsPNG)
        self.sceneMenu.addSeparator()
        self.sceneMenu.addAction(getIcon('copymenu.png'), 'Copy to clipboard',
                                 self.parent().copyToClipboard)

        # Common menu for all the individually selected items
        self.commonMenu = QMenu()
        #self.commonMenu.addAction(
        #    getIcon( "cutmenu.png" ), "Cut (Ctrl+X)", self.onCut )
        #self.commonMenu.addAction(
        #    getIcon( "copymenu.png" ), "Copy (Ctrl+C)", self.onCopy )
        #self.commonMenu.addSeparator()
        #self.commonMenu.addAction(
        #    getIcon( "trash.png" ), "Delete (Del)", self.onDelete )

        # Non-comment common menu for the individually selected items
        self.nonCommentCommonMenu = QMenu()
        #self.nonCommentCommonMenu.addAction(
        #    getIcon( "customcolors.png" ), "Custom colors...",
        #    self.onCustomColors )
        #self.nonCommentCommonMenu.addAction(
        #    getIcon( "replacetitle.png" ), "Replace text...",
        #    self.onReplaceText )

        # Individual items specific menu: begin
        ifContextMenu = QMenu()
        ifContextMenu.addAction(getIcon("switchbranches.png"),
                                "Switch branch layout", self.onSwitchIfBranch)

        self.individualMenus[IfCell] = ifContextMenu
        # Individual items specific menu: end

        # Menu for a group of selected items
        self.groupMenu = QMenu()
        #self.groupMenu.addAction(
        #    getIcon( "cfgroup.png" ), "Group...",
        #    self.onGroup )
        #self.groupMenu.addAction(
        #    getIcon( "customcolors.png" ), "Custom colors...",
        #    self.onCustomColors )
        #self.groupMenu.addSeparator()
        #self.groupMenu.addAction(
        #    getIcon( "trash.png" ), "Delete (Del)", self.onDelete )

        return

    def onContextMenu(self, event):
        " Triggered when a context menu should be shown "
        selectedItems = self.selectedItems()
        selectionCount = len(selectedItems)
        if selectionCount == 0:
            self.sceneMenu.popup(event.screenPos())
            return

        if selectionCount == 1:
            self.__buildIndividualMenu(selectedItems[0])
        else:
            self.__buildGroupMenu(selectedItems)
        self.menu.popup(event.screenPos())
        return

    def __buildIndividualMenu(self, item):
        " Builds a context menu for the given item "
        self.menu = QMenu()
        if type(item) in self.individualMenus:
            individualPart = self.individualMenus[type(item)]
            self.menu.addActions(individualPart.actions())
            self.menu.addSeparator()
        if not item.isComment():
            self.menu.addActions(self.nonCommentCommonMenu.actions())
            self.menu.addSeparator()
        self.menu.addActions(self.commonMenu.actions())

        # Note: if certain items need to be disabled then it should be done
        #       here

        return

    def __buildGroupMenu(self, items):
        " Builds a context menu for the group of items "
        self.menu = QMenu()
        self.menu.addActions(self.groupMenu.actions())

        # Note: if certain items need to be disabled then it should be done
        #       here

        return

    def onSwitchIfBranch(self):
        " If primitive should switch the branches "
        selectedItems = self.selectedItems()
        for item in selectedItems:
            if item.kind == CellElement.IF:
                item.switchBranches()
        return

    def onCustomColors(self):
        " Custom background and foreground colors "
        print "Custom colors"

    def onReplaceText(self):
        " Replace the code with a title "
        print "Replace title"

    def onDelete(self):
        " Delete the item "
        print "Delete"

    def onGroup(self):
        " Groups items into a single one "
        print "Group"

    def onCopy(self):
        print "Copy"

    def onCut(self):
        print "Cut"
Example #27
0
class MSQtCanvas(QWidget, MSDialogController):
    """
    DONE:the current peak is not updated while the user press up and down key on the treeView
    TODO: think about a mjor redesign of those classes
    
    """

    #linePlotted = pyqtSignal(object, str)
    #lineRemoved = pyqtSignal(object)

    def __init__(self, data, title, flags="chroma", parent=None, **k):
        QWidget.__init__(self, parent)
        MSDialogController.__init__(self, 0, parent)

        self.model = self.qApp.model
        self.view = self.qApp.view

        self.data = data
        self.title = title
        self.flags = flags

        if self.flags == 'peak':
            if self.acTree not in (self.view.treeView_2, self.view.treeView_3):
                print "Unknown Error"
                return
            idx = self.acTree.selectedIndexes()[0]
            s = qApp.instance().dockControl.currentSample[
                1 if self.acTree is self.view.treeView_2 else 2]
            if s is None:
                print "unknow error"
                return
            values = map(float, idx.data().toString().split('/')[:2])
            self.currentPeak = s.peakAt(*values)
            #connection to update the selected Peak object
            self.connect(self.acTree, SIGNAL("changedLine"),
                         self.updateCurrentPeak)

        self.minX, self.maxX, self.maxY = [0] * 3
        #if flags != 'peak':
        #    self.minX, self.maxX, self.maxY = self.getMax()
        self.pw = PlotWidget(self.minX, self.maxX, self.maxY, parent=self,
                             **k)  #parent=self,
        #self.pw.setAttribute(Qt.WA_DeleteOnClose)#plotItem.setAttribute(Qt.WA_PaintOnScreen & Qt.WA_PaintUnclipped)
        if k.get('antialiased', False):
            self.pw.setRenderHint(0x01)  #antialiasing i suppose
        self.pw.setTitle(title)
        self.pw.updateGrid()

        self._setupUi()

        self.connect(self, SIGNAL('linePlotted'), self.updateContextMenu)
        self.connect(self.view.sampleTableView,
                     SIGNAL("disHighlightRequested(QModelIndex)"),
                     self.disHighlightOne)
        self.connect(self.view.sampleTableView,
                     SIGNAL("highlightRequested(QModelIndex)"), self.highlight)
        self.connect(self.view.sampleTableView,
                     SIGNAL("noHighlightRequested()"), self.disHighlight)
        self.connect(self.view.ppmEditer, SIGNAL('valueChanged(double)'),
                     self.redrawAll)

        self.drawnItems = {}
        self.trashItems = []  #why unecessary? nope to collect annotation stuff
        self.textLabels = []
        self.pixmaps = []
        self.dataPoints = None

        self._plotting(self.data)  #initial plotting

    def getMax(self):
        localXmin = []
        localXmax = []
        localYmax = []
        for el in self.data:
            if el is None:
                continue
            localXmin.append(min_f(el.x_data))
            localXmax.append(max_f(el.x_data))
            localYmax.append(max_l(el.y_data))
        return min_f(np.array(localXmin)), max_f(np.array(localXmax)), max_l(
            np.array(localYmax))

    def _plotting(self, data):
        """
        refactor this shit
        c = Line(chrom.x_data, chrom.y_data, 
                 QColor.fromRgbF(*(self.ref.sample.color+(.7,))),
                 parent=self.pw.plotItem.vb, 
                 scene=self.pw.scene())
        
        #test scatter plot
        self.scatter = ScatterPlotItem(x=chrom.x_data, y=chrom.y_data)
        self.pw.addDataItem(self.scatter)
        self.scatter.sigClicked.connect(self.requestSpectra)
        
        """
        if self.flags == 'peak':

            self.connect(self.pw.plotItem.vb,
                         SIGNAL('showDiffOrSpectra(PyQt_PyObject)'),
                         self.drawSpectra)
            self.ref = sorted([e for e in data if e is not None],
                              key=lambda x: x.height)[-1]
            ppm = self.view.ppmEditer.value() if self.view.usePpm.isChecked(
            ) else self.ref.sample.ppm
            chrom = self.ref.sample.massExtraction(self.ref.mass(),
                                                   ppm,
                                                   asChromatogram=True)
            #show labels
            self.textLabels += self.showTextLabel(chrom.x_data, chrom.y_data)
            #drawing
            color = QColor.fromRgbF(*self.ref.sample.color + (.5, ))

            c = self.pw.plotItem.plot(chrom.x_data, chrom.y_data, pen=color)
            self.drawnItems[self.ref.sample] = c
            # peak's pixmap on the ref peak
            pix = PeakArrowItem(self.ref,
                                pen=color,
                                brush=color,
                                pos=(self.ref.rt, self.ref.height +
                                     (self.ref.height * 6) / 100.),
                                angle=-90,
                                parent=self.pw.plotItem.vb)
            pix.setZValue(1000)
            self.pw.addItem(pix)
            #both these connections are emitted
            #in peak Indicator by effictivamente qApp
            self.connect(qApp.instance(), SIGNAL("highlightRequested"),
                         c.setHighlighted)
            self.connect(qApp.instance(), SIGNAL('updateBarPlot'),
                         self.barPlot.setPeakGroup)  #
            self.emit(SIGNAL('linePlotted'), self.ref.sample.shortName())

            #if qApp.instance().lowMemory:
            #    chromatograms=[el.sample.loadAndExtract(el.mass(), el.sample.ppm, asChromatogram=True) \
            #                  for el in data if el != ref and el is not None]
            #else:
            ppm = self.view.ppmEditer.value() if self.view.usePpm.isChecked(
            ) else self.ref.sample.ppm
            chromatograms=[el.sample.massExtraction(el.mass(), ppm, asChromatogram=True) \
                          for el in data if el is not None and el != self.ref]
            self.drawEics(chromatograms)
            #initialisation zoom on the peak
            self.pw.setYRange(0.,
                              self.ref.height + (self.ref.height * 12) / 100.)
            self.pw.setXRange(self.ref.rtmin - 20, self.ref.rtmax + 20)

        elif self.flags == 'chroma':
            ref = [d for d in data if d is not None]
            if not ref:
                print "Error, empty data to plot"
                return
            self.ref = ref[0]
            self.textLabels += self.showTextLabel(self.ref.x_data,
                                                  self.ref.y_data)
            self.drawEics(data)

        else:  #spectrum
            if not data:
                #print "NOTHING TO PLOT"
                return
            self.ref = data[0]
            for el in data:
                c = SpectrumItem(el, centroid=True, scene=self.pw.scene())
                self.pw.addItem(c)
                self.drawnItems[el.sample] = c
                self.pw.plotItem.curves.append(c)
                self.emit(SIGNAL('linePlotted'), el.sample.shortName())
            #just put time information
            if data:
                i = 0
                while data[i] is None and i < len(data):
                    i += 1
                self.textLabels += self.showTextLabel(data[i].x_data,
                                                      data[i].y_data)
            #setting the range
            #warning: autoRange pw function does not work well
            #on spectrum item
            maxY = max([el.y_data.max() for el in data])
            minX, maxX = min([el.x_data.min() for el in data
                              ]), max([el.x_data.max() for el in data])
            self.pw.setXRange(minX, maxX, padding=0)
            self.pw.setYRange(0., maxY, padding=0)

    def drawEics(self, data):
        for chrom in data:
            color = QColor.fromRgbF(*(chrom.sample.color + (.5, )))
            c = self.pw.plotItem.plot(x=chrom.x_data,
                                      y=chrom.y_data,
                                      pen=color)
            #c = Line(chrom.x_data, chrom.y_data,
            #         color,
            #         parent=self.pw.plotItem.vb,
            #         scene=self.pw.scene())
            self.drawnItems[chrom.sample] = c
            #self.pw.addItem(c)
            #self.pw.plotItem.curves.append(c)
            self.emit(SIGNAL('linePlotted'), chrom.sample.shortName())
        if self.flags != 'peaks':
            self.pw.autoRange()
#===========================================================================
# UI stuffs
#===========================================================================

    def _setupUi(self):

        #        self.stop = QToolButton()
        #        self.stop.setIcon(QIcon('gui/icons/tools_wizard.png'))
        #        self.stop.setToolTip('Enable or disable the appearance of the contextMenu')
        layout = QVBoxLayout(self)

        self.smoothButton = QToolButton()
        #self.smoothButton.setToolButtonStyle(2)
        self.smoothButton.setPopupMode(2)
        self.smoothButton.setToolTip("Smooth the visualized data")
        #self.smoothButton.setText("Smooth...")
        self.smoothButton.setIcon(
            QIcon(os.path.normcase('gui/icons/smooth.png')))
        self.smoothMenu = QMenu()
        self.connect(self.smoothMenu, SIGNAL('triggered(QAction*)'),
                     self.smooth)
        self.smoothButton.setMenu(self.smoothMenu)
        self.pw.plotItem.toolBar.addWidget(self.smoothButton)

        self.flipButton = QToolButton()
        #self.flipButton.setToolButtonStyle(2)
        self.flipButton.setIcon(QIcon(os.path.normcase('gui/icons/flip.png')))
        self.flipButton.setToolTip("Flip the visualized data")
        #self.flipButton.setText("Flip...")
        self.flipButton.setPopupMode(2)
        self.flipMenu = QMenu()
        self.connect(self.flipMenu, SIGNAL('triggered(QAction*)'), self.flip)
        self.flipButton.setMenu(self.flipMenu)
        self.pw.plotItem.toolBar.addWidget(self.flipButton)

        self.annotButton = QToolButton()
        #self.annotButton.setToolButtonStyle(2)
        self.annotButton.setPopupMode(2)
        #self.annotButton.setText("&Annotate...")
        self.annotButton.setIcon(
            QIcon(os.path.normcase('gui/icons/attach.png')))
        self.annotMenu = QMenu()
        self.annotMenu.addAction("&Add Annotation")
        self.annotMenu.addAction("&Remove last Annotation")
        self.annotMenu.addAction("&Remove All Annotation")
        self.annotButton.setMenu(self.annotMenu)
        self.connect(self.annotMenu.actions()[0], SIGNAL("triggered()"),
                     self.annotate)
        self.connect(self.annotMenu.actions()[1], SIGNAL("triggered()"),
                     self.removeLastAnnot)
        self.connect(self.annotMenu.actions()[2], SIGNAL("triggered()"),
                     self.removeAllAnnot)
        self.pw.plotItem.toolBar.addWidget(self.annotButton)

        self.addPlotButton = QToolButton()
        #self.addPlotButton.setToolButtonStyle(2)
        self.addPlotButton.setText("Add...")
        self.addPlotButton.setIcon(
            QIcon(os.path.normcase('gui/icons/list_add.png')))
        self.addPlotButton.setToolTip("Add a new plot to the current figure")
        #self.addPlotButton.setText('&Add Plot')
        self.pw.plotItem.toolBar.addWidget(self.addPlotButton)

        self.showSpectra = QToolButton()
        self.showSpectra.setPopupMode(2)  #instant popup
        #self.showSpectra.setToolButtonStyle(2)
        self.showSpectra.setIcon(
            QIcon(os.path.normcase('gui/icons/file_export.png')))
        #self.showSpectra.setText('&Show /hide...')
        self.showSpectra.setToolTip('Show/hide ...')
        self.showMenu = QMenu()
        self.showTextLabels = QAction("&Show Labels", self.showMenu)
        self.showTextLabels.setCheckable(True)
        self.showTextLabels.setChecked(True)
        self.showMenu.addAction(self.showTextLabels)
        self.connect(self.showMenu.actions()[0], SIGNAL('toggled(bool)'),
                     self.setTextLabelsVisibility)
        showSpectrum = QAction("&Merged Spectrum", self.showMenu)
        showSpectrum.setCheckable(True)
        if self.flags == 'chroma' or self.flags == 'spectra':
            showSpectrum.setEnabled(False)
        self.showMenu.addAction(showSpectrum)
        self.connect(self.showMenu.actions()[1], SIGNAL('toggled(bool)'),
                     self.drawSpectraRequested)

        showNonXCMSPeak = QAction("&Show Non XCMS Peak", self.showMenu)
        showNonXCMSPeak.setCheckable(True)
        if self.flags == 'spectra':
            showNonXCMSPeak.setEnabled(False)
        self.showMenu.addAction(showNonXCMSPeak)
        self.connect(self.showMenu.actions()[2], SIGNAL('toggled(bool)'),
                     self.setPixmapVisibility)

        showDataPoints = QAction("&Show DataPoints", self.showMenu)
        showDataPoints.setCheckable(True)
        showDataPoints.setChecked(False)
        self.showMenu.addAction(showDataPoints)
        self.connect(self.showMenu.actions()[3], SIGNAL('toggled(bool)'),
                     self.setDataPointsVisibility)
        self.showSpectra.setMenu(self.showMenu)
        self.pw.plotItem.toolBar.addWidget(self.showSpectra)

        self.saveToPng = QToolButton()
        self.saveToPng.setIcon(
            QIcon(os.path.normcase('gui/icons/thumbnail.png')))
        #self.saveToPng.setToolButtonStyle(2)
        #self.saveToPng.setText("Save to Png...")
        self.pw.plotItem.toolBar.addWidget(self.saveToPng)
        self.connect(self.saveToPng, SIGNAL('clicked()'), self.pw.writeImage)
        #add bar plot even if we are plotting chroma
        #cause we can find non xcms peaks
        self.barPlot = BarPlot(scene=self.pw.sceneObj)
        #self.barPlot.rotate(-90.)
        if self.flags == 'peak':
            self.barPlot.setPeakGroup(self.data)
        #TODO modify to get this close to us
        #on the left part
        xpos = self.barPlot.scene().width() * 3.5  #-bwidth;
        ypos = self.barPlot.scene().height() * 1.1
        self.barPlot.setPos(xpos, ypos)
        self.barPlot.setZValue(1000)

        layout.addWidget(self.pw)
        layout.addWidget(self.pw.plotItem.toolBar)

    def showTextLabel(self, x, y, secure=25):
        """
        add labels of principle peaks of spectrum or chroma
        on the plot, return the labels, that we can show hide
        
        """
        maxis = []  #will contain tuple(rt, intens)
        indexes = []
        #from core.MetObjects import MSAbstractTypes
        from scipy.ndimage import gaussian_filter1d as gauss
        z = gauss(y, 1)
        #z = MSAbstractTypes.computeBaseLine(z, 92., 0.8)
        i = 0
        while i < len(z) - 1:
            while z[i + 1] >= z[i] and i < len(y) - 2:
                i += 1
            maxis.append((x[i], y[i]))
            indexes.append(i)
            while z[i + 1] <= z[i] and i < len(z) - 2:
                i += 1
            i += 1
        labels = []
        for t in sorted(maxis, key=lambda x: x[1])[-5:]:
            g = QGraphicsTextItem(str(t[0]))
            g.setFlag(QGraphicsItem.ItemIgnoresTransformations)
            font = QApplication.font()
            font.setPointSizeF(6.5)
            g.setFont(font)
            g.setDefaultTextColor(Qt.black)
            g.setPos(t[0], t[1])
            labels.append(g)
            self.pw.addItem(g)
        return labels

#===============================================================================
#SLOTS
#===============================================================================

    def redrawAll(self, value):
        self.pw.clear()
        self._plotting(self.data)

    def disHighlightOne(self, idx):
        if not idx.isValid():
            return
        sample = self.model.sample(idx.data().toString(), fullNameEntry=False)
        if sample is None:
            return
        try:
            self.drawnItems[sample].setHighlighted(False)
        except KeyError:
            pass

    def highlight(self, idx):
        if not idx.isValid():
            return
        sample = self.model.sample(idx.data().toString(), fullNameEntry=False)
        if sample is None:
            return
        try:
            self.drawnItems[sample].setHighlighted(True)
        except KeyError:
            pass
            #print "sample not found"
        self.pw.plotItem.update()  #works

    def disHighlight(self):
        for key in self.drawnItems.iterkeys():
            self.drawnItems[key].setHighlighted(False)
        self.pw.plotItem.update()

    def setTextLabelsVisibility(self, bool_):
        for t in self.textLabels:
            t.setVisible(bool_)

    def setDataPointsVisibility(self, b):
        if self.dataPoints is None:
            if self.flags == 'peak':
                chrom = self.ref.sample.massExtraction(self.ref.mass(),
                                                       self.ref.sample.ppm,
                                                       asChromatogram=True)
                self.dataPoints = ScatterPlotItem(x=chrom.x_data,
                                                  y=chrom.y_data)
            else:
                self.dataPoints = ScatterPlotItem(x=self.ref.x_data,
                                                  y=self.ref.y_data)
            if self.flags != 'spectra':
                self.dataPoints.sigClicked.connect(self.requestSpectra)
            self.pw.addDataItem(self.dataPoints)
        self.dataPoints.setVisible(b)

    def setPixmapVisibility(self, bool_):
        """
        draw other peaks than the xcms peak
        
        """
        if not self.pixmaps and bool_:
            ppm = 1. if self.ref.sample.kind == 'MRM' else self.ref.sample.ppm
            chrom = self.ref.sample.massExtraction(self.ref.mass(), ppm, asChromatogram=True) \
            if self.flags == 'peak' else self.ref
            chrom.findNonXCMSPeaks()
            for p in chrom.peaks.ipeaks():
                if self.flags == 'peak':
                    diff = (p.height * 10) / 100
                    if abs(p.height - self.ref.height) < diff:
                        continue  #we assume that they are the same peaks
                pix = PeakIndicator(p, icon='flags')
                #self.connect(pix, SIGNAL("highlightRequested"), c.setHighlighted)
                self.connect(pix, SIGNAL('updateBarPlot'),
                             self.barPlot.setPeakGroup)
                pix.setPos(p.rt, p.height + (p.height * 10) / 100.)
                pix.setZValue(1000)
                self.pixmaps.append(pix)
                self.pw.addItem(pix)
        if self.pixmaps:
            for t in self.pixmaps:
                t.setVisible(bool_)

    @pyqtSlot()
    def updateCurrentPeak(self):
        idx = self.acTree.selectedIndexes()[0]
        s = self.model.sample(idx.parent().data().toString(),
                              fullNameEntry=False)
        if s is not None:
            self.currentPeak = s.peakAt(*map(float,
                                             idx.data().toString().split('/')))

    def requestSpectra(self, scatter, l):
        """
        idea plot all spectra between a time range
        and not only with only one spectra
        
        """
        if not l:
            return
        ref = l[0]
        self.emit(SIGNAL("drawSpectrumByTime"), ref.pos(), self.ref.sample)

    @pyqtSlot()
    def drawSpectraRequested(self, bool_):
        """
        i think this is for plotting merged spectrum
        
        """
        if bool_:
            self.emit(SIGNAL('drawSpectraRequested'), self.currentPeak)
        else:
            self.hideRequested()

    def drawSpectra(self, l):
        self.emit(
            SIGNAL('drawSpectra(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
            l[0], l[1], self.ref.sample)

    @pyqtSlot()
    def hideRequested(self):
        self.emit(SIGNAL('hideRequested'))
        self.showMenu.actions()[1].setChecked(False)

    @pyqtSlot()
    def redraw(self):
        """
        this is for updating the view port
        when hiding or not samples
        
        """
        chromas = []
        for spl in self.model:
            if spl.checked:
                if spl in self.drawnItems.keys():
                    self.drawnItems[spl].setVisible(True)
                else:
                    chromas.append(spl.chroma[0])
            else:
                self.drawnItems[spl].setVisible(False)
        self._plotting(chromas)
        self.pw.plotItem.update()  #works

    def cleanScene(self):
        """
        remove all items in the trash
        
        """
        for element in self.trashItems:
            self.pw.sceneObj.removeItem(element)

    @pyqtSlot()
    def updateContextMenu(self, line):
        self.flipMenu.addAction(line)
        self.smoothMenu.addAction(line)


#===============================================================================
# CONTEXT MENU SLOTS
#===============================================================================

    @pyqtSlot(str)
    def flip(self, action):
        spl = self.model.sample(self.fullXmlPath(action.text()))
        if spl is None:
            print "can not flip, can not recognize the selected sample"
            return
        try:
            self.drawnItems[spl].updateData(-self.drawnItems[spl].getData()[1],
                                            self.drawnItems[spl].getData()[0])
        except KeyError:
            pass
        if len(self.data) == 1:
            #we are flipping the text labels only
            #if only one dataset is flipped
            for item in self.textLabels:
                item.setPos(item.pos().x(), -item.pos().y())

    @pyqtSlot(str)
    def smooth(self, action):
        """
        TODO:
        would be good to reuse the widget in the menuControl
        
        """
        from core.MetObjects import MSAbstractTypes

        class Dial(QDialog):
            choices = ['flat', 'hanning', 'hamming', 'bartlett', 'blackman']

            def __init__(self, parent):
                QDialog.__init__(self, parent)
                f = QFormLayout(self)
                self.a = QSpinBox(self)
                self.a.setValue(30)
                self.b = QComboBox(self)
                self.b.addItems(self.choices)
                self.c = QDialogButtonBox(self)
                self.c.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.Ok)
                f.addRow("window:", self.a)
                f.addRow("method:", self.b)
                f.addRow("", self.c)
                self.connect(self.c, SIGNAL("accepted()"), self.sendData)
                self.connect(self.c, SIGNAL("rejected()"), self.reinitialize)

            def sendData(self):
                self.parent().window = self.a.value()
                self.parent().method = self.b.currentText()
                self.close()

            def reinitialize(self):
                self.parent().window = None
                self.parent().method = None
                self.close()

        Dial(self).exec_()
        if self.window and self.method:
            for spl in self.drawnItems.keys():
                if action.text() == spl.shortName():
                    self.drawnItems[spl].updateData(
                        MSAbstractTypes.averageSmoothing(
                            self.drawnItems[spl].getData()[1], self.window,
                            self.method), self.drawnItems[spl].getData()[0])

    @pyqtSlot()
    def plotEIC(self):
        if self.flags == 'spectra':

            #show double combobox
            #select the good spectra then draw
            pass
        else:
            mass, ok = QInputDialog.getText(self.view, "EIC query", "mass:")
            if not (mass and ok):
                return
            xmlfile = self.fullXmlPath(self.selection[0].data().toString())
            if not xmlfile:
                xmlfile = self.fullXmlPath(
                    self.selection[0].parent().data().toString())
            if not xmlfile:
                print "item clicked not recognized..."
                return
            sample = self.model.sample(xmlfile)
            if sample.kind == 'HighRes':
                error = (sample.ppm / 1e6) * float(mass)
                x, y = massExtraction(sample, float(mass), error)
                from core.MetObjects import MSChromatogram
                chrom = MSChromatogram(x_data=x, y_data=y, sample=sample)
            else:
                chrom = sample.getChromWithTrans(math.ceil(float(mass)))
        self.view.addMdiSubWindow(
            MSQtCanvas([chrom],
                       "EIC %s" % str(mass),
                       labels={
                           'bottom': 'RT(s)',
                           'left': 'INTENSITY'
                       }))

    #===========================================================================
    # annotate stuff
    #===========================================================================
    @pyqtSlot()
    def annotate(self):
        text, bool_ = QInputDialog.getText(self.view, "Annotation dialog",
                                           "Annotation:")
        g = QGraphicsTextItem(str(text))
        g.setFlag(QGraphicsItem.ItemIgnoresTransformations)
        g.setFlag(QGraphicsItem.ItemIsMovable)
        g.setTextInteractionFlags(Qt.TextEditorInteraction)
        font = qApp.instance().font()
        font.setPointSizeF(10.)
        g.setFont(font)
        g.setDefaultTextColor(Qt.blue)
        g.setPos(500, 1e4)
        self.trashItems.append(g)
        self.pw.addItem(g)

    def removeAllAnnot(self):
        if not self.trashItems:
            self.view.showErrorMessage("Error", "No annotation detected")
            return
        for i in self.trashItems:
            self.pw.removeItem(i)

    def removeLastAnnot(self):
        if not self.trashItems:
            self.view.showErrorMessage("Error", "No annotation detected")
        self.pw.removeItem(self.trashItems[-1])
Example #28
0
class QuestionDlg(QDialog):
    def __init__(self,parent=None):
        super(QuestionDlg,self).__init__(parent)
        # self.setStyleSheet("background-image:url('image/panelbg.jpg'); border: 2px; border-radius 2px;")
        self.setWindowFlags(Qt.CustomizeWindowHint)
        # self.setStyleSheet("border: 2px; border-radius 2px;")
        # self.setWindowFlags(Qt.FramelessWindowHint)
        self.setStyleSheet("background-color: rgba(132, 171, 208, 200);")

        tabWidget=QTabWidget(self)
        tabWidget.currentChanged.connect(self.changeTab)
        # tabWidget.setTabShape(QTabWidget.Triangular)
        tabWidget.setStyleSheet("QTabWidget::pane{border-width:1px;border-color:rgb(48, 104, 151);\
            border-style: outset;background-color: rgb(132, 171, 208);\
            background: transparent;} \
            QTabWidget::tab-bar{border-width:0px;}\
            QTabBar::tab { height: 60px; width: 260px; color:rgb(0, 0, 255); font-size:20px; font-weight:bold;} \
            QTabBar::tab:hover{background:rgb(255,255, 255, 100);} \
            QTabBar::tab:selected{border-color:green;background-color:white;color:green;}")
        # tabWidget.setStyleSheet("QTabBar::tab:hover{background:rgb(255,255, 255, 100);}")
        self.btngroup = QButtonGroup()
        self.popMenu = QMenu(self)
        entry1 = self.popMenu.addAction("正确")
        self.connect(entry1,SIGNAL('triggered()'), lambda : self.answerRight())
        entry2 = self.popMenu.addAction("错误")
        self.connect(entry2,SIGNAL('triggered()'), lambda : self.answerWrong())
        entry3 = self.popMenu.addAction("替换")
        self.connect(entry3,SIGNAL('triggered()'), lambda : self.resetStudent())

        w1=QWidget()
        w1.setAccessibleName("w1tab")
        self.w1title = QLabel()
        self.btn_start = MyButton("开始")
        self.choicenum_text = QComboBox()
        self.choicenum_text.setObjectName('w1combonums')
        # self.w1title.setStyleSheet("background-image:url('image/panelbg.jpg');")
        

        titleLayout, btnlayout, bottomlayout = self.genOneTab(tabtitle = self.w1title, tabbtn=self.btn_start, tabnums=self.choicenum_text)

        tab1layout = QVBoxLayout()
        tab1layout.addLayout(titleLayout)       
        tab1layout.addLayout(btnlayout)
        tab1layout.addLayout(bottomlayout)
                
        w1.setLayout(tab1layout)
        w1.setStyleSheet("background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #228888);")

        w2=QWidget()
        w2.setAccessibleName("w2tab")
        self.w2title = QLabel()
        self.btn_start2 = QPushButton("开始")
        self.choicenum_text2 = QComboBox()
        self.choicenum_text2.setObjectName('w2combonums')
        titleLayout2, btnlayout2, bottomlayout2 = self.genOneTab(tabtitle = self.w2title, tabbtn=self.btn_start2, tabnums=self.choicenum_text2, strwhere = "where studentsn like '04%' ")
        tab2layout = QVBoxLayout()
        tab2layout.addLayout(titleLayout2)       
        tab2layout.addLayout(btnlayout2)
        tab2layout.addLayout(bottomlayout2)
        w2.setLayout(tab2layout)
        w2.setStyleSheet("background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #228888);")

        tabWidget.addTab(w1,"三(3)班")
        tabWidget.addTab(w2,"三(4)班")
        tabWidget.resize(740,700)
        # print(tabWidget.parentWidget())
        btnclose = QPushButton(self)
        btnclose.setToolTip("关闭")
        btnclose.setText("╳")
        btnclose.setGeometry(715, 5, 20, 20)
        btnclose.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255)")
        btnclose.clicked.connect(self.close)
        btnMinimized = QPushButton(self)
        btnMinimized.setToolTip("最小化")
        btnMinimized.setText("▁")
        btnMinimized.setGeometry(690, 5, 20, 20)
        btnMinimized.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255)")
        btnMinimized.clicked.connect(lambda: self.showMinimized())
        self.btnSysMenu = QPushButton(self)
        # self.btnSysMenu.setText("▼")
        self.btnSysMenu.setGeometry(665, 5, 20, 20)
        self.btnSysMenu.setToolTip("系统设置")
        self.btnSysMenu.clicked.connect(lambda: self.showMinimized())
        menufont = QFont("宋体", 10)
        popMenu = QMenu(self)
        entry1 = popMenu.addAction("初始化")
        entry1.setFont(menufont)
        self.connect(entry1,SIGNAL('triggered()'), self.initStudent)
        entry2 = popMenu.addAction("清除提问人员")
        entry2.setFont(menufont)
        self.connect(entry2,SIGNAL('triggered()'), self.deleteTmpdata)
        self.btnSysMenu.setMenu(popMenu)
        self.btnSysMenu.setStyleSheet("QPushButton::menu-indicator {image: url('image/sysmenu.png');subcontrol-position: right center;} ")
        # self.btnSysMenu.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255);")

        authorinfo = QLabel(tabWidget)
        # authorinfo.setToolTip("关闭")
        authorinfo.setText("汕头市大华一小:赵小娜")
        authorinfo.setGeometry(20, 665, 235, 26)
        authorinfo.setStyleSheet("background-color:rgba(255, 255, 255,160); font-size:20px;border: 1px solid rgb(60,200,255,200);color:rgba(0,0,0,220);border-radius:12px;")

        self.setWindowTitle("课堂随机提问")
        self.setWindowIcon(QIcon("image/start.ico"))
        self.setGeometry(100, 20, 740, 700)

        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2)

        self.btn_start.setMyarg('start')
        # print(self.btn_start.getMyarg())

        self.connect(self.btn_start, SIGNAL("clicked()"), self.startChoice)
        # self.connect(self.w1title, SIGNAL("currentIndexChanged(int)"), self.changeTitle)
        self.connect(self.btn_start2, SIGNAL("clicked()"), self.startChoice)
        # self.connect(self.w2title, SIGNAL("currentIndexChanged(int)"), self.changeTitle)
        self.btngroup.buttonClicked[int].connect(self.btns_click)
        # self.connect(self.btn_start,  SIGNAL("myslot(PyQt_PyObject)"), self.myslot)  
        # self.connect(self.btngroup, SIGNAL("buttonClicked(int)"), lambda:self.btns_click())

    def myslot(self, text):  
        # print(text)
        self.g_curbtn = text
        if self.g_curbtn not in self.dict_choices:
            self.btnSysMenu.setFocus()
            return

        # print(self.btngroup.button(int(self.g_curbtn)).parent())
        # print(type(self.btngroup.button(int(self.g_curbtn)).parentWidget()))
        pos = self.btngroup.button(int(self.g_curbtn)).parent().mapToGlobal(self.btngroup.button(int(self.g_curbtn)).pos())
        width = self.btngroup.button(int(self.g_curbtn)).rect().height()
        # print("-----", pos, width)
        pos.setY(pos.y()+width-5)

        indx = 0
        for istate in self.dict_choices[self.g_curbtn]:
            if istate == '1':
                self.popMenu.actions()[indx].setEnabled(True)
            elif istate == '0':
                self.popMenu.actions()[indx].setEnabled(False)
            indx += 1
        self.popMenu.exec_(pos)
        self.btnSysMenu.setFocus()
    # def on_context_menu(self, point):
    #     print(point)
    #     self.popMenu.exec_(self.button.mapToGlobal(point)) 

    def btns_click(self, btnid):
        # print(self.btngroup.button(btnid).rect())
        # print(self.mapToGlobal(self.btngroup.button(btnid).pos()))
        cur = conn.cursor()
        today = datetime.date.today()
        self.g_curbtn = str(btnid).zfill(4)
        if self.g_curbtn not in self.dict_choices:
            self.btngroup.button(int(self.g_curbtn)).setStyleSheet(stylesheetstr_new)
            cur.execute("select count(*) from tmprecord where studentsn='" + str(self.g_curbtn) + "'")
            if cur.fetchall()[0][0] == 0:
                strsql = "insert into tmprecord values (?, ?, ?)"
                cur.execute(strsql, (None, self.g_curbtn, today))
                conn.commit()
            self.dict_choices[self.g_curbtn] = "111"
        else:
            self.btngroup.button(int(self.g_curbtn)).setStyleSheet(stylesheetstr_old)
            self.btngroup.button(int(self.g_curbtn)).setIcon(QIcon())
            # cur.execute("select count(*) from tmprecord where studentsn='" + str(self.g_curbtn) + "'")
            # print(cur.fetchall())
            cur.execute("delete from tmprecord where studentsn='"+ str(self.g_curbtn) + "'")
            conn.commit()
            self.dict_choices.pop(self.g_curbtn)
        self.btnSysMenu.setFocus()
        cur.close()

    def initStudent(self):
        cur = conn.cursor()
        cur.execute("update student set wrongquestions=0")
        conn.commit()
        cur.execute("update student set rightquestions=0")
        conn.commit()

        # cur.execute("select * from student")
        # print(cur.fetchall())
        cur.close()

    def deleteTmpdata(self):
        cur = conn.cursor()
        cur.execute("delete from tmprecord where 1=1" )
        conn.commit()
        cur.close()

    def changeTab(self, curtab):
        if curtab == 0:
            strwhere = " and studentsn like '03%' "
        elif curtab == 1:
            strwhere = " and studentsn like '04%' "

        self.g_curbtn = ""
        self.dict_choices = {}

        cur = conn.cursor()
        cur.execute("delete from tmprecord where 1=1")
        conn.commit()
        cur.execute("select studentsn from student where 1=1 " + strwhere)
        self.studentSnlst = cur.fetchall()

        for isn in self.studentSnlst:
            self.btngroup.button(int(isn[0])).setStyleSheet(stylesheetstr_old)
            self.btngroup.button(int(isn[0])).setIcon(QIcon())

        # print(self.studentSnlst)
        self.group_animation = groupAnimation(self.studentSnlst, self.btngroup)
        # print(self.group_animation)

        cur.close()

    def mousePressEvent(self, event):
        if event.button() == Qt.RightButton:
            QDialog.mousePressEvent(self,event)
            return
        # print(event.sender(), event.button())
        self.offset = event.pos()
        # print(self.offset)

    def mouseMoveEvent(self, event):
        if hasattr(self, 'offset'):
            x=event.globalX()
            y=event.globalY()
            x_w = self.offset.x()
            y_w = self.offset.y()
            self.move(x-x_w, y-y_w)
        else:
            pass

    def genOneTab(self, tabtitle="", tabbtn="", tabnums="", strwhere = "where studentsn like '03%' "):
        # tabtitle.setFixedHeight(40)
        # tabtitle.setFixedWidth(160)
        tabtitle.setFont(QFont('Courier New', 20))
        tabtitle.setText("随堂提问演板")
        tabtitle.setStyleSheet("border: 1px solid blue; color:rgba(0,0,255, 220);\
            background-color:rgba(201,201,201,60);\
            border-radius: 6px; \
            padding: 1px 18px 1px 20px;\
            min-width: 8em;")
        tabtitle.setMinimumHeight(50);
        titleLayout = QHBoxLayout()
        titleLayout.addWidget(tabtitle)
        titleLayout.setAlignment(tabtitle, Qt.AlignCenter)
       
        btnlayout = QGridLayout()
        
        cur = conn.cursor()
        strsql = "select studentsn, studentname from student " + strwhere
        cur.execute(strsql)
     
        tmpnum = 0
        for item in cur.fetchall():
            irow = tmpnum // 7
            icol = tmpnum % 7
            tmpnum += 1
            btnlayout.setRowMinimumHeight(irow, 80)

            tmpbtn = MyButton(item[1])
            tmpbtn.setMyarg(item[0])
            # tmpbtn.setFixedHeight(20)
            tmpbtn.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding))
            # tmpbtn.setStyleSheet("border: 1px solid rgb(255,255,255,0);background-color: rgba(255,255,255,20);font-size:16px;")
            # tmpbtn.setFlat(True)
            self.connect(tmpbtn,  SIGNAL("myslot(PyQt_PyObject)"), self.myslot)
            # self.connect(tmpbtn, SIGNAL('customContextMenuRequested(const QPoint&)'), self.on_context_menu)

            tmpbtn.setAutoDefault(False)
            self.btngroup.addButton(tmpbtn, int(item[0]))

            btnlayout.addWidget(tmpbtn, irow, icol)

        tabbtn.setIcon(QIcon("image/start.png"))
        tabbtn.setStyleSheet("border: 1px solid yellow;")
        tabbtn.setFixedHeight(40)
        tabbtn.setFixedWidth(100)
        tabbtn.setFont(QFont('宋体', 20))
        # tabnums.setFixedHeight(45)
        # tabnums.setFixedWidth(60)
        tabnums.setFont(QFont('Courier New', 20))
        tabnums.setFixedHeight(45)
        tabnums.setStyleSheet("border: 2px solid blue; color:red;font-weight:light;font-size:26px;\
            border-radius: 6px; \
            min-width: 2em; ")
        tabnums.setEditable(True)
        tabnums.lineEdit().setReadOnly(True);
        tabnums.lineEdit().setAlignment(Qt.AlignCenter);

        model = tabnums.model()
        for row in list(range(1, 7)):
            item = QStandardItem(str(row))
            item.setTextAlignment(Qt.AlignCenter)
            item.setForeground(QColor('red'))
            item.setBackground(QColor(0,200,50, 130))
            model.appendRow(item)
        tabnums.setCurrentIndex(2)
        # tabnums.setStyleSheet ("QComboBox::drop-down {border-width: 100px;}")
        # tabnums.setStyleSheet ("QComboBox::down-arrow {image: url(image/downarrow.png);top: 10px;left: 1px;}")

        bottomlayout = QHBoxLayout()
        bottomlayout.setSizeConstraint(QLayout.SetFixedSize)
        bottomlayout.addStretch(10)
        bottomlayout.addWidget(tabbtn)
        bottomlayout.setSpacing(5)
        bottomlayout.addWidget(tabnums)
     
        cur.close()
        return(titleLayout, btnlayout, bottomlayout)
    
    def startChoice(self, usernum="", oldbtn=""): 
        if oldbtn != "":
            flag = str(int(oldbtn[:2]))
        else:
            self.dict_choices = {}
            whichtabpage = self.sender().parentWidget().accessibleName()
            flag = (whichtabpage == "w1tab") and "3" or "4"
            
        if flag== "3":
            strwhere = " and studentsn like '03%' "
            tabCombonums = self.findChild(QComboBox, 'w1combonums')
        else:
            strwhere = " and studentsn like '04%' "
            tabCombonums = self.findChild(QComboBox, 'w2combonums')

        # print(usernum, oldbtn)

        allstudent = []
        lstrecord = ['0000', '1111']
        cur = conn.cursor()   
        cur.execute("select studentsn from tmprecord where 1=1 " + strwhere)  
        for item in cur.fetchall():
            lstrecord.append(item[0])
        # print(lstrecord, 'record', "select studentsn from student where studentsn like '03%' and studentsn not in " + str(tuple(lstrecord)))
        cur.execute("select studentsn from student where studentsn not in " + str(tuple(lstrecord)) + strwhere)
        for item in cur.fetchall():
            allstudent.append(item[0])

        if usernum == "":
            nums = int(tabCombonums.currentText())
        else:
            nums = usernum
        if nums >= len(allstudent):
            cur.execute("delete from tmprecord where 1=1 " + strwhere) #delete tmp date no today
            conn.commit()
            allstudent = []
            cur.execute("select studentsn from student where 1=1 " + strwhere)
            for item in cur.fetchall():
                allstudent.append(item[0])
        # print(tabCombonums.currentText())
        cur.close()

        if oldbtn == "":
            random.seed()
            lstchoices = random.sample(allstudent, nums)
            for ibtn in lstchoices:
                self.dict_choices[ibtn] = "111"

            self.group_animation.start()
            QTimer.singleShot(1200, self.stopmovie)
        else:
            random.seed()
            otherbtn = random.sample(allstudent, 1)[0]
            # self.btngroup.button(int(otherbtn)).setFocus()
            self.dict_choices.pop(oldbtn)
            self.dict_choices[otherbtn] = '111'
            self.stopmovie()
        self.btnSysMenu.setFocus()

    def stopmovie(self):
        self.group_animation.stop()
        for isn in self.studentSnlst:
            self.btngroup.button(int(isn[0])).setStyleSheet(stylesheetstr_old)
            self.btngroup.button(int(isn[0])).setIcon(QIcon())
    
        cur = conn.cursor()
        today = datetime.date.today()
        for ibtn in self.dict_choices:
            self.btngroup.button(int(ibtn)).setStyleSheet(stylesheetstr_new)
            cur.execute("select count(*) from tmprecord where studentsn='" + str(ibtn) + "'")
            if cur.fetchall()[0][0] == 0:
                strsql = "insert into tmprecord values (?, ?, ?)"
                cur.execute(strsql, (None, ibtn, today))
                conn.commit()

        # cur.execute("select * from tmprecord")
        # print(cur.fetchall())
        cur.close()

    def answerRight(self):
        # print(self.g_curbtn)
        value = self.g_curbtn
        if value not in self.dict_choices:
            return

        self.btngroup.button(int(value)).setIcon(QIcon("image/smile.png"))
        self.btngroup.button(int(value)).setIconSize(QSize(20,20))

        cur = conn.cursor()
        cur.execute("select rightquestions from student where studentsn='" + value + "'")
        studentRightQuestions = cur.fetchall()[0][0] + 1
        cur.execute("update student set rightquestions=" + str(studentRightQuestions) + " where studentsn='" + value + "'")
        conn.commit()
        
        ###########
        if self.dict_choices[value] == "101":
            cur.execute("select wrongquestions from student where studentsn='" + value + "'")
            studentWrongQuestions = cur.fetchall()[0][0] - 1
            cur.execute("update student set wrongquestions=" + str(studentWrongQuestions) + " where studentsn='" + value + "'")
            conn.commit()
        cur.close()

        self.dict_choices[value] = "011"

    def answerWrong(self):
        value = self.g_curbtn
        if value not in self.dict_choices:
            return

        self.btngroup.button(int(value)).setIcon(QIcon("image/cry.png"))
        self.btngroup.button(int(value)).setIconSize(QSize(20,20))
        # self.btngroup.button(int(value)).setStyleSheet("border-image: url(image/ex_stu.png);")

        cur = conn.cursor()
        cur.execute("select wrongquestions from student where studentsn='" + value + "'")
        studentWrongQuestions = cur.fetchall()[0][0] + 1
        cur.execute("update student set wrongquestions=" + str(studentWrongQuestions) + " where studentsn='" + value + "'")
        conn.commit()

        if self.dict_choices[value] == "011":
            cur.execute("select rightquestions from student where studentsn='" + value + "'")
            studentRightQuestions = cur.fetchall()[0][0] - 1
            cur.execute("update student set rightquestions=" + str(studentRightQuestions) + " where studentsn='" + value + "'")
            conn.commit()
        cur.close()
        self.dict_choices[value] = "101"

    def resetStudent(self):
        value = self.g_curbtn
        if value not in self.dict_choices:
            return

        # self.btngroup.button(int(value)).parentWidget().setStyleSheet("border: 1px solid rgb(255,255,255,0);background-color: rgba(255,255,255,20);font-size:16px;")
        # self.btngroup.button(int(value)).setStyleSheet("border: 1px solid rgb(255,255,255,0);background-color: rgba(255,255,255,20);font-size:16px;")
        # self.btngroup.button(int(value)).setAutoDefault(False)

        cur = conn.cursor()

        if self.dict_choices[value] == "011":        
            cur.execute("select rightquestions from student where studentsn='" + value + "'")
            studentRightQuestions = cur.fetchall()[0][0] - 1
            cur.execute("update student set rightquestions=" + str(studentRightQuestions) + " where studentsn='" + value + "'")
            conn.commit()
        if self.dict_choices[value] == "101":
            cur.execute("select wrongquestions from student where studentsn='" + value + "'")
            studentWrongQuestions = cur.fetchall()[0][0] - 1
            cur.execute("update student set wrongquestions=" + str(studentWrongQuestions) + " where studentsn='" + value + "'")
            conn.commit()
        cur.close()

        self.startChoice(usernum=1, oldbtn=value)
        # print("---reset___")

        # curmenu.actions()[0].setEnabled(True)
        # curmenu.actions()[1].setEnabled(True)
        # self.choiceOneStudent(value)

    def createDb(self):
        cur = conn.cursor()
        sqlstr = 'create table student (id integer primary key, \
            studentsn varchar(20), \
            studentname varchar(20), \
            rightquestions integer, \
            wrongquestions integer)'
        # print(sqlstr)

        sqlstr2 = 'create table tmprecord (id integer primary key, \
            studentsn varchar(20), \
            datequestion date)'

        strdelete = "delete from student where 1=1"
        cur.execute(strdelete)
        conn.commit()
        strdelete = "delete from tmprecord where 1=1"
        cur.execute(strdelete)
        conn.commit()
        # print(sqlstr2)

        # cur.execute(sqlstr) 
        # conn.commit()
        # cur.execute(sqlstr2) 
        # conn.commit()

        # insert example data
        a03lst = ["曾忆谊","赵佳泉","翁文秀","林珑","郑铭洁","林泽思","吴崇霖","陈思嘉","欧阳月孜","郭展羽","詹伟哲","黄佳仪","杨秋霞","周奕子","林楚杰","欧伊涵","许腾誉","陈唯凯","陈树凯","林彦君","张钰佳","高锴","杨博凯","林妙菲","林楚鸿","陈展烯","姚静茵","吴欣桐","范思杰","肖佳","马思广","许一帆","姚奕帆","陈海珣","吴黛莹","吴育桐","肖凯帆","林欣阳","叶茂霖","姚楷臻","陈嘉豪","陈琦","杨子楷","陈炎宏","陈幸仪","杨景畅","罗暖婷","郑馨"]
        a04lst = ["罗恩琪","王可","曾祥威","谢濡婷","温嘉凯","许洁仪","肖欣淇","陈凯佳","林天倩","李乐海","吴文慧","黄文婷","万誉","陈进盛","张裕涵","陈振嘉","王巧玲","林珮琪","陈炜楷","杨健","赵泽锴","张凤临","蔡子丹","陈烨杰","廖妍希","林树超","夏培轩","陈锦森","李星","蔡依婷","姚容创","姚凯扬","沈嘉克","周凡","张玉川","邱金迅","陈菲敏","陈星翰","朱煜楷","郑泽洪","钱剑非","罗奕丰","陈杜炜","林知钦"]
        strsql = "insert into student values (?, ?, ?,?,?)" 
        for i in list(range(0,len(a03lst))):
            cur.execute(strsql, (None, "03"+str(i+1).zfill(2), a03lst[i], 0, 0))
            conn.commit()
        strsql = "insert into student values (?, ?, ?,?,?)" 
        for i in list(range(0,len(a04lst))):
            cur.execute(strsql, (None, "04"+str(i+1).zfill(2), a04lst[i], 0, 0))
            conn.commit()
        cur.close()
Example #29
0
class MSView(QSplitter):
    modifiedContext = pyqtSignal(object)

    def __init__(self, widget, parent=None, **kw):
        QSplitter.__init__(self, Qt.Horizontal, parent)
        self.setFocusPolicy(Qt.StrongFocus)
        self.mainWidget = widget
        self.addWidget(self.mainWidget)

        self.showHide = None

        self.subsidiaryWidget = MSQtCanvas(
            [], "", flags='spectrum')  #, subsidiaryWidget=True)
        self.subsidiaryWidget.pw.plotItem.toolBar.hide()

        self.subsidiaryWidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.connect(self.subsidiaryWidget,
                     SIGNAL("customContextMenuRequested(const QPoint &)"),
                     self.showContextMenu)
        self.menu = QMenu(self.subsidiaryWidget)
        self.menu.addAction("&Hide...")
        self.connect(self.menu.actions()[0], SIGNAL("triggered()"),
                     self.subsidiaryWidget.hide)

        self.addWidget(self.subsidiaryWidget)
        self.subsidiaryWidget.hide()
        self.barplotdrawn = False

        self.connect(self.mainWidget, SIGNAL('drawSpectraRequested'),
                     self.drawSpectrum)
        self.connect(
            self.mainWidget,
            SIGNAL('drawSpectra(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
            self.drawSpectra)
        self.connect(self.mainWidget, SIGNAL('drawSpectrumByTime'),
                     self.drawSpectrumByTime)
        self.connect(self.mainWidget, SIGNAL('hideRequested'),
                     self.subsidiaryWidget.hide)

    def showContextMenu(self, pos):
        if self.subsidiaryWidget.pw.plotItem.vb.hasMoved:
            return self.menu.exec_(QCursor.pos())

    @pyqtSlot()
    def drawSpectrum(self, p):
        if p is None:
            return
        mergedSpectra = p.merge(p.spectra)
        self.subsidiaryWidget.pw.clear()
        self.subsidiaryWidget._plotting([mergedSpectra])
        self.subsidiaryWidget.pw.setTitle("Merged Spectrum@%s-%s" %
                                          (str(p.rtmin), str(p.rtmax)))
        self.subsidiaryWidget.show()

    def drawSpectrumByTime(self, t, sample):
        if not sample or not t:
            print "unknown error..."
            return
        spectra = sample.spectraInRTRange(t.x(), t.x() - 2., t.x() + 2.)
        if not spectra:
            print "No spectrum found at this retention time"
            return
        closest = sorted(spectra, key=lambda x: abs(t.x() - x.rtmin))[0]
        self.subsidiaryWidget.pw.clear()
        self.subsidiaryWidget._plotting([closest])
        self.subsidiaryWidget.pw.setTitle("Spectrum@%s" % (str(closest.rtmin)))
        self.subsidiaryWidget.show()

    def drawSpectra(self, inf, sup, sample):
        if not sample:
            return
        spectra = sample.spectraInRTRange((inf + sup) / 2., inf, sup)
        print[s.rtmin for s in spectra]
        spectrum = None
        if not spectra:
            print "No spectrum found at this retention time"
            return
        elif len(spectra) > 1:
            ref = spectra[0]
            others = spectra[1:]
            spectrum = ref.merge(others)
        else:
            spectrum = spectra[0]
        self.subsidiaryWidget.pw.clear()
        self.subsidiaryWidget._plotting([spectrum])
        self.subsidiaryWidget.pw.setTitle("Spectrum@%s" %
                                          (str(spectrum.rtmin)))
        self.subsidiaryWidget.show()
Example #30
0
class MainWindow(QWidget):
    def __init__(self):
        super(QWidget, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.systemTray = QSystemTrayIcon(self)
        self.systemTray.setIcon(QIcon(':/images/icon.png'))
        self.act_autostart = QAction('开机启动', self)
        self.act_autostart.setCheckable(True)
        is_autostart = self.is_autostart()
        self.act_autostart.setChecked(is_autostart)
        self.act_autostart.triggered.connect(self.on_autostart)
        act_setting = QAction('设置启动项', self)
        act_setting.triggered.connect(self.on_settings)
        act_exit = QAction('退出', self)
        act_exit.triggered.connect(self.on_exit)
        self.menu_run = QMenu('运行', self)
        menu = QMenu('菜单', self)
        menu.addMenu(self.menu_run)
        menu.addAction(act_setting)
        menu.addSeparator()
        menu.addAction(self.act_autostart)
        menu.addAction(act_exit)
        self.systemTray.setContextMenu(menu)
        self.systemTray.show()
        self.showMessage('启动工具正在运行')

        self.ui.btn_add.clicked.connect(self.on_add)
        self.ui.btn_delete.clicked.connect(self.on_delete)
        self.ui.btn_apply.clicked.connect(self.on_apply)
        self.ui.btn_env_add.clicked.connect(self.on_env_add)
        self.ui.btn_env_del.clicked.connect(self.on_env_del)
        self.ui.btn_open.clicked.connect(self.on_open)
        self.ui.btn_run.clicked.connect(self.on_run)
        self.ui.le_args.textEdited.connect(self.on_edited)
        self.ui.le_desc.textEdited.connect(self.on_edited)
        self.ui.le_exe.textEdited.connect(self.on_edited)
        self.ui.cb_process.currentIndexChanged.connect(self.on_index_changed)
        self.ui.le_exe.installEventFilter(self)
        self.init()

    def eventFilter(self, obj, event):
        if event.type() == QEvent.DragEnter:
            # we need to accept this event explicitly to be able to receive QDropEvents!
            event.accept()
        if event.type() == QEvent.Drop:
            md = event.mimeData()
            urls = md.urls()
            if (urls and urls[0].scheme() == 'file'):
                # for some reason, this doubles up the intro slash
                filepath = urls[0].path().mid(1)
                self.ui.le_exe.setText(filepath)
                self.modify = True
                self.ui.btn_apply.setEnabled(True)
            event.accept()
        return QObject.eventFilter(self, obj, event)

    def showMessage(self, msg):
        self.systemTray.showMessage('Launcher', msg,
                                    QSystemTrayIcon.Information, 10000)

    def config_dir(self):
        confd = QString2str(
            QApplication.applicationDirPath()) + os.sep + 'configs'
        dir = QDir(confd)
        if not dir.exists():
            dir.mkpath(confd)
        return confd

    def on_settings(self):
        self.show()

    def on_exit(self):
        QtGui.qApp.quit()

    def on_edited(self):
        self.modify = True
        self.ui.btn_apply.setEnabled(True)

    def on_apply(self):
        if self.currentProcess is None:
            QMessageBox.warning(self, '警告', '未选择有效启动项,无法完成保存!')
            return
        args = self.ui.le_args.text()
        exe = self.ui.le_exe.text()
        desc = self.ui.le_desc.text()
        isInherit = self.ui.cb_inheri.checkState() == QtCore.Qt.Checked
        self.currentProcess.setArgs(QString2str(args))
        self.currentProcess.setExe(QString2str(exe))
        self.currentProcess.setDesc(QString2str(desc))
        self.currentProcess.setIsInherit(isInherit)
        envs = {}
        for i in range(self.ui.tw_envs.rowCount()):
            key = self.ui.tw_envs.item(i, 0).text()
            value = self.ui.tw_envs.item(i, 1).text()
            envs[QString2str(key)] = QString2str(value)
        self.currentProcess.setEnvs(envs)
        self.processDict[self.currentProcess.getName()] = self.currentProcess
        configDir = self.config_dir()
        configFilePath = configDir + os.sep + self.currentProcess.getName(
        ) + '.json'
        with open(configFilePath, 'w+') as f:
            f.write(self.currentProcess.save())
        self.modify = False
        self.ui.btn_apply.setEnabled(False)
        QMessageBox.information(self, '提示', '已保存!')

    def on_add(self):
        ret = QInputDialog.getText(self, '请输入启动项目名称', '名称')
        if not ret[1]:
            return
        name = ret[0]
        if name.isEmpty():
            return
        if self.processDict.has_key(QString2str(name)):
            QMessageBox.warning(self, '警告', '该启动项已存在!')
            return
        curProcess = Process()
        curProcess.setName(QString2str(name))
        configDir = self.config_dir()
        configFilePath = configDir + os.sep + QString2str(name) + '.json'
        with open(configFilePath, 'w+') as f:
            f.write(curProcess.save())
        self.add_item(curProcess)
        self.ui.cb_process.setCurrentIndex(self.ui.cb_process.count() - 1)

    def on_delete(self):
        name = self.ui.cb_process.currentText()
        index = self.ui.cb_process.currentIndex()
        if not self.processDict.has_key(QString2str(name)):
            QMessageBox.warning(self, '警告', '请先选择要删除的配置项!')
            return
        process = self.processDict.pop(QString2str(name))
        for action in self.menu_run.actions():
            if action.text() == name:
                self.menu_run.removeAction(action)
        self.ui.cb_process.removeItem(index)
        configFilePath = self.config_dir() + os.sep + QString2str(
            name) + '.json'
        os.remove(configFilePath)

    def on_index_changed(self, index):
        if self.modify and QMessageBox.question(
                self, '提示', '启动项已修改,是否保存?',
                QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
            self.on_apply()
        name = self.ui.cb_process.itemText(index)
        self.reset()
        if self.processDict.has_key(QString2str(name)):
            process = self.processDict[QString2str(name)]
            self.currentProcess = process
            self.display(process)

    def on_env_add(self):
        self.ui.tw_envs.setRowCount(self.ui.tw_envs.rowCount() + 1)
        self.modify = True
        self.ui.btn_apply.setEnabled(True)

    def on_env_del(self):
        index = self.ui.tw_envs.currentRow()
        self.ui.tw_envs.removeRow(index)
        self.modify = True
        self.ui.btn_apply.setEnabled(True)

    def on_run(self):
        if self.modify and QMessageBox.question(
                self, '提示', '启动项已修改,是否保存?',
                QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
            self.on_apply()
        name = self.ui.cb_process.currentText()
        if self.processDict.has_key(QString2str(name)):
            process = self.processDict[QString2str(name)]
            if process.start():
                self.showMessage(u'%s启动项已执行' % process.getName())
            else:
                self.showMessage(u'%s启动项执行失败,请检查配置' % process.getName())
        else:
            QMessageBox.warning(self, '警告', '请先选择要运行的启动项!')

    def on_action_run(self):
        name = self.sender().text()
        if self.processDict.has_key(QString2str(name)):
            process = self.processDict[QString2str(name)]
            if process.start():
                self.showMessage(u'%s启动项已执行' % process.getName())
            else:
                self.showMessage(u'%s启动项执行失败,请检查配置' % process.getName())
        else:
            QMessageBox.warning(self, '警告', '请先选择要运行的启动项!')

    def on_open(self):
        filePath = QFileDialog.getOpenFileName(self, '选择程序')
        self.ui.le_exe.setText(filePath)
        self.modify = True
        self.ui.btn_apply.setEnabled(True)

    def closeEvent(self, event):
        event.ignore()
        self.hide()

    def add_item(self, process):
        self.processDict[process.getName()] = process
        self.ui.cb_process.addItem(process.getName())
        act = self.menu_run.addAction(process.getName())
        act.triggered.connect(self.on_action_run)

    def init(self):
        self.modify = False
        self.ui.btn_apply.setEnabled(False)
        self.currentProcess = None
        self.processDict = {}
        config_dir = self.config_dir()
        items = os.listdir(config_dir)
        for item in items:
            currentPath = self.config_dir() + os.sep + item
            if not os.path.isdir(currentPath) and os.path.exists(currentPath):
                with open(currentPath, 'r') as f:
                    content = f.read()
                    process = Process()
                    if process.load(content):
                        self.add_item(process)

    def reset(self):
        self.ui.le_args.setText('')
        self.ui.le_exe.setText('')
        self.ui.le_desc.setText('')
        self.ui.tw_envs.clear()
        self.ui.tw_envs.setRowCount(0)
        self.modify = False
        self.ui.btn_apply.setEnabled(False)

    def display(self, process):
        self.ui.le_args.setText(process.getArgs())
        self.ui.le_exe.setText(process.getExe())
        self.ui.le_desc.setText(process.getDesc())
        envs = process.getEnvs()
        for key in envs.keys():
            row = self.ui.tw_envs.rowCount()
            self.ui.tw_envs.setRowCount(row + 1)
            self.ui.tw_envs.setItem(row, 0, QTableWidgetItem(key))
            self.ui.tw_envs.setItem(row, 1, QTableWidgetItem(envs[key]))

    def on_autostart(self):
        if self.act_autostart.isChecked():
            self.set_autostart(True)
            self.showMessage('已设置开机启动')
        else:
            self.set_autostart(False)
            self.showMessage('已取消开机启动')

    def is_autostart(self):
        reg = QSettings(
            "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
            QSettings.NativeFormat)
        return reg.contains("launcher")

    def set_autostart(self, auto):
        path = QApplication.applicationFilePath()
        path = QDir.toNativeSeparators(path)
        reg = QSettings(
            "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
            QSettings.NativeFormat)
        if auto is True:
            reg.setValue("launcher", QVariant(QString('"%1"').arg(path)))
        else:
            reg.remove("launcher")