7#include "katestatusbar.h"
9#include "kateabstractinputmode.h"
10#include "kateconfig.h"
11#include "katedocument.h"
12#include "kateglobal.h"
13#include "katemodemanager.h"
14#include "katemodemenulist.h"
15#include "katerenderer.h"
17#include "wordcounter.h"
19#include <KAcceleratorManager>
20#include <KActionCollection>
22#include <Sonnet/Speller>
24#include <QActionGroup>
26#include <QInputDialog>
27#include <QStylePainter>
30KateStatusBarOpenUpMenu::KateStatusBarOpenUpMenu(
QWidget *parent)
35void KateStatusBarOpenUpMenu::setVisible(
bool visibility)
40 geo.moveTopLeft(QPoint(
pos.x(),
pos.y() -
geo.height()));
52StatusBarButton::StatusBarButton(KateStatusBar *parent,
const QString &text )
56 setFocusProxy(parent->m_view);
57 setMinimumSize(
QSize(1, minimumSizeHint().height()));
62 QStylePainter p(
this);
63 QStyleOptionButton opt;
65 opt.features &= (~QStyleOptionButton::HasMenu);
69QSize StatusBarButton::sizeHint()
const
71 return minimumSizeHint();
74QSize StatusBarButton::minimumSizeHint()
const
76 const auto fm = QFontMetrics(
font());
77 const int h = fm.lineSpacing();
80 size.setHeight(h + vMmargin);
82 const int w = fm.horizontalAdvance(
text());
85 size.setWidth(w + bm + hMargin);
92KateStatusBar::KateStatusBar(KTextEditor::ViewPrivate *view)
93 : KateViewBarWidget(false)
96 , m_wordCounter(nullptr)
99 setFocusProxy(m_view);
114 m_cursorPosition->setWhatsThis(
i18n(
"Current cursor position. Click to go to a specific line."));
121 m_view->renderer()->resetFontSizes();
127 m_inputMode->setWhatsThis(
i18n(
"Insert mode and VI input mode indicator. Click to change the mode."));
129 m_view->currentInputMode()->toggleInsert();
135 m_dictionary->setWhatsThis(
i18n(
"Change dictionary"));
136 m_dictionaryMenu =
new KateStatusBarOpenUpMenu(m_dictionary);
137 m_dictionaryMenu->addAction(m_view->action(QStringLiteral(
"tools_change_dictionary")));
138 m_dictionaryMenu->addAction(m_view->action(QStringLiteral(
"tools_clear_dictionary_ranges")));
139 m_dictionaryMenu->addAction(m_view->action(QStringLiteral(
"tools_toggle_automatic_spell_checking")));
140 m_dictionaryMenu->addAction(m_view->action(QStringLiteral(
"tools_spelling_from_cursor")));
141 m_dictionaryMenu->addAction(m_view->action(QStringLiteral(
"tools_spelling")));
142 m_dictionaryMenu->addSeparator();
145 while (i.hasNext()) {
147 QAction *action = m_dictionaryGroup->addAction(i.key());
151 m_dictionaryMenu->addAction(action);
153 m_dictionary->setMenu(m_dictionaryMenu);
154 connect(m_dictionaryGroup, &QActionGroup::triggered,
this, &KateStatusBar::changeDictionary);
160 m_indentSettingsMenu =
new KateStatusBarOpenUpMenu(m_tabsIndent);
161 m_indentSettingsMenu->addSection(
i18n(
"Tab Width"));
163 addNumberAction(m_tabGroup, m_indentSettingsMenu, -1);
164 addNumberAction(m_tabGroup, m_indentSettingsMenu, 8);
165 addNumberAction(m_tabGroup, m_indentSettingsMenu, 4);
166 addNumberAction(m_tabGroup, m_indentSettingsMenu, 2);
167 connect(m_tabGroup, &QActionGroup::triggered,
this, &KateStatusBar::slotTabGroup);
169 m_indentSettingsMenu->addSection(
i18n(
"Indentation Width"));
171 addNumberAction(m_indentGroup, m_indentSettingsMenu, -1);
172 addNumberAction(m_indentGroup, m_indentSettingsMenu, 8);
173 addNumberAction(m_indentGroup, m_indentSettingsMenu, 4);
174 addNumberAction(m_indentGroup, m_indentSettingsMenu, 2);
175 connect(m_indentGroup, &QActionGroup::triggered,
this, &KateStatusBar::slotIndentGroup);
177 m_indentSettingsMenu->addSection(
i18n(
"Indentation Mode"));
179 m_mixedAction = m_indentSettingsMenu->addAction(
i18n(
"Tabulators && Spaces"));
180 m_mixedAction->setCheckable(
true);
181 m_mixedAction->setActionGroup(radioGroup);
182 m_hardAction = m_indentSettingsMenu->addAction(
i18n(
"Tabulators"));
183 m_hardAction->setCheckable(
true);
184 m_hardAction->setActionGroup(radioGroup);
185 m_softAction = m_indentSettingsMenu->addAction(
i18n(
"Spaces"));
186 m_softAction->setCheckable(
true);
187 m_softAction->setActionGroup(radioGroup);
188 connect(radioGroup, &QActionGroup::triggered,
this, &KateStatusBar::slotIndentTabMode);
190 m_tabsIndent->setMenu(m_indentSettingsMenu);
196 m_encoding->setMenu(m_view->encodingAction()->menu());
197 m_encoding->setWhatsThis(
i18n(
"Encoding"));
200 m_eol->setWhatsThis(
i18n(
"End of line type"));
201 m_eol->setToolTip(
i18n(
"End of line type"));
202 m_eol->setMenu(m_view->getEolMenu());
208 m_modeMenuList->setWhatsThis(
i18n(
209 "Here you can choose which mode should be used for the current document. This will influence the highlighting and folding being used, for example."));
210 m_modeMenuList->updateMenu(m_view->doc());
214 m_modeMenuList->setButton(m_mode, KateModeMenuList::AlignHInverse, KateModeMenuList::AlignTop, KateModeMenuList::AutoUpdateTextButton(
false));
215 m_mode->setMenu(m_modeMenuList);
216 m_mode->setWhatsThis(
i18n(
"Syntax highlighting"));
225 connect(m_view->doc(), &KTextEditor::DocumentPrivate::defaultDictionaryChanged,
this, &KateStatusBar::updateDictionary);
226 connect(m_view->doc(), &KTextEditor::DocumentPrivate::dictionaryRangesPresent,
this, &KateStatusBar::updateDictionary);
227 connect(m_view, &KTextEditor::ViewPrivate::caretChangedRange,
this, &KateStatusBar::updateDictionary);
230 toggleWordCount(KateViewConfig::global()->showWordCount());
244 if (QAction *inputModesAction = m_view->actionCollection()->action(QStringLiteral(
"view_input_modes"))) {
245 if (QMenu *inputModesMenu = inputModesAction->menu()) {
246 const auto actions = inputModesMenu->actions();
247 for (
int i = 0; i <
actions.count(); ++i) {
255 QAction *showLines = menu.addAction(
i18n(
"Show line count"),
this, &KateStatusBar::toggleShowLines);
257 showLines->
setChecked(KateViewConfig::global()->showLineCount());
258 QAction *showWords = menu.addAction(
i18n(
"Show word count"),
this, &KateStatusBar::toggleShowWords);
260 showWords->
setChecked(KateViewConfig::global()->showWordCount());
261 auto a = menu.addAction(
i18n(
"Line/Column compact mode"),
this, [](
bool checked) {
262 KateViewConfig::global()->
setValue(KateViewConfig::StatusbarLineColumnCompact, checked);
264 a->setCheckable(
true);
265 a->setChecked(KateViewConfig::global()->value(KateViewConfig::StatusbarLineColumnCompact).toBool());
266 menu.exec(
event->globalPos());
269void KateStatusBar::toggleShowLines(
bool checked)
271 KateViewConfig::global()->
setValue(KateViewConfig::ShowLineCount, checked);
274void KateStatusBar::toggleShowWords(
bool checked)
276 KateViewConfig::global()->setShowWordCount(checked);
279void KateStatusBar::updateStatus()
283 cursorPositionChanged();
284 documentConfigChanged();
290void KateStatusBar::selectionChanged()
292 const unsigned int newSelectionMode = m_view->blockSelection();
293 if (newSelectionMode == m_selectionMode) {
298 m_selectionMode = newSelectionMode;
302void KateStatusBar::viewModeChanged()
305 QString text = m_view->viewModeHuman();
306 if (m_view->blockSelection()) {
307 text =
i18n(
"[BLOCK] %1", text);
310 m_inputMode->setText(text);
313void KateStatusBar::cursorPositionChanged()
315 KTextEditor::Cursor position(m_view->cursorPositionVirtual());
316 const int l = position.line() + 1;
317 const int c = position.column() + 1;
321 if (KateViewConfig::global()->value(KateViewConfig::StatusbarLineColumnCompact).toBool()) {
322 if (KateViewConfig::global()->showLineCount()) {
328 if (KateViewConfig::global()->showLineCount()) {
335 text.
append(QLatin1String(
", ") + m_wordCount);
337 m_cursorPosition->setText(text);
340void KateStatusBar::updateDictionary()
342 const auto spellchecker = Sonnet::Speller();
343 const auto availableDictionaries = spellchecker.availableDictionaries();
345 if (availableDictionaries.isEmpty()) {
346 m_dictionary->hide();
352 KTextEditor::Cursor position(m_view->cursorPositionVirtual());
353 const QList<QPair<KTextEditor::MovingRange *, QString>> dictRanges = m_view->doc()->dictionaryRanges();
354 for (
const auto &rangeDictPair : dictRanges) {
355 const KTextEditor::MovingRange *range = rangeDictPair.first;
356 if (range->
contains(position) || range->
end() == position) {
357 newDict = rangeDictPair.second;
363 newDict = m_view->doc()->defaultDictionary();
365 newDict = spellchecker.defaultLanguage();
369 if (!m_dictionaryGroup->checkedAction() || (m_dictionaryGroup->checkedAction()->data().toString() != newDict) || m_dictionary->text().isEmpty()) {
372 m_dictionary->setText(newDict.
section(QLatin1Char(
'-'), 0, 0));
374 m_dictionaryGroup->blockSignals(
true);
375 const auto acts = m_dictionaryGroup->actions();
376 for (
auto a : acts) {
377 if (a->data().toString() == newDict) {
385 QString dictName = availableDictionaries.key(newDict);
387 QAction *action = m_dictionaryGroup->addAction(dictName);
391 m_dictionaryMenu->addAction(action);
394 m_dictionaryGroup->blockSignals(
false);
398void KateStatusBar::documentConfigChanged()
400 m_encoding->setText(m_view->document()->encoding());
401 KateDocumentConfig *config = ((KTextEditor::DocumentPrivate *)m_view->document())->config();
402 int tabWidth = config->tabWidth();
403 int indentationWidth = config->indentationWidth();
404 bool replaceTabsDyn = config->replaceTabsDyn();
406 static const KLocalizedString spacesOnly =
ki18n(
"Soft Tabs: %1");
407 static const KLocalizedString spacesOnlyShowTabs =
ki18n(
"Soft Tabs: %1 (%2)");
408 static const KLocalizedString tabsOnly =
ki18n(
"Tab Size: %1");
409 static const KLocalizedString tabSpacesMixed =
ki18n(
"Indent/Tab: %1/%2");
411 if (!replaceTabsDyn) {
412 if (tabWidth == indentationWidth) {
413 m_tabsIndent->setText(tabsOnly.
subs(tabWidth).
toString());
414 m_tabGroup->setEnabled(
false);
415 m_hardAction->setChecked(
true);
417 m_tabsIndent->setText(tabSpacesMixed.
subs(indentationWidth).
subs(tabWidth).
toString());
418 m_tabGroup->setEnabled(
true);
419 m_mixedAction->setChecked(
true);
422 if (tabWidth == indentationWidth) {
423 m_tabsIndent->setText(spacesOnly.
subs(indentationWidth).
toString());
424 m_tabGroup->setEnabled(
true);
425 m_softAction->setChecked(
true);
427 m_tabsIndent->setText(spacesOnlyShowTabs.
subs(indentationWidth).
subs(tabWidth).
toString());
428 m_tabGroup->setEnabled(
true);
429 m_softAction->setChecked(
true);
433 updateGroup(m_tabGroup, tabWidth);
434 updateGroup(m_indentGroup, indentationWidth);
438void KateStatusBar::modeChanged()
447 a = menu->
addAction(QStringLiteral(
"%1").arg(data));
456void KateStatusBar::updateGroup(
QActionGroup *group,
int w)
458 QAction *m1 =
nullptr;
461 const auto acts = group->
actions();
462 for (QAction *action : acts) {
483void KateStatusBar::slotTabGroup(
QAction *a)
487 KateDocumentConfig *config = ((KTextEditor::DocumentPrivate *)m_view->document())->config();
491 val = config->tabWidth();
494 config->setTabWidth(val);
497void KateStatusBar::slotIndentGroup(
QAction *a)
501 KateDocumentConfig *config = ((KTextEditor::DocumentPrivate *)m_view->document())->config();
504 i18n(
"Indentation Width"),
505 i18n(
"Please specify the wanted indentation width:"),
506 config->indentationWidth(),
512 val = config->indentationWidth();
516 config->setIndentationWidth(val);
517 if (m_hardAction->isChecked()) {
518 config->setTabWidth(val);
523void KateStatusBar::slotIndentTabMode(
QAction *a)
525 KateDocumentConfig *config = ((KTextEditor::DocumentPrivate *)m_view->document())->config();
526 if (a == m_softAction) {
527 config->setReplaceTabsDyn(
true);
528 }
else if (a == m_mixedAction) {
529 if (config->replaceTabsDyn()) {
530 config->setReplaceTabsDyn(
false);
532 m_tabGroup->setEnabled(
true);
533 }
else if (a == m_hardAction) {
534 if (config->replaceTabsDyn()) {
536 config->setReplaceTabsDyn(
false);
537 config->setTabWidth(config->indentationWidth());
540 config->setTabWidth(config->indentationWidth());
542 m_tabGroup->setEnabled(
false);
546void KateStatusBar::toggleWordCount(
bool on)
548 if ((m_wordCounter !=
nullptr) == on) {
553 m_wordCounter =
new WordCounter(m_view);
554 connect(m_wordCounter, &WordCounter::changed,
this, &KateStatusBar::wordCountChanged);
556 delete m_wordCounter;
557 m_wordCounter =
nullptr;
560 wordCountChanged(0, 0, 0, 0);
563void KateStatusBar::wordCountChanged(
int wordsInDocument,
int wordsInSelection,
int charsInDocument,
int charsInSelection)
566 if (charsInSelection > 0) {
567 m_wordCount =
i18nc(
"%1 and %3 are the selected words/chars count, %2 and %4 are the total words/chars count.",
568 "Words %1/%2, Chars %3/%4",
574 m_wordCount =
i18nc(
"%1 and %2 are the total words/chars count.",
"Words %1, Chars %2", wordsInDocument, charsInDocument);
580 cursorPositionChanged();
583void KateStatusBar::configChanged()
585 toggleWordCount(m_view->config()->showWordCount());
586 const int zoom = m_view->rendererConfig()->baseFont().pointSizeF() / KateRendererConfig::global()->baseFont().
pointSizeF() * 100;
588 m_zoomLevel->setVisible(
true);
589 m_zoomLevel->setText(
i18n(
"Zoom: %1%", zoom));
594 auto cfg = KateViewConfig::global();
595 auto updateButtonVisibility = [cfg](StatusBarButton *b, KateViewConfig::ConfigEntryTypes c) {
596 bool v = cfg->value(c).toBool();
601 updateButtonVisibility(m_inputMode, KateViewConfig::ShowStatusbarInputMode);
602 updateButtonVisibility(m_mode, KateViewConfig::ShowStatusbarHighlightingMode);
603 updateButtonVisibility(m_cursorPosition, KateViewConfig::ShowStatusbarLineColumn);
604 updateButtonVisibility(m_tabsIndent, KateViewConfig::ShowStatusbarTabSettings);
605 updateButtonVisibility(m_encoding, KateViewConfig::ShowStatusbarFileEncoding);
606 updateButtonVisibility(m_eol, KateViewConfig::ShowStatusbarEOL);
608 bool v = cfg->value(KateViewConfig::ShowStatusbarDictionary).toBool();
609 if (v != (!m_dictionary->isHidden()) && !Sonnet::Speller().availableDictionaries().isEmpty()) {
610 updateButtonVisibility(m_dictionary, KateViewConfig::ShowStatusbarDictionary);
614void KateStatusBar::changeDictionary(
QAction *action)
617 m_dictionary->setText(dictionary);
619 KTextEditor::Range selection = m_view->selectionRange();
621 m_view->doc()->setDictionary(dictionary, selection);
623 m_view->doc()->setDefaultDictionary(dictionary);
627void KateStatusBar::updateEOL()
629 const int eol = m_view->getEol();
632 case KateDocumentConfig::eolUnix:
633 text = QStringLiteral(
"LF");
635 case KateDocumentConfig::eolDos:
636 text = QStringLiteral(
"CRLF");
638 case KateDocumentConfig::eolMac:
639 text = QStringLiteral(
"CR");
642 if (text != m_eol->text()) {
643 m_eol->setText(text);
649 return m_modeMenuList;
652#include "moc_katestatusbar.cpp"
static void setNoAccel(QWidget *widget)
KLocalizedString subs(const KLocalizedString &a, int fieldWidth=0, QChar fillChar=QLatin1Char(' ')) const
void configChanged(KTextEditor::Document *document)
This signal is emitted whenever the current document configuration is changed.
void modeChanged(KTextEditor::Document *document)
Warn anyone listening that the current document's mode has changed.
static KTextEditor::EditorPrivate * self()
Kate Part Internal stuff ;)
virtual const MovingCursor & end() const =0
Retrieve end cursor of this range, read-only.
bool contains(const Range &range) const
Check whether the this range wholly encompasses range.
constexpr bool isEmpty() const noexcept
Returns true if this range contains no characters, ie.
constexpr bool isValid() const noexcept
Validity check.
void configChanged(KTextEditor::View *view)
This signal is emitted whenever the current view configuration is changed.
void cursorPositionChanged(KTextEditor::View *view, KTextEditor::Cursor newPosition)
This signal is emitted whenever the view's cursor position changed.
void viewModeChanged(KTextEditor::View *view, KTextEditor::View::ViewMode mode)
This signal is emitted whenever the view mode of view changes.
void selectionChanged(KTextEditor::View *view)
This signal is emitted whenever the view's selection changes.
void configEnd()
End a config change transaction, update the concerned KateDocumentConfig/KateDocumentConfig/KateDocum...
void configStart()
Start some config changes.
bool setValue(const int key, const QVariant &value)
Set a config value.
KLocalizedString KI18N_EXPORT ki18n(const char *text)
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
char * toString(const EngineQuery &query)
GeoCoordinates geo(const QVariant &location)
QAction * zoom(const QObject *recvr, const char *slot, QObject *parent)
QVariant data() const const
void setActionGroup(QActionGroup *group)
void setData(const QVariant &data)
void setText(const QString &text)
QList< QAction * > actions() const const
void addStretch(int stretch)
virtual void setSpacing(int spacing) override
qreal pointSizeF() const const
void setContentsMargins(const QMargins &margins)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
virtual bool event(QEvent *e)
virtual bool eventFilter(QObject *watched, QEvent *event)
QString & append(QChar ch)
bool isEmpty() const const
QString section(QChar sep, qsizetype start, qsizetype end, SectionFlags flags) const const
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const=0
int toInt(bool *ok) const const
QString toString() const const