Exemple #1
0
    def __init__(self, parent=None):
        super().__init__(parent)
        self._delegate = None
        # ScrollPerPixel means user can draw scroll bar and move list items pixel by pixel,
        # but mouse wheel still scroll item by item (the number of items scrolled depends on
        # qApp.wheelScrollLines)
        self.setVerticalScrollMode(self.ScrollPerPixel)
        self.scrollbar = DiaryList.ScrollBar(self)
        self.scrollbar.wantSetRow.connect(self.setRow)
        self.setVerticalScrollBar(self.scrollbar)

        self.setupTheme()
        # disable default editor. Editor is implemented in the View
        self.setEditTriggers(QAbstractItemView.NoEditTriggers)

        self.originModel = DiaryModel(self)
        self.modelProxy = MultiSortFilterProxyModel(self)
        self.modelProxy.setSourceModel(self.originModel)
        self.modelProxy.setDynamicSortFilter(True)
        self.modelProxy.addFilter([db.TAGS], cs=Qt.CaseSensitive)
        self.modelProxy.addFilter([db.TITLE, db.TEXT], cs=Qt.CaseInsensitive)
        self.modelProxy.addFilter([db.DATETIME])
        self.setModel(self.modelProxy)
        self.sort()

        self.editAct = QAction(self.tr('Edit'), self)
        self.delAct = QAction(makeQIcon(':/menu/list-delete.png', scaled2x=True),
                              self.tr('Delete'), self, shortcut=QKeySequence.Delete)
        self.randAct = QAction(makeQIcon(':/menu/random-big.png', scaled2x=True),
                               self.tr('Random'), self,
                               shortcut=QKeySequence(Qt.Key_F7), triggered=self.selectRandomly)
        self.gotoAct = QAction(self.tr('Go to location'), self)
        for i in (self.editAct, self.delAct, self.randAct, self.gotoAct):
            self.addAction(i)
Exemple #2
0
    def __init__(self, parent=None):
        super().__init__(parent, objectName='searchBox')

        self.button = QToolButton(self, objectName='searchBoxBtn')
        sz = QSize(16, 16) * scaleRatio
        self.button.setFocusPolicy(Qt.NoFocus)
        self.button.setFixedSize(sz)
        self.button.setIconSize(sz)
        self.button.setCursor(Qt.ArrowCursor)
        self.button.clicked.connect(self.clear)
        clearSc = QShortcut(QKeySequence(Qt.Key_Escape), self)
        clearSc.activated.connect(self.clear)
        self.textChanged.connect(self._updateIco)
        self.retranslate()
        self.setMinimumHeight(int(self.button.height() * 1.2))
        self.setTextMargins(QMargins(2, 0, sz.width(), 0))

        self._isTextBefore = True
        self._searchIco = makeQIcon(':/search.png')
        self._clrIco = makeQIcon(':/search-clr.png')
        self._updateIco('')  # initialize the icon

        self._delay = QTimer(self)
        self._delay.setSingleShot(True)
        self._delay.setInterval(310)
        self._delay.timeout.connect(lambda: self.contentChanged.emit(self.text()))
        self.textChanged.connect(self._updateDelayTimer)
