File indexing completed on 2024-04-28 15:30:59

0001 /*
0002     SPDX-FileCopyrightText: 2013 Dominik Haumann <dhaumann@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "katestatusbar.h"
0008 
0009 #include "kateabstractinputmode.h"
0010 #include "kateconfig.h"
0011 #include "katedocument.h"
0012 #include "kateglobal.h"
0013 #include "katemodemanager.h"
0014 #include "katemodemenulist.h"
0015 #include "kateview.h"
0016 #include "wordcounter.h"
0017 
0018 #include <KAcceleratorManager>
0019 #include <KActionCollection>
0020 #include <KIconUtils>
0021 #include <Sonnet/Speller>
0022 
0023 #include <QActionGroup>
0024 #include <QHBoxLayout>
0025 #include <QInputDialog>
0026 #include <QStylePainter>
0027 
0028 // BEGIN menu
0029 KateStatusBarOpenUpMenu::KateStatusBarOpenUpMenu(QWidget *parent)
0030     : QMenu(parent)
0031 {
0032 }
0033 
0034 void KateStatusBarOpenUpMenu::setVisible(bool visibility)
0035 {
0036     if (visibility) {
0037         QRect geo = geometry();
0038         QPoint pos = parentWidget()->mapToGlobal(QPoint(0, 0));
0039         geo.moveTopLeft(QPoint(pos.x(), pos.y() - geo.height()));
0040         if (geo.top() < 0) {
0041             geo.moveTop(0);
0042         }
0043         setGeometry(geo);
0044     }
0045 
0046     QMenu::setVisible(visibility);
0047 }
0048 // END menu
0049 
0050 // BEGIN StatusBarButton
0051 StatusBarButton::StatusBarButton(KateStatusBar *parent, const QString &text /*= QString()*/)
0052     : QPushButton(text, parent)
0053 {
0054     setFlat(true);
0055     setFocusProxy(parent->m_view);
0056     setMinimumSize(QSize(1, minimumSizeHint().height()));
0057 }
0058 
0059 void StatusBarButton::paintEvent(QPaintEvent *)
0060 {
0061     QStylePainter p(this);
0062     QStyleOptionButton opt;
0063     initStyleOption(&opt);
0064     opt.features &= (~QStyleOptionButton::HasMenu);
0065     p.drawControl(QStyle::CE_PushButton, opt);
0066 }
0067 
0068 QSize StatusBarButton::sizeHint() const
0069 {
0070     return minimumSizeHint();
0071 }
0072 
0073 QSize StatusBarButton::minimumSizeHint() const
0074 {
0075     const auto fm = QFontMetrics(font());
0076     const int h = fm.lineSpacing();
0077     QSize size = QPushButton::sizeHint();
0078     const int vMmargin = style()->pixelMetric(QStyle::PM_FocusFrameVMargin) * 2;
0079     size.setHeight(h + vMmargin);
0080 
0081     const int w = fm.horizontalAdvance(text());
0082     const int bm = style()->pixelMetric(QStyle::PM_ButtonMargin) * 2;
0083     const int hMargin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin) * 2;
0084     size.setWidth(w + bm + hMargin);
0085 
0086     return size;
0087 }
0088 
0089 // END StatusBarButton
0090 
0091 KateStatusBar::KateStatusBar(KTextEditor::ViewPrivate *view)
0092     : KateViewBarWidget(false)
0093     , m_view(view)
0094     , m_selectionMode(-1)
0095     , m_wordCounter(nullptr)
0096 {
0097     KAcceleratorManager::setNoAccel(this);
0098     setFocusProxy(m_view);
0099 
0100     // just add our status bar to central widget, full sized
0101     QHBoxLayout *topLayout = new QHBoxLayout(centralWidget());
0102     topLayout->setContentsMargins(0, 0, 0, 0);
0103     topLayout->setSpacing(0);
0104 
0105     // ensure all elements of the status bar are right aligned
0106     // for Kate this is nice, as on the left side are the tool view buttons
0107     // for KWrite this makes it more consistent with Kate
0108     topLayout->addStretch(1);
0109 
0110     // show Line XXX, Column XXX
0111     m_cursorPosition = new StatusBarButton(this);
0112     topLayout->addWidget(m_cursorPosition);
0113     m_cursorPosition->setWhatsThis(i18n("Current cursor position. Click to go to a specific line."));
0114     connect(m_cursorPosition, &StatusBarButton::clicked, m_view, &KTextEditor::ViewPrivate::gotoLine);
0115 
0116     // show the zoom level of the text
0117     m_zoomLevel = new StatusBarButton(this);
0118     topLayout->addWidget(m_zoomLevel);
0119     connect(m_zoomLevel, &StatusBarButton::clicked, [=] {
0120         m_view->renderer()->resetFontSizes();
0121     });
0122 
0123     // show the current mode, like INSERT, OVERWRITE, VI + modifiers like [BLOCK]
0124     m_inputMode = new StatusBarButton(this);
0125     topLayout->addWidget(m_inputMode);
0126     m_inputMode->setWhatsThis(i18n("Insert mode and VI input mode indicator. Click to change the mode."));
0127     connect(m_inputMode, &StatusBarButton::clicked, [=] {
0128         m_view->currentInputMode()->toggleInsert();
0129     });
0130 
0131     // Add dictionary button which allows user to switch dictionary of the document
0132     m_dictionary = new StatusBarButton(this);
0133     topLayout->addWidget(m_dictionary, 0);
0134     m_dictionary->setWhatsThis(i18n("Change dictionary"));
0135     m_dictionaryMenu = new KateStatusBarOpenUpMenu(m_dictionary);
0136     m_dictionaryMenu->addAction(m_view->action("tools_change_dictionary"));
0137     m_dictionaryMenu->addAction(m_view->action("tools_clear_dictionary_ranges"));
0138     m_dictionaryMenu->addAction(m_view->action("tools_toggle_automatic_spell_checking"));
0139     m_dictionaryMenu->addAction(m_view->action("tools_spelling_from_cursor"));
0140     m_dictionaryMenu->addAction(m_view->action("tools_spelling"));
0141     m_dictionaryMenu->addSeparator();
0142     m_dictionaryGroup = new QActionGroup(m_dictionaryMenu);
0143     QMapIterator<QString, QString> i(Sonnet::Speller().preferredDictionaries());
0144     while (i.hasNext()) {
0145         i.next();
0146         QAction *action = m_dictionaryGroup->addAction(i.key());
0147         action->setData(i.value());
0148         action->setToolTip(i.key());
0149         action->setCheckable(true);
0150         m_dictionaryMenu->addAction(action);
0151     }
0152     m_dictionary->setMenu(m_dictionaryMenu);
0153     connect(m_dictionaryGroup, &QActionGroup::triggered, this, &KateStatusBar::changeDictionary);
0154 
0155     // allow to change indentation configuration
0156     m_tabsIndent = new StatusBarButton(this);
0157     topLayout->addWidget(m_tabsIndent);
0158 
0159     m_indentSettingsMenu = new KateStatusBarOpenUpMenu(m_tabsIndent);
0160     m_indentSettingsMenu->addSection(i18n("Tab Width"));
0161     m_tabGroup = new QActionGroup(this);
0162     addNumberAction(m_tabGroup, m_indentSettingsMenu, -1);
0163     addNumberAction(m_tabGroup, m_indentSettingsMenu, 8);
0164     addNumberAction(m_tabGroup, m_indentSettingsMenu, 4);
0165     addNumberAction(m_tabGroup, m_indentSettingsMenu, 2);
0166     connect(m_tabGroup, &QActionGroup::triggered, this, &KateStatusBar::slotTabGroup);
0167 
0168     m_indentSettingsMenu->addSection(i18n("Indentation Width"));
0169     m_indentGroup = new QActionGroup(this);
0170     addNumberAction(m_indentGroup, m_indentSettingsMenu, -1);
0171     addNumberAction(m_indentGroup, m_indentSettingsMenu, 8);
0172     addNumberAction(m_indentGroup, m_indentSettingsMenu, 4);
0173     addNumberAction(m_indentGroup, m_indentSettingsMenu, 2);
0174     connect(m_indentGroup, &QActionGroup::triggered, this, &KateStatusBar::slotIndentGroup);
0175 
0176     m_indentSettingsMenu->addSection(i18n("Indentation Mode"));
0177     QActionGroup *radioGroup = new QActionGroup(m_indentSettingsMenu);
0178     m_mixedAction = m_indentSettingsMenu->addAction(i18n("Tabulators && Spaces"));
0179     m_mixedAction->setCheckable(true);
0180     m_mixedAction->setActionGroup(radioGroup);
0181     m_hardAction = m_indentSettingsMenu->addAction(i18n("Tabulators"));
0182     m_hardAction->setCheckable(true);
0183     m_hardAction->setActionGroup(radioGroup);
0184     m_softAction = m_indentSettingsMenu->addAction(i18n("Spaces"));
0185     m_softAction->setCheckable(true);
0186     m_softAction->setActionGroup(radioGroup);
0187     connect(radioGroup, &QActionGroup::triggered, this, &KateStatusBar::slotIndentTabMode);
0188 
0189     m_tabsIndent->setMenu(m_indentSettingsMenu);
0190 
0191     // add encoding button which allows user to switch encoding of document
0192     // this will reuse the encoding action menu of the view
0193     m_encoding = new StatusBarButton(this);
0194     topLayout->addWidget(m_encoding);
0195     m_encoding->setMenu(m_view->encodingAction()->menu());
0196     m_encoding->setWhatsThis(i18n("Encoding"));
0197 
0198     m_eol = new StatusBarButton(this);
0199     m_eol->setWhatsThis(i18n("End of line type"));
0200     m_eol->setToolTip(i18n("End of line type"));
0201     m_eol->setMenu(m_view->getEolMenu());
0202     topLayout->addWidget(m_eol);
0203 
0204     // load the mode menu, which contains a scrollable list + search bar.
0205     // This is an alternative menu to the mode action menu of the view.
0206     m_modeMenuList = new KateModeMenuList(i18n("Mode"), this);
0207     m_modeMenuList->setWhatsThis(i18n(
0208         "Here you can choose which mode should be used for the current document. This will influence the highlighting and folding being used, for example."));
0209     m_modeMenuList->updateMenu(m_view->doc());
0210     // add mode button which allows user to switch mode of document
0211     m_mode = new StatusBarButton(this);
0212     topLayout->addWidget(m_mode);
0213     m_modeMenuList->setButton(m_mode, KateModeMenuList::AlignHInverse, KateModeMenuList::AlignTop, KateModeMenuList::AutoUpdateTextButton(false));
0214     m_mode->setMenu(m_modeMenuList);
0215     m_mode->setWhatsThis(i18n("Syntax highlighting"));
0216 
0217     // signals for the statusbar
0218     connect(m_view, &KTextEditor::View::cursorPositionChanged, this, &KateStatusBar::cursorPositionChanged);
0219     connect(m_view, &KTextEditor::View::viewModeChanged, this, &KateStatusBar::viewModeChanged);
0220     connect(m_view, &KTextEditor::View::selectionChanged, this, &KateStatusBar::selectionChanged);
0221     connect(m_view->doc(), &KTextEditor::Document::configChanged, this, &KateStatusBar::documentConfigChanged);
0222     connect(m_view->document(), &KTextEditor::DocumentPrivate::modeChanged, this, &KateStatusBar::modeChanged);
0223     connect(m_view, &KTextEditor::View::configChanged, this, &KateStatusBar::configChanged);
0224     connect(m_view->doc(), &KTextEditor::DocumentPrivate::defaultDictionaryChanged, this, &KateStatusBar::updateDictionary);
0225     connect(m_view->doc(), &KTextEditor::DocumentPrivate::dictionaryRangesPresent, this, &KateStatusBar::updateDictionary);
0226     connect(m_view, &KTextEditor::ViewPrivate::caretChangedRange, this, &KateStatusBar::updateDictionary);
0227 
0228     updateStatus();
0229     toggleWordCount(KateViewConfig::global()->showWordCount());
0230 }
0231 
0232 bool KateStatusBar::eventFilter(QObject *obj, QEvent *event)
0233 {
0234     return KateViewBarWidget::eventFilter(obj, event);
0235 }
0236 
0237 void KateStatusBar::contextMenuEvent(QContextMenuEvent *event)
0238 {
0239     // TODO Add option "Show Statusbar" and options to show/hide buttons of the status bar
0240     QMenu menu(this);
0241 
0242     if (childAt(event->pos()) == m_inputMode) {
0243         if (QAction *inputModesAction = m_view->actionCollection()->action(QStringLiteral("view_input_modes"))) {
0244             if (QMenu *inputModesMenu = inputModesAction->menu()) {
0245                 const auto actions = inputModesMenu->actions();
0246                 for (int i = 0; i < actions.count(); ++i) {
0247                     menu.addAction(actions.at(i));
0248                 }
0249                 menu.addSeparator();
0250             }
0251         }
0252     }
0253 
0254     QAction *showLines = menu.addAction(i18n("Show line count"), this, &KateStatusBar::toggleShowLines);
0255     showLines->setCheckable(true);
0256     showLines->setChecked(KateViewConfig::global()->showLineCount());
0257     QAction *showWords = menu.addAction(i18n("Show word count"), this, &KateStatusBar::toggleShowWords);
0258     showWords->setCheckable(true);
0259     showWords->setChecked(KateViewConfig::global()->showWordCount());
0260     auto a = menu.addAction(i18n("Line/Column compact mode"), this, [](bool checked) {
0261         KateViewConfig::global()->setValue(KateViewConfig::StatusbarLineColumnCompact, checked);
0262     });
0263     a->setCheckable(true);
0264     a->setChecked(KateViewConfig::global()->value(KateViewConfig::StatusbarLineColumnCompact).toBool());
0265     menu.exec(event->globalPos());
0266 }
0267 
0268 void KateStatusBar::toggleShowLines(bool checked)
0269 {
0270     KateViewConfig::global()->setValue(KateViewConfig::ShowLineCount, checked);
0271 }
0272 
0273 void KateStatusBar::toggleShowWords(bool checked)
0274 {
0275     KateViewConfig::global()->setShowWordCount(checked);
0276 }
0277 
0278 void KateStatusBar::updateStatus()
0279 {
0280     selectionChanged();
0281     viewModeChanged();
0282     cursorPositionChanged();
0283     documentConfigChanged();
0284     modeChanged();
0285     updateDictionary();
0286     updateEOL();
0287 }
0288 
0289 void KateStatusBar::selectionChanged()
0290 {
0291     const unsigned int newSelectionMode = m_view->blockSelection();
0292     if (newSelectionMode == m_selectionMode) {
0293         return;
0294     }
0295 
0296     // remember new mode and update info
0297     m_selectionMode = newSelectionMode;
0298     viewModeChanged();
0299 }
0300 
0301 void KateStatusBar::viewModeChanged()
0302 {
0303     // prepend BLOCK for block selection mode
0304     QString text = m_view->viewModeHuman();
0305     if (m_view->blockSelection()) {
0306         text = i18n("[BLOCK] %1", text);
0307     }
0308 
0309     m_inputMode->setText(text);
0310 }
0311 
0312 void KateStatusBar::cursorPositionChanged()
0313 {
0314     KTextEditor::Cursor position(m_view->cursorPositionVirtual());
0315     const int l = position.line() + 1;
0316     const int c = position.column() + 1;
0317 
0318     // Update line/column label
0319     QString text;
0320     if (KateViewConfig::global()->value(KateViewConfig::StatusbarLineColumnCompact).toBool()) {
0321         if (KateViewConfig::global()->showLineCount()) {
0322             text = i18n("%1/%2:%3", QLocale().toString(l), QLocale().toString(m_view->doc()->lines()), QLocale().toString(c));
0323         } else {
0324             text = i18n("%1:%2", QLocale().toString(l), QLocale().toString(c));
0325         }
0326     } else {
0327         if (KateViewConfig::global()->showLineCount()) {
0328             text = i18n("Line %1 of %2, Column %3", QLocale().toString(l), QLocale().toString(m_view->doc()->lines()), QLocale().toString(c));
0329         } else {
0330             text = i18n("Line %1, Column %2", QLocale().toString(l), QLocale().toString(c));
0331         }
0332     }
0333     if (m_wordCounter) {
0334         text.append(QLatin1String(", ") + m_wordCount);
0335     }
0336     m_cursorPosition->setText(text);
0337 }
0338 
0339 void KateStatusBar::updateDictionary()
0340 {
0341     const auto spellchecker = Sonnet::Speller();
0342     const auto availableDictionaries = spellchecker.availableDictionaries();
0343     // No dictionaries available? => hide
0344     if (availableDictionaries.isEmpty()) {
0345         m_dictionary->hide();
0346         return;
0347     }
0348 
0349     QString newDict;
0350     // Check if at the current cursor position is a special dictionary in use
0351     KTextEditor::Cursor position(m_view->cursorPositionVirtual());
0352     const QList<QPair<KTextEditor::MovingRange *, QString>> dictRanges = m_view->doc()->dictionaryRanges();
0353     for (const auto &rangeDictPair : dictRanges) {
0354         const KTextEditor::MovingRange *range = rangeDictPair.first;
0355         if (range->contains(position) || range->end() == position) {
0356             newDict = rangeDictPair.second;
0357             break;
0358         }
0359     }
0360     // Check if the default dictionary is in use
0361     if (newDict.isEmpty()) {
0362         newDict = m_view->doc()->defaultDictionary();
0363         if (newDict.isEmpty()) {
0364             newDict = spellchecker.defaultLanguage();
0365         }
0366     }
0367     // Update button and menu only on a changed dictionary
0368     if (!m_dictionaryGroup->checkedAction() || (m_dictionaryGroup->checkedAction()->data().toString() != newDict) || m_dictionary->text().isEmpty()) {
0369         bool found = false;
0370         // Remove "-w_accents -variant_0" and such from dict-code to keep it small and clean
0371         m_dictionary->setText(newDict.section(QLatin1Char('-'), 0, 0));
0372         // For maximum user clearness, change the checked menu option
0373         m_dictionaryGroup->blockSignals(true);
0374         const auto acts = m_dictionaryGroup->actions();
0375         for (auto a : acts) {
0376             if (a->data().toString() == newDict) {
0377                 a->setChecked(true);
0378                 found = true;
0379                 break;
0380             }
0381         }
0382         if (!found) {
0383             // User has chose some other dictionary from combo box, we need to add that
0384             QString dictName = availableDictionaries.key(newDict);
0385             if (!dictName.isEmpty()) {
0386                 QAction *action = m_dictionaryGroup->addAction(dictName);
0387                 action->setData(newDict);
0388                 action->setCheckable(true);
0389                 action->setChecked(true);
0390                 m_dictionaryMenu->addAction(action);
0391             }
0392         }
0393         m_dictionaryGroup->blockSignals(false);
0394     }
0395 }
0396 
0397 void KateStatusBar::documentConfigChanged()
0398 {
0399     m_encoding->setText(m_view->document()->encoding());
0400     KateDocumentConfig *config = ((KTextEditor::DocumentPrivate *)m_view->document())->config();
0401     int tabWidth = config->tabWidth();
0402     int indentationWidth = config->indentationWidth();
0403     bool replaceTabsDyn = config->replaceTabsDyn();
0404 
0405     static const KLocalizedString spacesOnly = ki18n("Soft Tabs: %1");
0406     static const KLocalizedString spacesOnlyShowTabs = ki18n("Soft Tabs: %1 (%2)");
0407     static const KLocalizedString tabsOnly = ki18n("Tab Size: %1");
0408     static const KLocalizedString tabSpacesMixed = ki18n("Indent/Tab: %1/%2");
0409 
0410     if (!replaceTabsDyn) {
0411         if (tabWidth == indentationWidth) {
0412             m_tabsIndent->setText(tabsOnly.subs(tabWidth).toString());
0413             m_tabGroup->setEnabled(false);
0414             m_hardAction->setChecked(true);
0415         } else {
0416             m_tabsIndent->setText(tabSpacesMixed.subs(indentationWidth).subs(tabWidth).toString());
0417             m_tabGroup->setEnabled(true);
0418             m_mixedAction->setChecked(true);
0419         }
0420     } else {
0421         if (tabWidth == indentationWidth) {
0422             m_tabsIndent->setText(spacesOnly.subs(indentationWidth).toString());
0423             m_tabGroup->setEnabled(true);
0424             m_softAction->setChecked(true);
0425         } else {
0426             m_tabsIndent->setText(spacesOnlyShowTabs.subs(indentationWidth).subs(tabWidth).toString());
0427             m_tabGroup->setEnabled(true);
0428             m_softAction->setChecked(true);
0429         }
0430     }
0431 
0432     updateGroup(m_tabGroup, tabWidth);
0433     updateGroup(m_indentGroup, indentationWidth);
0434     updateEOL();
0435 }
0436 
0437 void KateStatusBar::modeChanged()
0438 {
0439     m_mode->setText(KTextEditor::EditorPrivate::self()->modeManager()->fileType(m_view->document()->mode()).nameTranslated());
0440 }
0441 
0442 void KateStatusBar::addNumberAction(QActionGroup *group, QMenu *menu, int data)
0443 {
0444     QAction *a;
0445     if (data != -1) {
0446         a = menu->addAction(QStringLiteral("%1").arg(data));
0447     } else {
0448         a = menu->addAction(i18n("Other..."));
0449     }
0450     a->setData(data);
0451     a->setCheckable(true);
0452     a->setActionGroup(group);
0453 }
0454 
0455 void KateStatusBar::updateGroup(QActionGroup *group, int w)
0456 {
0457     QAction *m1 = nullptr;
0458     bool found = false;
0459     // linear search should be fast enough here, no additional hash
0460     const auto acts = group->actions();
0461     for (QAction *action : acts) {
0462         int val = action->data().toInt();
0463         if (val == -1) {
0464             m1 = action;
0465         }
0466         if (val == w) {
0467             found = true;
0468             action->setChecked(true);
0469         }
0470     }
0471 
0472     if (m1) {
0473         if (found) {
0474             m1->setText(i18n("Other..."));
0475         } else {
0476             m1->setText(i18np("Other (%1)", "Other (%1)", w));
0477             m1->setChecked(true);
0478         }
0479     }
0480 }
0481 
0482 void KateStatusBar::slotTabGroup(QAction *a)
0483 {
0484     int val = a->data().toInt();
0485     bool ok;
0486     KateDocumentConfig *config = ((KTextEditor::DocumentPrivate *)m_view->document())->config();
0487     if (val == -1) {
0488         val = QInputDialog::getInt(this, i18n("Tab Width"), i18n("Please specify the wanted tab width:"), config->tabWidth(), 1, 200, 1, &ok);
0489         if (!ok) {
0490             val = config->tabWidth();
0491         }
0492     }
0493     config->setTabWidth(val);
0494 }
0495 
0496 void KateStatusBar::slotIndentGroup(QAction *a)
0497 {
0498     int val = a->data().toInt();
0499     bool ok;
0500     KateDocumentConfig *config = ((KTextEditor::DocumentPrivate *)m_view->document())->config();
0501     if (val == -1) {
0502         val = QInputDialog::getInt(this,
0503                                    i18n("Indentation Width"),
0504                                    i18n("Please specify the wanted indentation width:"),
0505                                    config->indentationWidth(),
0506                                    1,
0507                                    200,
0508                                    1,
0509                                    &ok);
0510         if (!ok) {
0511             val = config->indentationWidth();
0512         }
0513     }
0514     config->configStart();
0515     config->setIndentationWidth(val);
0516     if (m_hardAction->isChecked()) {
0517         config->setTabWidth(val);
0518     }
0519     config->configEnd();
0520 }
0521 
0522 void KateStatusBar::slotIndentTabMode(QAction *a)
0523 {
0524     KateDocumentConfig *config = ((KTextEditor::DocumentPrivate *)m_view->document())->config();
0525     if (a == m_softAction) {
0526         config->setReplaceTabsDyn(true);
0527     } else if (a == m_mixedAction) {
0528         if (config->replaceTabsDyn()) {
0529             config->setReplaceTabsDyn(false);
0530         }
0531         m_tabGroup->setEnabled(true);
0532     } else if (a == m_hardAction) {
0533         if (config->replaceTabsDyn()) {
0534             config->configStart();
0535             config->setReplaceTabsDyn(false);
0536             config->setTabWidth(config->indentationWidth());
0537             config->configEnd();
0538         } else {
0539             config->setTabWidth(config->indentationWidth());
0540         }
0541         m_tabGroup->setEnabled(false);
0542     }
0543 }
0544 
0545 void KateStatusBar::toggleWordCount(bool on)
0546 {
0547     if ((m_wordCounter != nullptr) == on) {
0548         return;
0549     }
0550 
0551     if (on) {
0552         m_wordCounter = new WordCounter(m_view);
0553         connect(m_wordCounter, &WordCounter::changed, this, &KateStatusBar::wordCountChanged);
0554     } else {
0555         delete m_wordCounter;
0556         m_wordCounter = nullptr;
0557     }
0558 
0559     wordCountChanged(0, 0, 0, 0);
0560 }
0561 
0562 void KateStatusBar::wordCountChanged(int wordsInDocument, int wordsInSelection, int charsInDocument, int charsInSelection)
0563 {
0564     if (m_wordCounter) {
0565         if (charsInSelection > 0) {
0566             m_wordCount = i18nc("%1 and %3 are the selected words/chars count, %2 and %4 are the total words/chars count.",
0567                                 "Words %1/%2, Chars %3/%4",
0568                                 wordsInSelection,
0569                                 wordsInDocument,
0570                                 charsInSelection,
0571                                 charsInDocument);
0572         } else {
0573             m_wordCount = i18nc("%1 and %2 are the total words/chars count.", "Words %1, Chars %2", wordsInDocument, charsInDocument);
0574         }
0575     } else {
0576         m_wordCount.clear();
0577     }
0578 
0579     cursorPositionChanged();
0580 }
0581 
0582 void KateStatusBar::configChanged()
0583 {
0584     toggleWordCount(m_view->config()->showWordCount());
0585     const int zoom = m_view->renderer()->config()->baseFont().pointSizeF() / KateRendererConfig::global()->baseFont().pointSizeF() * 100;
0586     if (zoom != 100) {
0587         m_zoomLevel->setVisible(true);
0588         m_zoomLevel->setText(i18n("Zoom: %1%", zoom));
0589     } else {
0590         m_zoomLevel->hide();
0591     }
0592 
0593     auto cfg = KateViewConfig::global();
0594     auto updateButtonVisibility = [cfg](StatusBarButton *b, KateViewConfig::ConfigEntryTypes c) {
0595         bool v = cfg->value(c).toBool();
0596         if (v != (!b->isHidden())) {
0597             b->setVisible(v);
0598         }
0599     };
0600     updateButtonVisibility(m_inputMode, KateViewConfig::ShowStatusbarInputMode);
0601     updateButtonVisibility(m_mode, KateViewConfig::ShowStatusbarHighlightingMode);
0602     updateButtonVisibility(m_cursorPosition, KateViewConfig::ShowStatusbarLineColumn);
0603     updateButtonVisibility(m_tabsIndent, KateViewConfig::ShowStatusbarTabSettings);
0604     updateButtonVisibility(m_encoding, KateViewConfig::ShowStatusbarFileEncoding);
0605     updateButtonVisibility(m_eol, KateViewConfig::ShowStatusbarEOL);
0606 
0607     bool v = cfg->value(KateViewConfig::ShowStatusbarDictionary).toBool();
0608     if (v != (!m_dictionary->isHidden()) && !Sonnet::Speller().availableDictionaries().isEmpty()) {
0609         updateButtonVisibility(m_dictionary, KateViewConfig::ShowStatusbarDictionary);
0610     }
0611 }
0612 
0613 void KateStatusBar::changeDictionary(QAction *action)
0614 {
0615     const QString dictionary = action->data().toString();
0616     m_dictionary->setText(dictionary);
0617     // Code stolen from KateDictionaryBar::dictionaryChanged
0618     KTextEditor::Range selection = m_view->selectionRange();
0619     if (selection.isValid() && !selection.isEmpty()) {
0620         m_view->doc()->setDictionary(dictionary, selection);
0621     } else {
0622         m_view->doc()->setDefaultDictionary(dictionary);
0623     }
0624 }
0625 
0626 void KateStatusBar::updateEOL()
0627 {
0628     const int eol = m_view->getEol();
0629     QString text;
0630     switch (eol) {
0631     case KateDocumentConfig::eolUnix:
0632         text = QStringLiteral("LF");
0633         break;
0634     case KateDocumentConfig::eolDos:
0635         text = QStringLiteral("CRLF");
0636         break;
0637     case KateDocumentConfig::eolMac:
0638         text = QStringLiteral("CR");
0639         break;
0640     }
0641     if (text != m_eol->text()) {
0642         m_eol->setText(text);
0643     }
0644 }
0645 
0646 KateModeMenuList *KateStatusBar::modeMenu() const
0647 {
0648     return m_modeMenuList;
0649 }
0650 
0651 #include "moc_katestatusbar.cpp"