client: Fix text format shortcuts edge case
[quassel.git] / src / qtui / inputwidget.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2018 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #include "inputwidget.h"
22
23 #include <QIcon>
24 #include <QPainter>
25 #include <QPixmap>
26 #include <QRect>
27
28 #include "action.h"
29 #include "actioncollection.h"
30 #include "bufferview.h"
31 #include "client.h"
32 #include "icon.h"
33 #include "ircuser.h"
34 #include "networkmodel.h"
35 #include "qtui.h"
36 #include "qtuisettings.h"
37 #include "tabcompleter.h"
38
39 const int leftMargin = 3;
40
41 InputWidget::InputWidget(QWidget *parent)
42     : AbstractItemView(parent),
43     _networkId(0)
44 {
45     ui.setupUi(this);
46     connect(ui.ownNick, SIGNAL(activated(QString)), this, SLOT(changeNick(QString)));
47
48     layout()->setAlignment(ui.ownNick, Qt::AlignBottom);
49     layout()->setAlignment(ui.inputEdit, Qt::AlignBottom);
50     layout()->setAlignment(ui.showStyleButton, Qt::AlignBottom);
51     layout()->setAlignment(ui.styleFrame, Qt::AlignBottom);
52
53     setStyleOptionsExpanded(false);
54
55     setFocusProxy(ui.inputEdit);
56     ui.ownNick->setFocusProxy(ui.inputEdit);
57
58     ui.ownNick->setSizeAdjustPolicy(QComboBox::AdjustToContents);
59     ui.ownNick->installEventFilter(new MouseWheelFilter(this));
60     ui.inputEdit->installEventFilter(this);
61
62     ui.inputEdit->setMinHeight(1);
63     ui.inputEdit->setMaxHeight(5);
64     ui.inputEdit->setMode(MultiLineEdit::MultiLine);
65     ui.inputEdit->setPasteProtectionEnabled(true);
66
67     ui.boldButton->setIcon(icon::get("format-text-bold"));
68     ui.italicButton->setIcon(icon::get("format-text-italic"));
69     ui.underlineButton->setIcon(icon::get("format-text-underline"));
70     ui.clearButton->setIcon(icon::get("edit-clear"));
71     ui.encryptionIconLabel->hide();
72
73     _colorMenu = new QMenu();
74     _colorFillMenu = new QMenu();
75
76     QStringList names;
77     names << tr("White") << tr("Black") << tr("Dark blue") << tr("Dark green") << tr("Red") << tr("Dark red") << tr("Dark magenta")  << tr("Orange")
78           << tr("Yellow") << tr("Green") << tr("Dark cyan") << tr("Cyan") << tr("Blue") << tr("Magenta") << tr("Dark gray") << tr("Light gray");
79
80     QPixmap pix(16, 16);
81     for (int i = 0; i < inputLine()->mircColorMap().count(); i++) {
82         pix.fill(inputLine()->mircColorMap().values()[i]);
83         _colorMenu->addAction(pix, names[i])->setData(inputLine()->mircColorMap().keys()[i]);
84         _colorFillMenu->addAction(pix, names[i])->setData(inputLine()->mircColorMap().keys()[i]);
85     }
86
87     pix.fill(Qt::transparent);
88     _colorMenu->addAction(pix, tr("Clear Color"))->setData("");
89     _colorFillMenu->addAction(pix, tr("Clear Color"))->setData("");
90
91     ui.textcolorButton->setMenu(_colorMenu);
92     // Set the default action to clear color (last added action)
93     ui.textcolorButton->setDefaultAction(_colorMenu->actions().last());
94     connect(_colorMenu, SIGNAL(triggered(QAction *)), this, SLOT(colorChosen(QAction *)));
95
96     ui.highlightcolorButton->setMenu(_colorFillMenu);
97     // Set the default action to clear fill color (last added action)
98     ui.highlightcolorButton->setDefaultAction(_colorFillMenu->actions().last());
99     connect(_colorFillMenu, SIGNAL(triggered(QAction *)), this, SLOT(colorHighlightChosen(QAction *)));
100
101     // Needs to be done after adding the menu, otherwise the icon mysteriously vanishes until clicked
102     ui.textcolorButton->setIcon(icon::get("format-text-color"));
103     ui.highlightcolorButton->setIcon(icon::get("format-fill-color"));
104
105     // Show/hide style button
106     connect(ui.showStyleButton, SIGNAL(toggled(bool)), this, SLOT(setStyleOptionsExpanded(bool)));
107
108     // Clear formatting button
109     connect(ui.clearButton, SIGNAL(clicked()), this, SLOT(clearFormat()));
110
111     new TabCompleter(ui.inputEdit);
112
113     UiStyleSettings fs("Fonts");
114     fs.notify("UseCustomInputWidgetFont", this, SLOT(setUseCustomFont(QVariant)));
115     fs.notify("InputWidget", this, SLOT(setCustomFont(QVariant)));
116     if (fs.value("UseCustomInputWidgetFont", false).toBool())
117         setCustomFont(fs.value("InputWidget", QFont()));
118
119     UiSettings s("InputWidget");
120
121 #ifdef HAVE_KDE4
122     s.notify("EnableSpellCheck", this, SLOT(setEnableSpellCheck(QVariant)));
123     setEnableSpellCheck(s.value("EnableSpellCheck", false));
124 #endif
125
126     s.notify("EnableEmacsMode", this, SLOT(setEnableEmacsMode(QVariant)));
127     setEnableEmacsMode(s.value("EnableEmacsMode", false));
128
129     s.notify("ShowNickSelector", this, SLOT(setShowNickSelector(QVariant)));
130     setShowNickSelector(s.value("ShowNickSelector", true));
131
132     s.notify("ShowStyleButtons", this, SLOT(setShowStyleButtons(QVariant)));
133     setShowStyleButtons(s.value("ShowStyleButtons", true));
134
135     s.notify("EnablePerChatHistory", this, SLOT(setEnablePerChatHistory(QVariant)));
136     setEnablePerChatHistory(s.value("EnablePerChatHistory", true));
137
138     s.notify("MaxNumLines", this, SLOT(setMaxLines(QVariant)));
139     setMaxLines(s.value("MaxNumLines", 5));
140
141     s.notify("EnableScrollBars", this, SLOT(setScrollBarsEnabled(QVariant)));
142     setScrollBarsEnabled(s.value("EnableScrollBars", true));
143
144     s.notify("EnableLineWrap", this, SLOT(setLineWrapEnabled(QVariant)));
145     setLineWrapEnabled(s.value("EnableLineWrap", true));
146
147     s.notify("EnableMultiLine", this, SLOT(setMultiLineEnabled(QVariant)));
148     setMultiLineEnabled(s.value("EnableMultiLine", true));
149
150     ActionCollection *coll = QtUi::actionCollection();
151
152     Action *activateInputline = coll->add<Action>("FocusInputLine");
153     connect(activateInputline, SIGNAL(triggered()), SLOT(setFocus()));
154     activateInputline->setText(tr("Focus Input Line"));
155     activateInputline->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_L));
156
157     connect(inputLine(), SIGNAL(textEntered(QString)), SLOT(onTextEntered(QString)), Qt::QueuedConnection); // make sure the line is already reset, bug #984
158     connect(inputLine(), SIGNAL(currentCharFormatChanged(QTextCharFormat)), this, SLOT(currentCharFormatChanged(QTextCharFormat)));
159 }
160
161
162 InputWidget::~InputWidget()
163 {
164 }
165
166
167 void InputWidget::setUseCustomFont(const QVariant &v)
168 {
169     if (v.toBool()) {
170         UiStyleSettings fs("Fonts");
171         setCustomFont(fs.value("InputWidget"));
172     }
173     else
174         setCustomFont(QFont());
175 }
176
177
178 void InputWidget::setCustomFont(const QVariant &v)
179 {
180     QFont font = v.value<QFont>();
181     if (font.family().isEmpty())
182         font = QApplication::font();
183     // we don't want font styles as this conflics with mirc code richtext editing
184     font.setBold(false);
185     font.setItalic(false);
186     font.setUnderline(false);
187     font.setStrikeOut(false);
188     ui.inputEdit->setCustomFont(font);
189 }
190
191
192 void InputWidget::setEnableSpellCheck(const QVariant &v)
193 {
194     ui.inputEdit->setSpellCheckEnabled(v.toBool());
195 }
196
197
198 void InputWidget::setEnableEmacsMode(const QVariant &v)
199 {
200     ui.inputEdit->setEmacsMode(v.toBool());
201 }
202
203
204 void InputWidget::setShowNickSelector(const QVariant &v)
205 {
206     ui.ownNick->setVisible(v.toBool());
207 }
208
209
210 void InputWidget::setShowStyleButtons(const QVariant &v)
211 {
212     ui.showStyleButton->setVisible(v.toBool());
213 }
214
215
216 void InputWidget::setEnablePerChatHistory(const QVariant &v)
217 {
218     _perChatHistory = v.toBool();
219 }
220
221
222 void InputWidget::setMaxLines(const QVariant &v)
223 {
224     ui.inputEdit->setMaxHeight(v.toInt());
225 }
226
227
228 void InputWidget::setScrollBarsEnabled(const QVariant &v)
229 {
230     ui.inputEdit->setScrollBarsEnabled(v.toBool());
231 }
232
233
234 void InputWidget::setLineWrapEnabled(const QVariant &v)
235 {
236     ui.inputEdit->setLineWrapEnabled(v.toBool());
237 }
238
239
240 void InputWidget::setMultiLineEnabled(const QVariant &v)
241 {
242     ui.inputEdit->setMode(v.toBool() ? MultiLineEdit::MultiLine : MultiLineEdit::SingleLine);
243 }
244
245
246 bool InputWidget::eventFilter(QObject *watched, QEvent *event)
247 {
248     if (event->type() != QEvent::KeyPress)
249         return false;
250
251     QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
252
253     // keys from BufferView should be sent to (and focus) the input line
254     BufferView *view = qobject_cast<BufferView *>(watched);
255     if (view) {
256         if (keyEvent->text().length() == 1 && !(keyEvent->modifiers() & (Qt::ControlModifier ^ Qt::AltModifier))) { // normal key press
257             QChar c = keyEvent->text().at(0);
258             if (c.isLetterOrNumber() || c.isSpace() || c.isPunct() || c.isSymbol()) {
259                 setFocus();
260                 QCoreApplication::sendEvent(inputLine(), keyEvent);
261                 return true;
262             }
263         }
264         return false;
265     }
266     else if (watched == ui.inputEdit) {
267         if (keyEvent->matches(QKeySequence::Find)) {
268             QAction *act = GraphicalUi::actionCollection()->action("ToggleSearchBar");
269             if (act) {
270                 act->toggle();
271                 return true;
272             }
273         }
274         return false;
275     }
276     return false;
277 }
278
279
280 void InputWidget::currentChanged(const QModelIndex &current, const QModelIndex &previous)
281 {
282     BufferId currentBufferId = current.data(NetworkModel::BufferIdRole).value<BufferId>();
283     BufferId previousBufferId = previous.data(NetworkModel::BufferIdRole).value<BufferId>();
284
285     if (_perChatHistory) {
286         //backup
287         historyMap[previousBufferId].history = inputLine()->history();
288         historyMap[previousBufferId].tempHistory = inputLine()->tempHistory();
289         historyMap[previousBufferId].idx = inputLine()->idx();
290         historyMap[previousBufferId].inputLine = inputLine()->html();
291
292         //restore
293         inputLine()->setHistory(historyMap[currentBufferId].history);
294         inputLine()->setTempHistory(historyMap[currentBufferId].tempHistory);
295         inputLine()->setIdx(historyMap[currentBufferId].idx);
296         inputLine()->setHtml(historyMap[currentBufferId].inputLine);
297         inputLine()->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
298
299         // FIXME this really should be in MultiLineEdit (and the const int on top removed)
300         QTextBlockFormat format = inputLine()->textCursor().blockFormat();
301         format.setLeftMargin(leftMargin); // we want a little space between the frame and the contents
302         inputLine()->textCursor().setBlockFormat(format);
303     }
304
305     NetworkId networkId = current.data(NetworkModel::NetworkIdRole).value<NetworkId>();
306     if (networkId == _networkId)
307         return;
308
309     setNetwork(networkId);
310     updateNickSelector();
311     updateEnabledState();
312 }
313
314
315 void InputWidget::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
316 {
317     QItemSelectionRange changedArea(topLeft, bottomRight);
318     if (changedArea.contains(selectionModel()->currentIndex())) {
319         updateEnabledState();
320
321         bool encrypted = false;
322
323         IrcChannel *chan = qobject_cast<IrcChannel *>(Client::bufferModel()->data(selectionModel()->currentIndex(), NetworkModel::IrcChannelRole).value<QObject *>());
324         if (chan)
325             encrypted = chan->encrypted();
326
327         IrcUser *user = qobject_cast<IrcUser *>(Client::bufferModel()->data(selectionModel()->currentIndex(), NetworkModel::IrcUserRole).value<QObject *>());
328         if (user)
329             encrypted = user->encrypted();
330
331         if (encrypted)
332             ui.encryptionIconLabel->show();
333         else
334             ui.encryptionIconLabel->hide();
335     }
336 }
337
338
339 void InputWidget::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
340 {
341     NetworkId networkId;
342     QModelIndex child;
343     for (int row = start; row <= end; row++) {
344         child = model()->index(row, 0, parent);
345         if (NetworkModel::NetworkItemType != child.data(NetworkModel::ItemTypeRole).toInt())
346             continue;
347         networkId = child.data(NetworkModel::NetworkIdRole).value<NetworkId>();
348         if (networkId == _networkId) {
349             setNetwork(0);
350             updateNickSelector();
351             return;
352         }
353     }
354 }
355
356
357 void InputWidget::updateEnabledState()
358 {
359 // FIXME: Find a visualization for this that does not disable the widget!
360 //        Disabling kills global action shortcuts, plus users sometimes need/want to enter text
361 //        even in inactive channels.
362 #if 0
363     QModelIndex currentIndex = selectionModel()->currentIndex();
364
365     const Network *net = Client::networkModel()->networkByIndex(currentIndex);
366     bool enabled = false;
367     if (net) {
368         // disable inputline if it's a channelbuffer we parted from or...
369         enabled = (currentIndex.data(NetworkModel::ItemActiveRole).value<bool>() || (currentIndex.data(NetworkModel::BufferTypeRole).toInt() != BufferInfo::ChannelBuffer));
370         // ... if we're not connected to the network at all
371         enabled &= net->isConnected();
372     }
373
374     ui.inputEdit->setEnabled(enabled);
375 #endif
376 }
377
378
379 const Network *InputWidget::currentNetwork() const
380 {
381     return Client::network(_networkId);
382 }
383
384
385 BufferInfo InputWidget::currentBufferInfo() const
386 {
387     return selectionModel()->currentIndex().data(NetworkModel::BufferInfoRole).value<BufferInfo>();
388 };
389
390
391 void InputWidget::applyFormatActiveColor()
392 {
393     if (!ui.textcolorButton->defaultAction()) {
394         return;
395     }
396     colorChosen(ui.textcolorButton->defaultAction());
397 }
398
399
400 void InputWidget::applyFormatActiveColorFill()
401 {
402     if (!ui.highlightcolorButton->defaultAction()) {
403         return;
404     }
405     colorHighlightChosen(ui.highlightcolorButton->defaultAction());
406 }
407
408
409 void InputWidget::toggleFormatBold()
410 {
411     setFormatBold(!ui.boldButton->isChecked());
412 }
413
414
415 void InputWidget::toggleFormatItalic()
416 {
417     setFormatItalic(!ui.italicButton->isChecked());
418 }
419
420
421 void InputWidget::toggleFormatUnderline()
422 {
423     setFormatUnderline(!ui.underlineButton->isChecked());
424 }
425
426
427 void InputWidget::clearFormat()
428 {
429     // Clear all formatting for selection (not global)
430     setFormatClear(false);
431 }
432
433
434 void InputWidget::setNetwork(NetworkId networkId)
435 {
436     if (_networkId == networkId)
437         return;
438
439     const Network *previousNet = Client::network(_networkId);
440     if (previousNet) {
441         disconnect(previousNet, 0, this, 0);
442         if (previousNet->me())
443             disconnect(previousNet->me(), 0, this, 0);
444     }
445
446     _networkId = networkId;
447
448     const Network *network = Client::network(networkId);
449     if (network) {
450         connect(network, SIGNAL(identitySet(IdentityId)), this, SLOT(setIdentity(IdentityId)));
451         connectMyIrcUser();
452         setIdentity(network->identity());
453     }
454     else {
455         setIdentity(0);
456         _networkId = 0;
457     }
458 }
459
460
461 void InputWidget::connectMyIrcUser()
462 {
463     const Network *network = currentNetwork();
464     if (network->me()) {
465         connect(network->me(), SIGNAL(nickSet(const QString &)), this, SLOT(updateNickSelector()));
466         connect(network->me(), SIGNAL(userModesSet(QString)), this, SLOT(updateNickSelector()));
467         connect(network->me(), SIGNAL(userModesAdded(QString)), this, SLOT(updateNickSelector()));
468         connect(network->me(), SIGNAL(userModesRemoved(QString)), this, SLOT(updateNickSelector()));
469         connect(network->me(), SIGNAL(awaySet(bool)), this, SLOT(updateNickSelector()));
470         disconnect(network, SIGNAL(myNickSet(const QString &)), this, SLOT(connectMyIrcUser()));
471         updateNickSelector();
472     }
473     else {
474         connect(network, SIGNAL(myNickSet(const QString &)), this, SLOT(connectMyIrcUser()));
475     }
476 }
477
478
479 void InputWidget::setIdentity(IdentityId identityId)
480 {
481     if (_identityId == identityId)
482         return;
483
484     const Identity *previousIdentity = Client::identity(_identityId);
485     if (previousIdentity)
486         disconnect(previousIdentity, 0, this, 0);
487
488     _identityId = identityId;
489
490     const Identity *identity = Client::identity(identityId);
491     if (identity) {
492         connect(identity, SIGNAL(nicksSet(QStringList)), this, SLOT(updateNickSelector()));
493     }
494     else {
495         _identityId = 0;
496     }
497     updateNickSelector();
498 }
499
500
501 void InputWidget::updateNickSelector() const
502 {
503     ui.ownNick->clear();
504
505     const Network *net = currentNetwork();
506     if (!net)
507         return;
508
509     const Identity *identity = Client::identity(net->identity());
510     if (!identity) {
511         qWarning() << "InputWidget::updateNickSelector(): can't find Identity for Network" << net->networkId() << "IdentityId:" << net->identity();
512         return;
513     }
514
515     int nickIdx;
516     QStringList nicks = identity->nicks();
517     if ((nickIdx = nicks.indexOf(net->myNick())) == -1) {
518         nicks.prepend(net->myNick());
519         nickIdx = 0;
520     }
521
522     if (nicks.isEmpty())
523         return;
524
525     IrcUser *me = net->me();
526     if (me) {
527         nicks[nickIdx] = net->myNick();
528         if (!me->userModes().isEmpty())
529             nicks[nickIdx] += QString(" (+%1)").arg(me->userModes());
530     }
531
532     ui.ownNick->addItems(nicks);
533
534     if (me && me->isAway())
535         ui.ownNick->setItemData(nickIdx, icon::get({"im-user-away", "user-away"}), Qt::DecorationRole);
536
537     ui.ownNick->setCurrentIndex(nickIdx);
538 }
539
540
541 void InputWidget::changeNick(const QString &newNick) const
542 {
543     const Network *net = currentNetwork();
544     if (!net || net->isMyNick(newNick))
545         return;
546
547     // we reset the nick selecter as we have no confirmation yet, that this will succeed.
548     // if the action succeeds it will be properly updated anyways.
549     updateNickSelector();
550     Client::userInput(BufferInfo::fakeStatusBuffer(net->networkId()), QString("/NICK %1").arg(newNick));
551 }
552
553
554 void InputWidget::onTextEntered(const QString &text)
555 {
556     Client::userInput(currentBufferInfo(), text);
557
558     // Remove formatting from entered text
559     // TODO: Offer a way to convert pasted text to mIRC formatting codes
560     setFormatClear(true);
561 }
562
563
564 void InputWidget::setFormatClear(const bool global)
565 {
566     // Apply formatting
567     QTextCharFormat fmt;
568     fmt.setFontWeight(QFont::Normal);
569     fmt.setFontUnderline(false);
570     fmt.setFontItalic(false);
571     fmt.clearForeground();
572     fmt.clearBackground();
573     if (global) {
574         inputLine()->setCurrentCharFormat(fmt);
575     } else {
576         setFormatOnSelection(fmt);
577     }
578
579     // Make sure UI state follows
580     ui.boldButton->setChecked(false);
581     ui.italicButton->setChecked(false);
582     ui.underlineButton->setChecked(false);
583 }
584
585
586 void InputWidget::setFormatBold(const bool bold)
587 {
588     // Apply formatting
589     QTextCharFormat fmt;
590     fmt.setFontWeight(bold ? QFont::Bold : QFont::Normal);
591     mergeFormatOnSelection(fmt);
592     // Make sure UI state follows
593     ui.boldButton->setChecked(bold);
594 }
595
596
597 void InputWidget::setFormatItalic(const bool italic)
598 {
599     // Apply formatting
600     QTextCharFormat fmt;
601     fmt.setFontItalic(italic);
602     mergeFormatOnSelection(fmt);
603     // Make sure UI state follows
604     ui.italicButton->setChecked(italic);
605 }
606
607
608 void InputWidget::setFormatUnderline(const bool underline)
609 {
610     // Apply formatting
611     QTextCharFormat fmt;
612     fmt.setFontUnderline(underline);
613     mergeFormatOnSelection(fmt);
614     // Make sure UI state follows
615     ui.underlineButton->setChecked(underline);
616 }
617
618
619 void InputWidget::mergeFormatOnSelection(const QTextCharFormat &format)
620 {
621     QTextCursor cursor = inputLine()->textCursor();
622     cursor.mergeCharFormat(format);
623     inputLine()->mergeCurrentCharFormat(format);
624 }
625
626
627 void InputWidget::setFormatOnSelection(const QTextCharFormat &format)
628 {
629     QTextCursor cursor = inputLine()->textCursor();
630     cursor.setCharFormat(format);
631     inputLine()->setCurrentCharFormat(format);
632 }
633
634
635 QTextCharFormat InputWidget::getFormatOfWordOrSelection()
636 {
637     QTextCursor cursor = inputLine()->textCursor();
638     return cursor.charFormat();
639 }
640
641
642 void InputWidget::setStyleOptionsExpanded(bool expanded)
643 {
644     ui.styleFrame->setVisible(expanded);
645     if (expanded) {
646         ui.showStyleButton->setArrowType(Qt::LeftArrow);
647         ui.showStyleButton->setToolTip(tr("Hide formatting options"));
648     } else {
649         ui.showStyleButton->setArrowType(Qt::RightArrow);
650         ui.showStyleButton->setToolTip(tr("Show formatting options"));
651     }
652 }
653
654
655 void InputWidget::currentCharFormatChanged(const QTextCharFormat &format)
656 {
657     fontChanged(format.font());
658 }
659
660
661 void InputWidget::on_boldButton_clicked(bool checked)
662 {
663     setFormatBold(checked);
664 }
665
666
667 void InputWidget::on_underlineButton_clicked(bool checked)
668 {
669     setFormatUnderline(checked);
670 }
671
672
673 void InputWidget::on_italicButton_clicked(bool checked)
674 {
675     setFormatItalic(checked);
676 }
677
678
679 void InputWidget::fontChanged(const QFont &f)
680 {
681     ui.boldButton->setChecked(f.bold());
682     ui.italicButton->setChecked(f.italic());
683     ui.underlineButton->setChecked(f.underline());
684 }
685
686
687 void InputWidget::colorChosen(QAction *action)
688 {
689     QTextCharFormat fmt;
690     QColor color;
691     if (action->data().value<QString>() == "") {
692         color = Qt::transparent;
693         fmt = getFormatOfWordOrSelection();
694         fmt.clearForeground();
695         setFormatOnSelection(fmt);
696     }
697     else {
698         color = QColor(inputLine()->rgbColorFromMirc(action->data().value<QString>()));
699         fmt.setForeground(color);
700         mergeFormatOnSelection(fmt);
701     }
702     ui.textcolorButton->setDefaultAction(action);
703     ui.textcolorButton->setIcon(createColorToolButtonIcon(icon::get("format-text-color"), color));
704 }
705
706
707 void InputWidget::colorHighlightChosen(QAction *action)
708 {
709     QTextCharFormat fmt;
710     QColor color;
711     if (action->data().value<QString>() == "") {
712         color = Qt::transparent;
713         fmt = getFormatOfWordOrSelection();
714         fmt.clearBackground();
715         setFormatOnSelection(fmt);
716     }
717     else {
718         color = QColor(inputLine()->rgbColorFromMirc(action->data().value<QString>()));
719         fmt.setBackground(color);
720         mergeFormatOnSelection(fmt);
721     }
722     ui.highlightcolorButton->setDefaultAction(action);
723     ui.highlightcolorButton->setIcon(createColorToolButtonIcon(icon::get("format-fill-color"), color));
724 }
725
726
727 void InputWidget::on_showStyleButton_toggled(bool checked)
728 {
729     setStyleOptionsExpanded(checked);
730 }
731
732
733 QIcon InputWidget::createColorToolButtonIcon(const QIcon &icon, const QColor &color)
734 {
735     QPixmap pixmap(16, 16);
736     pixmap.fill(Qt::transparent);
737     QPainter painter(&pixmap);
738     QPixmap image = icon.pixmap(16, 16);
739     QRect target(0, 0, 16, 14);
740     QRect source(0, 0, 16, 14);
741     painter.fillRect(QRect(0, 14, 16, 16), color);
742     painter.drawPixmap(target, image, source);
743
744     return QIcon(pixmap);
745 }
746
747
748 // MOUSE WHEEL FILTER
749 MouseWheelFilter::MouseWheelFilter(QObject *parent)
750     : QObject(parent)
751 {
752 }
753
754
755 bool MouseWheelFilter::eventFilter(QObject *obj, QEvent *event)
756 {
757     if (event->type() != QEvent::Wheel)
758         return QObject::eventFilter(obj, event);
759     else
760         return true;
761 }