Exemple #3
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     layout = QVBoxLayout(self)
     layout.setSpacing(0)
     layout.setContentsMargins(0, 0, 0, 0)
     self.bar = QFrame(self, objectName='heatMapBar')
     barLayout = QHBoxLayout(self.bar)
     barLayout.setContentsMargins(0, 0, 0, 0)
     barLayout.setSpacing(3)
     # setup buttons and menu
     self.view = HeatMapView(self,
                             font=self.font(),
                             objectName='heatMapView')
     self.yearBtn = QPushButton(str(self.view.year),
                                self,
                                objectName='heatMapBtn')
     self.yearBtn.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
     self.yearBtn.setFocusPolicy(Qt.TabFocus)
     self.yearBtn.setFont(self.font())
     self.yearBtn.clicked.connect(self.yearBtnAct)
     self.yearMenu = QMenu(self, objectName='heatMapMenu')
     self._yearActGroup = QActionGroup(self.yearMenu)
     self.setupYearMenu()
     sz = QSize(16, 16) * scaleRatio
     ico = makeQIcon(':/heatmap/arrow-left.png')
     preBtn = QToolButton(self, icon=ico, clicked=self.yearPre, iconSize=sz)
     ico = makeQIcon(':/heatmap/arrow-right.png')
     nextBtn = QToolButton(self,
                           icon=ico,
                           clicked=self.yearNext,
                           iconSize=sz)
     # setup color sample
     self.sample = ColorSampleView(self, cellLen=11)
     # always bigger than sizeHint even policy is Maximum, so painful. use fixed
     self.sample.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
     self.sample.setFixedSize(
         preBtn.sizeHint().width() * 2 + barLayout.spacing(),
         preBtn.sizeHint().height())
     barLayout.addWidget(preBtn, Qt.AlignVCenter)
     barLayout.addWidget(nextBtn, Qt.AlignVCenter)
     barLayout.addSpacerItem(
         QSpacerItem(30, 1, QSizePolicy.Expanding, QSizePolicy.Fixed))
     barLayout.addWidget(self.yearBtn)
     barLayout.addSpacerItem(
         QSpacerItem(30, 1, QSizePolicy.Expanding, QSizePolicy.Fixed))
     barLayout.addWidget(self.sample)
     barLayout.addSpacerItem(
         QSpacerItem(3, 1, QSizePolicy.Fixed, QSizePolicy.Fixed))
     layout.addWidget(self.bar)
     layout.addWidget(self.view)
     # setup shortcuts
     self.preSc = QShortcut(QKeySequence(Qt.Key_Left), self, self.yearPre)
     self.nextSc = QShortcut(QKeySequence(Qt.Key_Right), self,
                             self.yearNext)
     self.pre5Sc = QShortcut(QKeySequence(Qt.Key_Up), self, self.yearPre5)
     self.next5Sc = QShortcut(QKeySequence(Qt.Key_Down), self,
                              self.yearNext5)
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._doc = NTextDocument(self)
        self.setDocument(self._doc)
        # remove highlight color's alpha to avoid alpha loss in copy&paste.
        # NTextDocument should use this color too.
        hl, bg = self.HlColor, self.palette().base().color()
        fac = hl.alpha() / 255
        self.HlColor = QColor(round(hl.red()*fac + bg.red()*(1-fac)),
                              round(hl.green()*fac + bg.green()*(1-fac)),
                              round(hl.blue()*fac + bg.blue()*(1-fac)))

        self.autoIndent = False
        # used by tab indent shortcut
        if QLocale().language() in (QLocale.Chinese, QLocale.Japanese):
            self._indent = '  '   # 2 full width spaces
        else:
            self._indent = '    '  # 4 spaces
        # setup format menu
        onHLAct = lambda: super(NTextEdit, self).setHL(self.hlAct.isChecked())
        onBDAct = lambda: super(NTextEdit, self).setBD(self.bdAct.isChecked())
        onSOAct = lambda: super(NTextEdit, self).setSO(self.soAct.isChecked())
        onULAct = lambda: super(NTextEdit, self).setUL(self.ulAct.isChecked())
        onItaAct = lambda: super(NTextEdit, self).setIta(self.itaAct.isChecked())

        self.fmtMenu = QMenu(self.tr('Format'), self)
        # shortcuts of format actions only used to display shortcut-hint in menu
        self.hlAct = QAction(makeQIcon(':/menu/highlight.png'), self.tr('Highlight'),
                             self, triggered=onHLAct,
                             shortcut=QKeySequence('Ctrl+H'))
        self.bdAct = QAction(makeQIcon(':/menu/bold.png'), self.tr('Bold'),
                             self, triggered=onBDAct,
                             shortcut=QKeySequence.Bold)
        self.soAct = QAction(makeQIcon(':/menu/strikeout.png'), self.tr('Strike out'),
                             self, triggered=onSOAct,
                             shortcut=QKeySequence('Ctrl+T'))
        self.ulAct = QAction(makeQIcon(':/menu/underline.png'), self.tr('Underline'),
                             self, triggered=onULAct,
                             shortcut=QKeySequence.Underline)
        self.itaAct = QAction(makeQIcon(':/menu/italic.png'), self.tr('Italic'),
                              self, triggered=onItaAct,
                              shortcut=QKeySequence.Italic)
        self.clrAct = QAction(self.tr('Clear format'), self,
                              shortcut=QKeySequence('Ctrl+D'),
                              triggered=self.clearFormat)
        self.acts = (self.hlAct, self.bdAct, self.soAct, self.ulAct,
                     self.itaAct)  # excluding uncheckable clrAct
        for a in self.acts:
            self.fmtMenu.addAction(a)
            a.setCheckable(True)
        self.fmtMenu.addSeparator()
        self.addAction(self.clrAct)
        self.fmtMenu.addAction(self.clrAct)
        self.key2act = {
            Qt.Key_H: self.hlAct, Qt.Key_B: self.bdAct, Qt.Key_T: self.soAct,
            Qt.Key_U: self.ulAct, Qt.Key_I: self.itaAct}
