clazy: Convert many old-style connects into function pointer based
[quassel.git] / src / qtui / topicwidget.cpp
index 8a49d27..e18625c 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005/06 by the Quassel Project                          *
+ *   Copyright (C) 2005-2018 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   You should have received a copy of the GNU General Public License     *
  *   along with this program; if not, write to the                         *
  *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
 #include "topicwidget.h"
 
 #include "client.h"
-#include "iconloader.h"
+#include "icon.h"
 #include "networkmodel.h"
+#include "uisettings.h"
+#include "graphicalui.h"
+#include "uistyle.h"
 
 TopicWidget::TopicWidget(QWidget *parent)
-  : AbstractItemView(parent)
+    : AbstractItemView(parent)
 {
-  ui.setupUi(this);
-  ui.topicEditButton->setIcon(SmallIcon("edit-rename"));
-  ui.topicLineEdit->setWordWrapEnabled(true);
+    ui.setupUi(this);
+    ui.topicEditButton->setIcon(icon::get("edit-rename"));
+    ui.topicLineEdit->setLineWrapEnabled(true);
+    ui.topicLineEdit->installEventFilter(this);
 
-  ui.topicLineEdit->installEventFilter(this);
-}
+    connect(ui.topicLabel, &StyledLabel::clickableActivated, this, &TopicWidget::clickableActivated);
+    connect(ui.topicLineEdit, &MultiLineEdit::noTextEntered, this, &TopicWidget::on_topicLineEdit_textEntered);
+
+    UiSettings s("TopicWidget");
+    s.notify("DynamicResize", this, SLOT(updateResizeMode()));
+    s.notify("ResizeOnHover", this, SLOT(updateResizeMode()));
+    updateResizeMode();
 
-void TopicWidget::currentChanged(const QModelIndex &current, const QModelIndex &previous) {
-  Q_UNUSED(previous);
-  setTopic(current.sibling(current.row(), 1).data().toString());
+    UiStyleSettings fs("Fonts");
+    fs.notify("UseCustomTopicWidgetFont", this, SLOT(setUseCustomFont(QVariant)));
+    fs.notify("TopicWidget", this, SLOT(setCustomFont(QVariant)));
+    if (fs.value("UseCustomTopicWidgetFont", false).toBool())
+        setCustomFont(fs.value("TopicWidget", QFont()));
+
+    _mouseEntered = false;
+    _readonly = false;
 }
 
-void TopicWidget::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) {
-  QItemSelectionRange changedArea(topLeft, bottomRight);
-  QModelIndex currentTopicIndex = selectionModel()->currentIndex().sibling(selectionModel()->currentIndex().row(), 1);
-  if(changedArea.contains(currentTopicIndex))
-    setTopic(currentTopicIndex.data().toString());
-};
 
