diff --git a/src/view/katestatusbar.h b/src/view/katestatusbar.h --- a/src/view/katestatusbar.h +++ b/src/view/katestatusbar.h @@ -42,9 +42,23 @@ void setVisible(bool) override; }; +/** + * For convenience an own button class to ensure a unified look&feel. + * Should someone dislike the QPushButton at all could he change it + * to a e.g. QLabel subclass + */ +class StatusBarButton: public QPushButton +{ + Q_OBJECT +public: + explicit StatusBarButton(KateStatusBar *parent, const QString &text = QString()); + ~StatusBarButton() override; +}; + class KateStatusBar : public KateViewBarWidget { Q_OBJECT + friend class StatusBarButton; public: explicit KateStatusBar(KTextEditor::ViewPrivate *view); @@ -76,17 +90,13 @@ private: KTextEditor::ViewPrivate *const m_view; - QLabel *m_lineColLabel; - QLabel *m_wordCountLabel; - QToolButton *m_modifiedLabel; - QLabel *m_insertModeLabel; - QPushButton *m_mode; - QPushButton *m_encoding; - QPushButton *m_tabsIndent; - KLocalizedString m_spacesOnly; - KLocalizedString m_tabsOnly; - KLocalizedString m_tabSpacesMixed; - KLocalizedString m_spacesOnlyShowTabs; + StatusBarButton *m_cursorPosition = nullptr; + QString m_wordCount; + StatusBarButton *m_modified = nullptr; + StatusBarButton *m_inputMode = nullptr; + StatusBarButton *m_mode = nullptr; + StatusBarButton *m_encoding = nullptr; + StatusBarButton *m_tabsIndent = nullptr; QMenu *m_indentSettingsMenu; unsigned int m_modifiedStatus; unsigned int m_selectionMode; diff --git a/src/view/katestatusbar.cpp b/src/view/katestatusbar.cpp --- a/src/view/katestatusbar.cpp +++ b/src/view/katestatusbar.cpp @@ -43,7 +43,7 @@ { if (visibility) { QRect geo = geometry(); - QPoint pos = ((QPushButton *)parent())->mapToGlobal(QPoint(0, 0)); + QPoint pos = parentWidget()->mapToGlobal(QPoint(0, 0)); geo.moveTopLeft(QPoint(pos.x(), pos.y() - geo.height())); if (geo.top() < 0) geo.moveTop(0); setGeometry(geo); @@ -53,10 +53,23 @@ } //END menu +//BEGIN StatusBarButton +StatusBarButton::StatusBarButton(KateStatusBar *parent, const QString &text /*= QString()*/) + : QPushButton(text, parent) +{ + setFlat(true); + setFocusProxy(parent->m_view); + setMinimumSize(QSize(1, minimumSizeHint().height())); +} + +StatusBarButton::~StatusBarButton() +{ +} +//END StatusBarButton + KateStatusBar::KateStatusBar(KTextEditor::ViewPrivate *view) : KateViewBarWidget(false) , m_view(view) - , m_insertModeLabel(nullptr) , m_modifiedStatus(-1) , m_selectionMode(-1) , m_wordCounter(nullptr) @@ -72,166 +85,121 @@ topLayout->setSpacing(4); /** - * add a bit space + * show modification state of the document + * TODO Using a (StatusBar)Button is currently pointless but handy due to no "setIcon()" function in QLabel. + * Add some useful action when button is clicked, e.g. save document or show tool-tip + * or find a way to not show a "focus frame" when hovered by mouse */ - topLayout->addSpacing(4); + m_modified = new StatusBarButton(this); + topLayout->addWidget(m_modified); /** * show Line XXX, Column XXX */ - m_lineColLabel = new QLabel(this); - m_lineColLabel->installEventFilter(this); // register for doubleclick - topLayout->addWidget(m_lineColLabel, 0); - m_lineColLabel->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); - m_lineColLabel->setFocusProxy(m_view); - m_lineColLabel->setWhatsThis(i18n("Current cursor position. Doubleclick to go to specific line.")); + m_cursorPosition = new StatusBarButton(this); + topLayout->addWidget(m_cursorPosition); + m_cursorPosition->setWhatsThis(i18n("Current cursor position. Click to go to a specific line.")); + connect(m_cursorPosition, &StatusBarButton::clicked, m_view, &KTextEditor::ViewPrivate::gotoLine); - /** - * show word count - */ - m_wordCountLabel = new QLabel(this); - topLayout->addWidget(m_wordCountLabel, 0); - m_wordCountLabel->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); - m_wordCountLabel->setFocusProxy(m_view); - m_wordCountLabel->setWhatsThis(i18n("Words and Chars count in document/selection.")); - m_wordCountLabel->hide(); + // Separate the status line in a left and right part + topLayout->addStretch(1); /** * show the current mode, like INSERT, OVERWRITE, VI + modifiers like [BLOCK] */ - m_insertModeLabel = new QLabel(this); - m_insertModeLabel->installEventFilter(this); // register for doubleclick - topLayout->addWidget(m_insertModeLabel, 1000 /* this one should stretch */); - m_insertModeLabel->setAlignment(Qt::AlignVCenter | Qt::AlignRight); - m_insertModeLabel->setFocusProxy(m_view); - m_insertModeLabel->setWhatsThis(i18n("Insert mode and VI input mode indicator")); + m_inputMode = new StatusBarButton(this); + topLayout->addWidget(m_inputMode); + m_inputMode->setWhatsThis(i18n("Insert mode and VI input mode indicator. Click to change the mode.")); + connect(m_inputMode, &StatusBarButton::clicked, [=] { m_view->currentInputMode()->toggleInsert(); }); /** * allow to change indentation configuration */ - m_spacesOnly = ki18n("Soft Tabs: %1"); - m_spacesOnlyShowTabs = ki18n("Soft Tabs: %1 (%2)"); - m_tabsOnly = ki18n("Tab Size: %1"); - m_tabSpacesMixed = ki18n("Indent/Tab: %1/%2"); - - QAction *action; - m_tabGroup = new QActionGroup(this); - m_indentGroup = new QActionGroup(this); - m_tabsIndent = new QPushButton(QString(), this); - m_tabsIndent->setFlat(true); - topLayout->addWidget(m_tabsIndent, 0); - m_tabsIndent->setFocusProxy(m_view); + m_tabsIndent = new StatusBarButton(this); + topLayout->addWidget(m_tabsIndent); m_indentSettingsMenu = new KateStatusBarOpenUpMenu(m_tabsIndent); m_indentSettingsMenu->addSection(i18n("Tab Width")); + m_tabGroup = new QActionGroup(this); addNumberAction(m_tabGroup, m_indentSettingsMenu, -1); addNumberAction(m_tabGroup, m_indentSettingsMenu, 8); addNumberAction(m_tabGroup, m_indentSettingsMenu, 4); addNumberAction(m_tabGroup, m_indentSettingsMenu, 2); + connect(m_tabGroup, &QActionGroup::triggered, this, &KateStatusBar::slotTabGroup); + m_indentSettingsMenu->addSection(i18n("Indentation Width")); + m_indentGroup = new QActionGroup(this); addNumberAction(m_indentGroup, m_indentSettingsMenu, -1); addNumberAction(m_indentGroup, m_indentSettingsMenu, 8); addNumberAction(m_indentGroup, m_indentSettingsMenu, 4); addNumberAction(m_indentGroup, m_indentSettingsMenu, 2); + connect(m_indentGroup, &QActionGroup::triggered, this, &KateStatusBar::slotIndentGroup); m_indentSettingsMenu->addSection(i18n("Indentation Mode")); QActionGroup *radioGroup = new QActionGroup(m_indentSettingsMenu); - action = m_indentSettingsMenu->addAction(i18n("Tabulators && Spaces")); - action->setCheckable(true); - action->setActionGroup(radioGroup); - m_mixedAction = action; - action = m_indentSettingsMenu->addAction(i18n("Tabulators")); - action->setCheckable(true); - action->setActionGroup(radioGroup); - m_hardAction = action; - action = m_indentSettingsMenu->addAction(i18n("Spaces")); - action->setCheckable(true); - action->setActionGroup(radioGroup); - m_softAction = action; + m_mixedAction = m_indentSettingsMenu->addAction(i18n("Tabulators && Spaces")); + m_mixedAction->setCheckable(true); + m_mixedAction->setActionGroup(radioGroup); + m_hardAction = m_indentSettingsMenu->addAction(i18n("Tabulators")); + m_hardAction->setCheckable(true); + m_hardAction->setActionGroup(radioGroup); + m_softAction = m_indentSettingsMenu->addAction(i18n("Spaces")); + m_softAction->setCheckable(true); + m_softAction->setActionGroup(radioGroup); + connect(radioGroup, &QActionGroup::triggered, this, &KateStatusBar::slotIndentTabMode); m_tabsIndent->setMenu(m_indentSettingsMenu); /** * add encoding button which allows user to switch encoding of document * this will reuse the encoding action menu of the view */ - m_encoding = new QPushButton(QString(), this); - m_encoding->setFlat(true); - topLayout->addWidget(m_encoding, 0); + m_encoding = new StatusBarButton(this); + topLayout->addWidget(m_encoding); m_encoding->setMenu(m_view->encodingAction()->menu()); - m_encoding->setFocusProxy(m_view); m_encoding->setWhatsThis(i18n("Encoding")); /** * add mode button which allows user to switch mode of document * this will reuse the mode action menu of the view */ - m_mode = new QPushButton(QString(), this); - m_mode->setFlat(true); - topLayout->addWidget(m_mode, 0); + m_mode = new StatusBarButton(this); + topLayout->addWidget(m_mode); m_mode->setMenu(m_view->modeAction()->menu()); - m_mode->setFocusProxy(m_view); m_mode->setWhatsThis(i18n("Syntax highlighting")); - /** - * show modification state of the document - */ - m_modifiedLabel = new QToolButton(this); - m_modifiedLabel->setAutoRaise(true); - m_modifiedLabel->setEnabled(false); - topLayout->addWidget(m_modifiedLabel, 0); - m_modifiedLabel->setFocusProxy(m_view); - - /** - * add a bit space - */ - topLayout->addSpacing(4); - // signals for the statusbar - connect(m_view, SIGNAL(cursorPositionChanged(KTextEditor::View*, KTextEditor::Cursor)), this, SLOT(cursorPositionChanged())); - connect(m_view, SIGNAL(viewModeChanged(KTextEditor::View*, KTextEditor::View::ViewMode)), this, SLOT(viewModeChanged())); - connect(m_view, SIGNAL(selectionChanged(KTextEditor::View*)), this, SLOT(selectionChanged())); - connect(m_view->document(), SIGNAL(modifiedChanged(KTextEditor::Document*)), this, SLOT(modifiedChanged())); - connect(m_view->document(), SIGNAL(modifiedOnDisk(KTextEditor::Document*, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)), this, SLOT(modifiedChanged())); - connect(m_view->document(), SIGNAL(configChanged()), this, SLOT(documentConfigChanged())); - connect(m_view->document(), SIGNAL(modeChanged(KTextEditor::Document*)), this, SLOT(modeChanged())); + connect(m_view, &KTextEditor::View::cursorPositionChanged, this, &KateStatusBar::cursorPositionChanged); + connect(m_view, &KTextEditor::View::viewModeChanged, this, &KateStatusBar::viewModeChanged); + connect(m_view, &KTextEditor::View::selectionChanged, this, &KateStatusBar::selectionChanged); + connect(m_view->document(), &KTextEditor::DocumentPrivate::modifiedChanged, this, &KateStatusBar::modifiedChanged); + connect(m_view->doc(), &KTextEditor::DocumentPrivate::modifiedOnDisk, this, &KateStatusBar::modifiedChanged); + connect(m_view->doc(), &KTextEditor::DocumentPrivate::configChanged, this, &KateStatusBar::documentConfigChanged); + connect(m_view->document(), &KTextEditor::DocumentPrivate::modeChanged, this, &KateStatusBar::modeChanged); connect(m_view, &KTextEditor::ViewPrivate::configChanged, this, &KateStatusBar::configChanged); - connect(m_tabGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotTabGroup(QAction*))); - connect(m_indentGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotIndentGroup(QAction*))); - connect(radioGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotIndentTabMode(QAction*))); updateStatus(); - wordCountChanged(0, 0, 0, 0); + toggleWordCount(KateViewConfig::global()->showWordCount()); } bool KateStatusBar::eventFilter(QObject *obj, QEvent *event) { - if (obj == m_insertModeLabel) { - if (event->type() == QEvent::MouseButtonDblClick) { - m_view->currentInputMode()->toggleInsert(); - return true; - } - } else if (obj == m_lineColLabel) { - if (event->type() == QEvent::MouseButtonDblClick) { - m_view->gotoLine(); - return true; - } - } - return KateViewBarWidget::eventFilter(obj, event); } void KateStatusBar::contextMenuEvent(QContextMenuEvent *event) { + // TODO Add option "Show Statusbar" and options to show/hide buttons of the status bar QMenu menu(this); QAction *showLines = menu.addAction(QStringLiteral("Show line count"), this, &KateStatusBar::toggleShowLines); showLines->setCheckable(true); showLines->setChecked(KateViewConfig::global()->showLineCount()); QAction *showWords = menu.addAction(QStringLiteral("Show word count"), this, &KateStatusBar::toggleShowWords); showWords->setCheckable(true); showWords->setChecked(KateViewConfig::global()->showWordCount()); menu.exec(event->globalPos()); + } void KateStatusBar::toggleShowLines(bool checked) @@ -271,31 +239,33 @@ // prepend BLOCK for block selection mode QString text = m_view->viewModeHuman(); if (m_view->blockSelection()) - text = i18n("[BLOCK] %1", text); + text = i18n("[BLOCK] %1", text); - m_insertModeLabel->setText(text); + m_inputMode->setText(text); } void KateStatusBar::cursorPositionChanged() { KTextEditor::Cursor position(m_view->cursorPositionVirtual()); - if (KateViewConfig::global()->showLineCount()) - m_lineColLabel->setText( - i18n("Line %1 of %2, Column %3" - , QLocale().toString(position.line() + 1) - , QLocale().toString(m_view->doc()->lines()) - , QLocale().toString(position.column() + 1) - ) - ); - - else - m_lineColLabel->setText( - i18n("Line %1, Column %2" - , QLocale().toString(position.line() + 1) - , QLocale().toString(position.column() + 1) - ) - ); + QString text; + + if (KateViewConfig::global()->showLineCount()) { + text = i18n("Line %1 of %2, Column %3", QLocale().toString(position.line() + 1) + , QLocale().toString(m_view->doc()->lines()) + , QLocale().toString(position.column() + 1) + ); + } else { + text = i18n("Line %1, Column %2", QLocale().toString(position.line() + 1) + , QLocale().toString(position.column() + 1) + ); + } + + if (m_wordCounter) { + text.append(QStringLiteral(", ") + m_wordCount); + } + + m_cursorPosition->setText(text); } void KateStatusBar::modifiedChanged() @@ -313,24 +283,24 @@ m_modifiedStatus = newStatus; switch (m_modifiedStatus) { case 0x1: - m_modifiedLabel->setIcon(QIcon::fromTheme(QStringLiteral("document-save"))); - m_modifiedLabel->setWhatsThis(i18n("Meaning of current icon: Document was modified since it was loaded")); + m_modified->setIcon(QIcon::fromTheme(QStringLiteral("document-save"))); + m_modified->setWhatsThis(i18n("Meaning of current icon: Document was modified since it was loaded")); break; case 0x2: - m_modifiedLabel->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); - m_modifiedLabel->setWhatsThis(i18n("Meaning of current icon: Document was modified or deleted by another program")); + m_modified->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); + m_modified->setWhatsThis(i18n("Meaning of current icon: Document was modified or deleted by another program")); break; case 0x3: - m_modifiedLabel->setIcon(QIcon(KIconUtils::addOverlay(QIcon::fromTheme(QStringLiteral("document-save")), + m_modified->setIcon(QIcon(KIconUtils::addOverlay(QIcon::fromTheme(QStringLiteral("document-save")), QIcon(QStringLiteral("emblem-important")), Qt::TopLeftCorner))); - m_modifiedLabel->setWhatsThis(QString()); + m_modified->setWhatsThis(QString()); break; default: - m_modifiedLabel->setIcon(QIcon::fromTheme(QStringLiteral("text-plain"))); - m_modifiedLabel->setWhatsThis(i18n("Meaning of current icon: Document was not modified since it was loaded")); + m_modified->setIcon(QIcon::fromTheme(QStringLiteral("text-plain"))); + m_modified->setWhatsThis(i18n("Meaning of current icon: Document was not modified since it was loaded")); break; } } @@ -343,23 +313,28 @@ int indentationWidth = config->indentationWidth(); bool replaceTabsDyn = config->replaceTabsDyn(); + static const KLocalizedString spacesOnly = ki18n("Soft Tabs: %1"); + static const KLocalizedString spacesOnlyShowTabs = ki18n("Soft Tabs: %1 (%2)"); + static const KLocalizedString tabsOnly = ki18n("Tab Size: %1"); + static const KLocalizedString tabSpacesMixed = ki18n("Indent/Tab: %1/%2"); + if (!replaceTabsDyn) { if (tabWidth == indentationWidth) { - m_tabsIndent->setText(m_tabsOnly.subs(tabWidth).toString()); + m_tabsIndent->setText(tabsOnly.subs(tabWidth).toString()); m_tabGroup->setEnabled(false); m_hardAction->setChecked(true); } else { - m_tabsIndent->setText(m_tabSpacesMixed.subs(indentationWidth).subs(tabWidth).toString()); + m_tabsIndent->setText(tabSpacesMixed.subs(indentationWidth).subs(tabWidth).toString()); m_tabGroup->setEnabled(true); m_mixedAction->setChecked(true); } } else { if (tabWidth == indentationWidth) { - m_tabsIndent->setText(m_spacesOnly.subs(indentationWidth).toString()); + m_tabsIndent->setText(spacesOnly.subs(indentationWidth).toString()); m_tabGroup->setEnabled(true); m_softAction->setChecked(true); } else { - m_tabsIndent->setText(m_spacesOnlyShowTabs.subs(indentationWidth).subs(tabWidth).toString()); + m_tabsIndent->setText(spacesOnlyShowTabs.subs(indentationWidth).subs(tabWidth).toString()); m_tabGroup->setEnabled(true); m_softAction->setChecked(true); } @@ -392,7 +367,7 @@ QAction *m1 = nullptr; bool found = false; //linear search should be fast enough here, no additional hash - Q_FOREACH (QAction *action, group->actions()) { + for (QAction *action : group->actions()) { int val = action->data().toInt(); if (val == -1) m1 = action; if (val == w) { @@ -469,17 +444,20 @@ } else { delete m_wordCounter; m_wordCounter = nullptr; - wordCountChanged(0, 0, 0, 0); } - m_wordCountLabel->setVisible(on); + wordCountChanged(0, 0, 0, 0); } void KateStatusBar::wordCountChanged(int wordsInDocument, int wordsInSelection, int charsInDocument, int charsInSelection) { - m_wordCountLabel->setText(i18n("Words %1/%2, Chars %3/%4", - wordsInDocument, wordsInSelection, - charsInDocument, charsInSelection)); + if (m_wordCounter) { + m_wordCount = i18n("Words %1/%2, Chars %3/%4", wordsInDocument, wordsInSelection, charsInDocument, charsInSelection); + } else { + m_wordCount.clear(); + } + + cursorPositionChanged(); } void KateStatusBar::configChanged()