Exemple #5
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     layout = QVBoxLayout(self)
     layout.setSpacing(0)
     layout.setContentsMargins(0, 0, 0, 0)
     self.bar = QFrame(self, objectName='heatMapBar')
     barLayout = QHBoxLayout(self.bar)
     barLayout.setContentsMargins(0, 0, scaleRatio, 0)
     barLayout.setSpacing(3)
     # setup buttons and menu
     self.view = HeatMapView(self,
                             font=self.font(),
                             objectName='heatMapView')
     self.yearBtn = QPushButton(str(self.view.year),
                                self,
                                objectName='heatMapBtn')
     self.yearBtn.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
     self.yearBtn.setFocusPolicy(Qt.TabFocus)
     self.yearBtn.setFont(self.font())
     self.yearBtn.clicked.connect(self.yearBtnAct)
     self.yearMenu = QMenu(self, objectName='heatMapMenu')
     self._yearActGroup = QActionGroup(self.yearMenu)
     self.setupYearMenu()
     sz = QSize(16, 16) * scaleRatio
     ico = makeQIcon(':/heatmap/arrow-left.png', scaled2x=True)
     preBtn = QToolButton(self, icon=ico, clicked=self.yearPre, iconSize=sz)
     ico = makeQIcon(':/heatmap/arrow-right.png', scaled2x=True)
     nextBtn = QToolButton(self,
                           icon=ico,
                           clicked=self.yearNext,
                           iconSize=sz)
     # setup color sample
     self.sample = ColorSampleView(self, cellLen=11)
     # without following size will be bigger than fixed, why?
     self.sample.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
     self.sample.setFixedSize(200, 14 * scaleRatio)
     barLayout.addWidget(preBtn)
     barLayout.addWidget(nextBtn)
     barLayout.addSpacing(200 - preBtn.sizeHint().width() * 2 -
                          barLayout.spacing())
     barLayout.addStretch()
     barLayout.addWidget(self.yearBtn)
     barLayout.addStretch()
     barLayout.addWidget(self.sample)
     layout.addWidget(self.bar)
     layout.addWidget(self.view)
     # setup shortcuts
     self.preSc = QShortcut(QKeySequence(Qt.Key_Left), self, self.yearPre)
     self.nextSc = QShortcut(QKeySequence(Qt.Key_Right), self,
                             self.yearNext)
     self.pre5Sc = QShortcut(QKeySequence(Qt.Key_Up), self, self.yearPre5)
     self.next5Sc = QShortcut(QKeySequence(Qt.Key_Down), self,
                              self.yearNext5)