-void TopicWidget::setTopic(const QString &newtopic) {
-  if(_topic == newtopic)
-    return;
+void TopicWidget::currentChanged(const QModelIndex &current, const QModelIndex &previous)
+{
+    Q_UNUSED(previous);
+    setTopic(current);
+}
+
 
-  _topic = newtopic;
-  ui.topicLabel->setText(newtopic);
-  ui.topicLineEdit->setText(newtopic);
-  switchPlain();
+void TopicWidget::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+{
+    QItemSelectionRange changedArea(topLeft, bottomRight);
+    QModelIndex currentTopicIndex = selectionModel()->currentIndex().sibling(selectionModel()->currentIndex().row(), 1);
+    if (changedArea.contains(currentTopicIndex))
+        setTopic(selectionModel()->currentIndex());
 }
 
-void TopicWidget::on_topicLineEdit_textEntered() {
-  QModelIndex currentIdx = currentIndex();
-  if(currentIdx.isValid() && currentIdx.data(NetworkModel::BufferTypeRole) == BufferInfo::ChannelBuffer) {
-    BufferInfo bufferInfo = currentIdx.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
-    if(ui.topicLineEdit->text().isEmpty())
-      Client::userInput(bufferInfo, QString("/quote TOPIC %1 :").arg(bufferInfo.bufferName()));
+void TopicWidget::setUseCustomFont(const QVariant &v)
+{
+    if (v.toBool()) {
+        UiStyleSettings fs("Fonts");
+        setCustomFont(fs.value("TopicWidget").value<QFont>());
+    }
     else
-      Client::userInput(bufferInfo, QString("/topic %1").arg(ui.topicLineEdit->text()));
-  }
-  switchPlain();
+        setCustomFont(QFont());
 }
 
-void TopicWidget::on_topicEditButton_clicked() {
-  switchEditable();
-}
 
-void TopicWidget::switchEditable() {
-  ui.stackedWidget->setCurrentIndex(1);
-  ui.topicLineEdit->setFocus();
-  updateGeometry();
+void TopicWidget::setCustomFont(const QVariant &v)
+{
+    UiStyleSettings fs("Fonts");
+    if (!fs.value("UseCustomTopicWidgetFont", false).toBool())
+        return;
+
+    setCustomFont(v.value<QFont>());
 }
 
-void TopicWidget::switchPlain() {
-  ui.stackedWidget->setCurrentIndex(0);
-  ui.topicLineEdit->setText(_topic);
-  updateGeometry();
+
+void TopicWidget::setCustomFont(const QFont &f)
+{
+    QFont font = f;
+    if (font.family().isEmpty())
+        font = QApplication::font();
+
+    ui.topicLineEdit->setCustomFont(font);
+    ui.topicLabel->setCustomFont(font);
 }
 
-// filter for the input widget to switch back to normal mode
-bool TopicWidget::eventFilter(QObject *obj, QEvent *event) {
-  if(event->type() == QEvent::FocusOut) {
+
+void TopicWidget::setTopic(const QModelIndex &index)
+{
+    QString newtopic;
+    bool readonly = true;
+
+    BufferId id = index.data(NetworkModel::BufferIdRole).value<BufferId>();
+    if (id.isValid()) {
+        QModelIndex index0 = index.sibling(index.row(), 0);
+        const Network *network = Client::network(Client::networkModel()->networkId(id));
+
+        switch (Client::networkModel()->bufferType(id)) {
+        case BufferInfo::StatusBuffer:
+            if (network) {
+                newtopic = QString("%1 (%2) | %3 | %4")
+                           .arg(network->networkName().toHtmlEscaped())
+                           .arg(network->currentServer().toHtmlEscaped())
+                           .arg(tr("Users: %1").arg(network->ircUsers().count()))
+                           .arg(tr("Lag: %1 msecs").arg(network->latency()));
+            }
+            else {
+                newtopic = index0.data(Qt::DisplayRole).toString();
+            }
+            break;
+
+        case BufferInfo::ChannelBuffer:
+            newtopic = index.sibling(index.row(), 1).data().toString();
+            readonly = false;
+            break;
+
+        case BufferInfo::QueryBuffer:
+        {
+            QString nickname = index0.data(Qt::DisplayRole).toString();
+            if (network) {
+                const IrcUser *user = network->ircUser(nickname);
+                if (user) {
+                    newtopic = QString("%1%2%3 | %4@%5").arg(nickname)
+                               .arg(user->userModes().isEmpty() ? QString() : QString(" (+%1)").arg(user->userModes()))
+                               .arg(user->realName().isEmpty() ? QString() : QString(" | %1").arg(user->realName()))
+                               .arg(user->user())
+                               .arg(user->host());
+                }
+                else { // no such user
+                    newtopic = nickname;
+                }
+            }
+            else { // no valid Network-Obj.
+                newtopic = nickname;
+            }
+            break;
+        }
+        default:
+            newtopic = index0.data(Qt::DisplayRole).toString();
+        }
+    }
+
+    _topic = sanitizeTopic(newtopic);
+    _readonly = readonly;
+
+    ui.topicEditButton->setVisible(!_readonly);
+    ui.topicLabel->setText(_topic);
+    ui.topicLineEdit->setPlainText(_topic);
     switchPlain();
-    return true;
-  }
+}
+
+
+void TopicWidget::setReadOnly(const bool &readonly)
+{
+    if (_readonly == readonly)
+        return;
+
+    _readonly = readonly;
+}
+
+
+void TopicWidget::updateResizeMode()
+{
+    StyledLabel::ResizeMode mode = StyledLabel::NoResize;
+    UiSettings s("TopicWidget");
+    if (s.value("DynamicResize", true).toBool()) {
+        if (s.value("ResizeOnHover", true).toBool())
+            mode = StyledLabel::ResizeOnHover;
+        else
+            mode = StyledLabel::DynamicResize;
+    }
 
-  if(event->type() != QEvent::KeyPress)
-    return QObject::eventFilter(obj, event);
+    ui.topicLabel->setResizeMode(mode);
+}
+
+
+void TopicWidget::clickableActivated(const Clickable &click)
+{
+    NetworkId networkId = selectionModel()->currentIndex().data(NetworkModel::NetworkIdRole).value<NetworkId>();
+    UiStyle::StyledString sstr = GraphicalUi::uiStyle()->styleString(GraphicalUi::uiStyle()->mircToInternal(_topic), UiStyle::FormatType::PlainMsg);
+    click.activate(networkId, sstr.plainText);
+}
 
-  QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
 
-  if(keyEvent->key() == Qt::Key_Escape) {
+void TopicWidget::on_topicLineEdit_textEntered()
+{
+    QModelIndex currentIdx = currentIndex();
+    if (currentIdx.isValid() && currentIdx.data(NetworkModel::BufferTypeRole) == BufferInfo::ChannelBuffer) {
+        BufferInfo bufferInfo = currentIdx.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
+        if (ui.topicLineEdit->text().isEmpty())
+            Client::userInput(bufferInfo, QString("/quote TOPIC %1 :").arg(bufferInfo.bufferName()));
+        else
+            Client::userInput(bufferInfo, QString("/topic %1").arg(ui.topicLineEdit->text()));
+    }
     switchPlain();
-    return true;
-  }
+}
+
+
+void TopicWidget::on_topicEditButton_clicked()
+{
+    switchEditable();
+}
+
+
+void TopicWidget::switchEditable()
+{
+    ui.stackedWidget->setCurrentIndex(1);
+    ui.topicLineEdit->setFocus();
+    ui.topicLineEdit->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
+    updateGeometry();
+}
+
+
+void TopicWidget::switchPlain()
+{
+    ui.stackedWidget->setCurrentIndex(0);
+    ui.topicLineEdit->setPlainText(_topic);
+    updateGeometry();
+    emit switchedPlain();
+}
+
+
+// filter for the input widget to switch back to normal mode
+bool TopicWidget::eventFilter(QObject *obj, QEvent *event)
+{
+    if (event->type() == QEvent::FocusOut && !_mouseEntered) {
+        switchPlain();
+        return true;
+    }
+
+    if (event->type() == QEvent::Enter) {
+        _mouseEntered = true;
+    }
+
+    if (event->type() == QEvent::Leave) {
+        _mouseEntered = false;
+    }
+
+    if (event->type() != QEvent::KeyRelease)
+        return QObject::eventFilter(obj, event);
+
+    auto *keyEvent = static_cast<QKeyEvent *>(event);
+
+    if (keyEvent->key() == Qt::Key_Escape) {
+        switchPlain();
+        return true;
+    }
+
+    return false;
+}
+
+QString TopicWidget::sanitizeTopic(const QString& topic)
+{
+    // Normally, you don't have new lines in topic messages
+    // But the use of "plain text" functionnality from Qt replaces
+    // some unicode characters with a new line, which then triggers
+    // a stack overflow later
+    QString result(topic);
+    result.replace(QChar::CarriageReturn, " ");
+    result.replace(QChar::ParagraphSeparator, " ");
+    result.replace(QChar::LineSeparator, " ");
 
-  return false;
+    return result;
 }