Exemple #6
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     layout = QVBoxLayout(self)
     layout.setSpacing(0)
     layout.setContentsMargins(0, 0, 0, 0)
     self.bar = QFrame(self, objectName='heatMapBar')
     barLayout = QHBoxLayout(self.bar)
     barLayout.setContentsMargins(0, 0, scaleRatio, 0)
     barLayout.setSpacing(3)
     # setup buttons and menu
     self.view = HeatMapView(self, font=self.font(), objectName='heatMapView')
     self.yearBtn = QPushButton(str(self.view.year), self,
                                objectName='heatMapBtn')
     self.yearBtn.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
     self.yearBtn.setFocusPolicy(Qt.TabFocus)
     self.yearBtn.setFont(self.font())
     self.yearBtn.clicked.connect(self.yearBtnAct)
     self.yearMenu = QMenu(self, objectName='heatMapMenu')
     self._yearActGroup = QActionGroup(self.yearMenu)
     self.setupYearMenu()
     sz = QSize(16, 16) * scaleRatio
     ico = makeQIcon(':/heatmap/arrow-left.png', scaled2x=True)
     preBtn = QToolButton(self, icon=ico, clicked=self.yearPre, iconSize=sz)
     ico = makeQIcon(':/heatmap/arrow-right.png', scaled2x=True)
     nextBtn = QToolButton(self, icon=ico, clicked=self.yearNext, iconSize=sz)
     # setup color sample
     self.sample = ColorSampleView(self, cellLen=11)
     # without following size will be bigger than fixed, why?
     self.sample.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
     self.sample.setFixedSize(200, 14*scaleRatio)
     barLayout.addWidget(preBtn)
     barLayout.addWidget(nextBtn)
     barLayout.addSpacing(200 - preBtn.sizeHint().width()*2 - barLayout.spacing())
     barLayout.addStretch()
     barLayout.addWidget(self.yearBtn)
     barLayout.addStretch()
     barLayout.addWidget(self.sample)
     layout.addWidget(self.bar)
     layout.addWidget(self.view)
     # setup shortcuts
     self.preSc = QShortcut(QKeySequence(Qt.Key_Left), self, self.yearPre)
     self.nextSc = QShortcut(QKeySequence(Qt.Key_Right), self, self.yearNext)
     self.pre5Sc = QShortcut(QKeySequence(Qt.Key_Up), self, self.yearPre5)
     self.next5Sc = QShortcut(QKeySequence(Qt.Key_Down), self, self.yearNext5)
Exemple #7
0
    def __init__(self, parent=None):
        super().__init__(parent)
        self._delegate = None
        # ScrollPerPixel means user can draw scroll bar and move list items pixel by pixel,
        # but mouse wheel still scroll item by item (the number of items scrolled depends on
        # qApp.wheelScrollLines)
        self.setVerticalScrollMode(self.ScrollPerPixel)
        self.scrollbar = DiaryListScrollBar(self)
        self.scrollbar.wantSetRow.connect(self.setRow)
        self.setVerticalScrollBar(self.scrollbar)

        # disable default editor. Editor is implemented in the View
        self.setEditTriggers(QAbstractItemView.NoEditTriggers)

        self.originModel = DiaryModel(self)
        self.modelProxy = MultiSortFilterProxyModel(self)
        self.modelProxy.setSourceModel(self.originModel)
        self.modelProxy.setDynamicSortFilter(True)
        self.modelProxy.addFilter([db.TAGS], cs=Qt.CaseSensitive)
        self.modelProxy.addFilter([db.TITLE, db.TEXT], cs=Qt.CaseInsensitive)
        self.modelProxy.addFilter([db.DATETIME])
        self.setModel(self.modelProxy)
        self.sort()

        self.setupTheme()

        self.editAct = QAction(self.tr('Edit'), self)
        self.delAct = QAction(makeQIcon(':/menu/list-delete.png',
                                        scaled2x=True),
                              self.tr('Delete'),
                              self,
                              shortcut=QKeySequence.Delete)
        self.randAct = QAction(makeQIcon(':/menu/random-big.png',
                                         scaled2x=True),
                               self.tr('Random'),
                               self,
                               shortcut=QKeySequence(Qt.Key_F7),
                               triggered=self.selectRandomly)
        self.gotoAct = QAction(self.tr('Go to location'), self)
        for i in (self.editAct, self.delAct, self.randAct, self.gotoAct):
            self.addAction(i)
Exemple #8
0
    def __init__(self, parent=None):
        super().__init__(parent, objectName='searchBox')
        self._searchByTip = None

        self.btn = QPushButton(self, objectName='searchBoxBtn')
        sz = QSize(16, 16) * scaleRatio
        self.btn.setFocusPolicy(Qt.NoFocus)
        self.btn.setFixedSize(sz)
        self.btn.setIconSize(sz)
        self.btn.setCursor(Qt.PointingHandCursor)
        self.btn.clicked.connect(self.onBtnClicked)

        self._byMenu = menu = QMenu(self)
        group = QActionGroup(menu)
        self.byTitleTextAct = QAction(self.tr('Title && Text'), group)
        self.byDatetimeAct = QAction(self.tr('Date (YYYY-MM-DD)'), group)
        for i in (self.byTitleTextAct, self.byDatetimeAct):
            i.setCheckable(True)
            menu.addAction(i)
        self.byTitleTextAct.setChecked(True)

        clearSc = QShortcut(QKeySequence(Qt.Key_Escape), self)
        clearSc.activated.connect(self.clear)
        self.textChanged.connect(self.onTextChanged)
        self.retranslate()
        self.setMinimumHeight(int(self.btn.height() * 1.2))
        self.setTextMargins(QMargins(2, 0, sz.width(), 0))

        self._hasText = True
        self._searchIco = makeQIcon(':/search.png', scaled2x=True)
        self._clrIco = makeQIcon(':/search-clr.png', scaled2x=True)
        self.onTextChanged('')  # initialize the icon

        self._delayed = QTimer(self)
        self._delayed.setSingleShot(True)
        self._delayed.setInterval(310)
        self._delayed.timeout.connect(
            lambda: self.contentChanged.emit(self.text()))
        self.textChanged.connect(self._updateDelayedTimer)
Exemple #9
0
    def __init__(self, parent):
        super().__init__(parent, Qt.WindowTitleHint)
        self._checkUpdateTask = self._installUpdateTask = None
        self._dlProgressBlocks = None
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setupUi(self)
        fixWidgetSizeOnHiDpi(self)

        # about browser
        self.aboutBrowser.anchorClicked.connect(self._NavigateAboutArea)
        self.aboutBrowser.document().setDocumentMargin(0)
        self.aboutBrowser.document().setDefaultStyleSheet(aboutBrowserCss)
        if updater.foundUpdate:
            self._NavigateAboutArea(QUrl('hzm://show-update'))
        elif updater.checkUpdateTask:
            # signal losing is impossible? because of GIL
            task = self._checkUpdateTask = updater.checkUpdateTask
            task.succeeded.connect(self._onCheckUpdateSucceeded)
            task.failed.connect(self._aboutAreaError)
            self._NavigateAboutArea(QUrl('hzm://show-info/' + self.tr('checking...')))
        else:
            self._NavigateAboutArea(QUrl('hzm://show-info'))

        if scaleRatio > 1:
            self.openOutBtn.setIcon(makeQIcon(':/check.png', scaled2x=True))
        self.openOutBtn.hide()  # can't set initial state in creator
        self.appIcoBtn.setIcon(qApp.windowIcon())
        self.appIcoBtn.setIconSize(QSize(32, 32) * scaleRatio)
        self.appIcoBtn.setStyleSheet('border: none')
        self.appIcoBtn.clicked.connect(self._easterEgg)

        self.updateCheck.setChecked(settings['Update'].getboolean('autoCheck'))
        self.aindCheck.setChecked(settings['Editor'].getboolean('autoIndent'))
        self.tabIndentCheck.setChecked(settings['Editor'].getboolean('tabIndent'))
        self.autoRoCheck.setChecked(settings['Editor'].getboolean('autoReadOnly'))
        self.tListCountCheck.setChecked(settings['Main'].getboolean('tagListCount'))
        self.annotateCheck.setChecked(settings['Main'].getboolean('listAnnotated'))
        if settings['Editor'].getboolean('titleFocus'):
            self.focusTitleRadio.setChecked(True)
        else:
            self.focusTextRadio.setChecked(True)
        self.bkCheck.setChecked(settings['Main'].getboolean('backup'))
        self.extendBgCheck.setChecked(settings['Main'].getboolean('extendTitleBarBg'))
        if isWin and not isDwmUsable():
            self.extendBgCheck.setEnabled(False)
        # language ComboBox
        for i in TRANS_DISPLAY_NAMES:
            self.langCombo.addItem(i)
        langIndex = TRANSLATIONS.index(settings['Main']['lang'])
        self.langCombo.setCurrentIndex(langIndex)

        self.rstCombo.model().item(0).setSelectable(False)
        self.rstCombo.addItems(diarybook.list_backups())
        self.themeCombo.addItems(THEMES)
        self.themeCombo.setCurrentIndex(THEMES.index(settings['Main']['theme']))
        self.preLinesBox.setValue(settings['Main'].getint('previewLines'))
        # theme specific
        if settings['Main']['theme'] == '1px-rect':
            self._disableThemeSpe()
        else:
            self._enableThemeSpe()
        self.themeCombo.currentIndexChanged.connect(
            lambda idx: self._enableThemeSpe() if idx != 0 else self._disableThemeSpe())
        # fonts
        self.enRenderCheck.setChecked(settings['Font'].getboolean('enhanceRender'))
        self.enRenderCheck.setVisible(isWin)
        self.enRenderCheck.setEnabled(mactype.isUsable())
        self.defFontGBox.setChecked('default' in settings['Font'])
        self.fontBtns = (self.dtFontBtn, self.titleFontBtn, self.textFontBtn,
                         self.defFontBtn)
        fontBtnConfigNames = ('datetime', 'title', 'text', 'default')
        fontDialogPreview = 'AaBbYy@2017 %s' % self.langCombo.currentText()

        for b, n in zip(self.fontBtns, fontBtnConfigNames):
            b.configName = n
            b.resettable = n != 'default'
            b.PreviewText = fontDialogPreview  # change class var may cause segfault!
            font_ = getattr(font, n)
            b.setFont(font_, font_.userSet)  # userSet is set by Font in __init__
            if scaleRatio > 1:
                b.setMinimumWidth((b.minimumWidth() * scaleRatio))
        # setup statistics
        diaryCount = len(db)
        if diaryCount < 2:
            diaryDtRange = None
        elif settings['Main']['listSortBy'] == 'datetime' and parent:
            # only save 10 milliseconds (600 diaries)
            m = parent.diaryList.model()
            diaryDtRange = m.data(m.index(0, 1)), m.data(m.index(m.rowCount()-1, 1))
            if settings['Main'].getboolean('listReverse'):
                diaryDtRange = diaryDtRange[::-1]
        else:
            diaryDtRange = db.get_datetime_range()
        if diaryDtRange:
            qRange = tuple(map(lambda x: QDateTime.fromString(x, DB_DATETIME_FMT_QT),
                               diaryDtRange))
            days = qRange[0].daysTo(qRange[1])
        else:
            days = 0
        if days > 0:
            freq = round(1 / (diaryCount / days), 1)
            oldest, newest = map(lambda x: x[:7], diaryDtRange)
            self.staLabel.setText(self.tr('Every <b>%s</b> days a diary, from <b>%s</b> to <b>%s</b>') %
                                  (freq, oldest, newest))
        else:
            self.staLabel.setText(self.tr('N/A'))
Exemple #10
0
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.cfgDialog = self.heatMap = self.ssEditor = None  # create on action triggered
        self.editors = OrderedDict(
        )  # diaryId => Editor, id of new diary is -1

        restoreWidgetGeo(self, settings['Main'].get('windowGeo'))
        # setup toolbar bg properties; the second stage is in showEvent
        self.setToolbarProperty()
        self.toolBar.setIconSize(QSize(24, 24) * scaleRatio)

        self.diaryList.editAct.triggered.connect(self.startEditor)
        self.diaryList.gotoAct.triggered.connect(self.onGotoActTriggered)
        self.diaryList.delAct.triggered.connect(self.deleteDiary)

        # setup TagList
        self._tagListAni = QPropertyAnimation(self, 'tagListWidth')
        self._tagListAni.setEasingCurve(QEasingCurve(QEasingCurve.OutCubic))
        self._tagListAni.setDuration(150)
        self._tagListAni.finished.connect(self.onTagListAniFinished)

        # setup sort menu
        menu = QMenu(self)
        group = QActionGroup(menu)
        datetime = QAction(self.tr('Date'), group)
        datetime.name = 'datetime'
        title = QAction(self.tr('Title'), group)
        title.name = 'title'
        length = QAction(self.tr('Length'), group)
        length.name = 'length'
        ascDescGroup = QActionGroup(menu)
        asc = QAction(self.tr('Ascending'), ascDescGroup)
        asc.name = 'asc'
        desc = QAction(self.tr('Descending'), ascDescGroup)
        desc.name = 'desc'
        for i in [datetime, title, length, None, asc, desc]:
            if i is None:
                menu.addSeparator()
                continue
            i.setCheckable(True)
            menu.addAction(i)
            i.triggered[bool].connect(self.onSortOrderChanged)
        # restore from settings
        order = settings['Main']['listSortBy']
        locals()[order].setChecked(True)
        if settings['Main'].getboolean('listReverse'):
            desc.setChecked(True)
        else:
            asc.setChecked(True)
        self.sorAct.setMenu(menu)
        self.toolBar.widgetForAction(self.sorAct).setPopupMode(
            QToolButton.InstantPopup)

        # setup count label
        # Qt Designer doesn't allow us to add widget in toolbar
        p = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)
        p.setHorizontalStretch(8)
        spacer1 = QWidget(self.toolBar)
        spacer1.setSizePolicy(p)
        self.toolBar.addWidget(spacer1)
        countLabel = self.countLabel = QLabel(self.toolBar,
                                              objectName='countLabel')
        countLabel.setSizePolicy(
            QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum))
        countLabel.setMargin(4 * scaleRatio)
        self.toolBar.addWidget(countLabel)

        # setup search box
        box = self.searchBox = SearchBox(self)
        p = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
        p.setHorizontalStretch(5)
        box.setSizePolicy(p)
        box.setMinimumHeight(22 * scaleRatio)
        box.setMinimumWidth(box.minimumHeight() * 7.5)
        box.byTitleTextAct.triggered.connect(self._setSearchBy)
        box.byDatetimeAct.triggered.connect(self._setSearchBy)
        self._setSearchBy()
        self.toolBar.addWidget(box)
        spacer2 = QWidget(self.toolBar)
        spacer2.setFixedSize(2.5 * scaleRatio, 1)
        self.toolBar.addWidget(spacer2)
        if settings['Main'].getboolean('tagListVisible'):
            self.tListAct.setChecked(True)  # will not trigger signal
            if self.isMaximized():
                # Qt will maximize the window after showing... why?
                QTimer.singleShot(
                    0, lambda: self.toggleTagList(True, animated=False))
            else:
                self.toggleTagList(True, animated=False)
        else:
            self.tagList.hide()  # don't use toggleTagList, it will save width
        # setup shortcuts
        searchSc = QShortcut(QKeySequence.Find, self)
        searchSc.activated.connect(self.searchBox.setFocus)

        # setup bigger toolbar icons
        if scaleRatio > 1.0:
            for act, fname in [(self.cfgAct, 'config'), (self.creAct, 'new'),
                               (self.delAct, 'delete'),
                               (self.mapAct, 'heatmap'), (self.sorAct, 'sort'),
                               (self.tListAct, 'tag-list')]:
                act.setIcon(makeQIcon(':/toolbar/%s.png' % fname))

        # setup auto update check
        if updater.isCheckNeeded():
            task = updater.CheckUpdate()
            QTimer.singleShot(1200, task.start)
            task.succeeded.connect(
                self.setUpdateHint)  # use lambda here will cause segfault!

        # delay list loading until main event loop start
        QTimer.singleShot(0, self.diaryList.load)