common: Make SyncableObject non-copyable
[quassel.git] / src / qtui / settingspages / aliasesmodel.cpp
index 46daed8..780b152 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-2015 by the Quassel Project                        *
+ *   Copyright (C) 2005-2020 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 #include "client.h"
 #include "signalproxy.h"
 
-AliasesModel::AliasesModel(QObject *parent)
-    : QAbstractItemModel(parent),
-    _configChanged(false),
-    _modelReady(false)
+AliasesModel::AliasesModel(QObject* parent)
+    : QAbstractItemModel(parent)
 {
     // we need this signal for future connects to reset the data;
-    connect(Client::instance(), SIGNAL(connected()), this, SLOT(clientConnected()));
-    connect(Client::instance(), SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
+    connect(Client::instance(), &Client::connected, this, &AliasesModel::clientConnected);
+    connect(Client::instance(), &Client::disconnected, this, &AliasesModel::clientDisconnected);
 
     if (Client::isConnected())
         clientConnected();
@@ -41,8 +39,7 @@ AliasesModel::AliasesModel(QObject *parent)
         emit modelReady(false);
 }
 
-
-QVariant AliasesModel::data(const QModelIndex &index, int role) const
+QVariant AliasesModel::data(const QModelIndex& index, int role) const
 {
     if (!_modelReady)
         return QVariant();
@@ -57,18 +54,70 @@ QVariant AliasesModel::data(const QModelIndex &index, int role) const
             return tr("<b>The shortcut for the alias</b><br />"
                       "It can be used as a regular slash command.<br /><br />"
                       "<b>Example:</b> \"foo\" can be used per /foo");
-        case 1:
-            return tr("<b>The string the shortcut will be expanded to</b><br />"
-                      "<b>special variables:</b><br />"
-                      " - <b>$i</b> represents the i'th parameter.<br />"
-                      " - <b>$i..j</b> represents the i'th to j'th parameter separated by spaces.<br />"
-                      " - <b>$i..</b> represents all parameters from i on separated by spaces.<br />"
-                      " - <b>$i:hostname</b> represents the hostname of the user identified by the i'th parameter or a * if unknown.<br />"
-                      " - <b>$0</b> the whole string.<br />"
-                      " - <b>$nick</b> your current nickname<br />"
-                      " - <b>$channel</b> the name of the selected channel<br /><br />"
-                      "Multiple commands can be separated with semicolons<br /><br />"
-                      "<b>Example:</b> \"Test $1; Test $2; Test All $0\" will be expanded to three separate messages \"Test 1\", \"Test 2\" and \"Test All 1 2 3\" when called like /test 1 2 3");
+        case 1: {
+            // To avoid overwhelming the user, organize things into a table
+            QString strTooltip;
+            QTextStream tooltip(&strTooltip, QIODevice::WriteOnly);
+            tooltip << "<qt><style>.bold { font-weight: bold; } .italic { font-style: italic; }</style>";
+
+            // Function to add a row to the tooltip table
+            auto addRow = [&](const QString& key, const QString& value = QString(), bool condition = true) {
+                if (condition) {
+                    if (value.isEmpty()) {
+                        tooltip << "<tr><td class='italic' align='left' colspan='2'>" << key << "</td></tr>";
+                    }
+                    else {
+                        tooltip << "<tr><td class='bold' align='left'>" << key << "</td><td>" << value << "</td></tr>";
+                    }
+                }
+            };
+
+            tooltip << "<p class='bold'>" << tr("The string the shortcut will be expanded to") << "</p>";
+
+            tooltip << "<p class='bold' align='center'>" << tr("Special variables") << "</p>";
+
+            // Variable option table
+            tooltip << "<table cellspacing='5' cellpadding='0'>";
+
+            // Parameter variables
+            addRow(tr("Parameter variables"));
+            addRow("$i", tr("i'th parameter"));
+            addRow("$i..j", tr("i'th to j'th parameter separated by spaces"));
+            addRow("$i..", tr("all parameters from i on separated by spaces"));
+
+            // IrcUser handling
+            addRow(tr("Nickname parameter variables"));
+            addRow("$i:account",
+                   tr("account of user identified by i'th parameter, or a '*' if logged out or "
+                      "unknown"));
+            addRow("$i:hostname", tr("hostname of user identified by i'th parameter, or a '*' if unknown"));
+            addRow("$i:ident", tr("ident of user identified by i'th parameter, or a '*' if unknown"));
+            addRow("$i:identd",
+                   tr("ident of user identified by i'th parameter if verified, or a '*' if unknown "
+                      "or unverified (prefixed with '~')"));
+
+            // General variables
+            addRow(tr("General variables"));
+            addRow("$0", tr("the whole string"));
+            addRow("$nick", tr("your current nickname"));
+            addRow("$channel", tr("the name of the selected channel"));
+
+            // End table
+            tooltip << "</table>";
+
+            // Example header
+            tooltip << "<p>" << tr("Multiple commands can be separated with semicolons") << "</p>";
+            // Example
+            tooltip << "<p>";
+            tooltip << QString("<p><span class='bold'>%1</span> %2<br />").arg(tr("Example:"), tr("\"Test $1; Test $2; Test All $0\""));
+            tooltip << tr("...will be expanded to three separate messages \"Test 1\", \"Test 2\" "
+                          "and \"Test All 1 2 3\" when called like <i>/test 1 2 3</i>")
+                    << "</p>";
+
+            // End tooltip
+            tooltip << "</qt>";
+            return strTooltip;
+        }
         default:
             return QVariant();
         }
@@ -87,8 +136,7 @@ QVariant AliasesModel::data(const QModelIndex &index, int role) const
     }
 }
 
-
-bool AliasesModel::setData(const QModelIndex &index, const QVariant &value, int role)
+bool AliasesModel::setData(const QModelIndex& index, const QVariant& value, int role)
 {
     if (!_modelReady)
         return false;
@@ -117,12 +165,11 @@ bool AliasesModel::setData(const QModelIndex &index, const QVariant &value, int
     }
 }
 
-
 void AliasesModel::newAlias()
 {
     QString newName("alias");
     int i = 0;
-    AliasManager &manager = cloneAliasManager();
+    AliasManagermanager = cloneAliasManager();
     while (manager.contains(newName)) {
         i++;
         newName = QString("alias%1").arg(i);
@@ -132,13 +179,12 @@ void AliasesModel::newAlias()
     endInsertRows();
 }
 
-
 void AliasesModel::loadDefaults()
 {
     if (!_modelReady)
         return;
 
-    AliasManager &manager = cloneAliasManager();
+    AliasManagermanager = cloneAliasManager();
 
     if (!manager.isEmpty()) {
         beginRemoveRows(QModelIndex(), 0, rowCount() - 1);
@@ -149,26 +195,24 @@ void AliasesModel::loadDefaults()
 
     AliasManager::AliasList defaults = AliasManager::defaults();
     beginInsertRows(QModelIndex(), 0, defaults.count() - 1);
-    foreach(AliasManager::Alias alias, defaults) {
+    foreach (AliasManager::Alias alias, defaults) {
         manager.addAlias(alias.name, alias.expansion);
     }
     endInsertRows();
 }
 
-
 void AliasesModel::removeAlias(int index)
 {
     if (index < 0 || index >= rowCount())
         return;
 
-    AliasManager &manager = cloneAliasManager();
+    AliasManagermanager = cloneAliasManager();
     beginRemoveRows(QModelIndex(), index, index);
     manager.removeAt(index);
     endRemoveRows();
 }
 
-
-Qt::ItemFlags AliasesModel::flags(const QModelIndex &index) const
+Qt::ItemFlags AliasesModel::flags(const QModelIndex& index) const
 {
     if (!index.isValid()) {
         return Qt::ItemIsDropEnabled;
@@ -178,12 +222,10 @@ Qt::ItemFlags AliasesModel::flags(const QModelIndex &index) const
     }
 }
 
-
 QVariant AliasesModel::headerData(int section, Qt::Orientation orientation, int role) const
 {
     QStringList header;
-    header << tr("Alias")
-           << tr("Expansion");
+    header << tr("Alias") << tr("Expansion");
 
     if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
         return header[section];
@@ -191,68 +233,55 @@ QVariant AliasesModel::headerData(int section, Qt::Orientation orientation, int
     return QVariant();
 }
 
-
-QModelIndex AliasesModel::index(int row, int column, const QModelIndex &parent) const
+QModelIndex AliasesModel::index(int row, int column, const QModelIndex& parent) const
 {
     Q_UNUSED(parent);
     if (row >= rowCount() || column >= columnCount())
-        return QModelIndex();
+        return {};
 
     return createIndex(row, column);
 }
 
-
-const AliasManager &AliasesModel::aliasManager() const
+const AliasManager& AliasesModel::aliasManager() const
 {
-    if (_configChanged)
-        return _clonedAliasManager;
-    else
-        return *Client::aliasManager();
+    return _clonedAliasManager ? *_clonedAliasManager : *Client::aliasManager();
 }
 
-
-AliasManager &AliasesModel::aliasManager()
+AliasManager& AliasesModel::aliasManager()
 {
-    if (_configChanged)
-        return _clonedAliasManager;
-    else
-        return *Client::aliasManager();
+    return _clonedAliasManager ? *_clonedAliasManager : *Client::aliasManager();
 }
 
-
-AliasManager &AliasesModel::cloneAliasManager()
+AliasManager& AliasesModel::cloneAliasManager()
 {
-    if (!_configChanged) {
-        _clonedAliasManager = *Client::aliasManager();
-        _configChanged = true;
+    if (!_clonedAliasManager) {
+        _clonedAliasManager = std::make_unique<ClientAliasManager>();
+        _clonedAliasManager->fromVariantMap(Client::aliasManager()->toVariantMap());
         emit configChanged(true);
     }
-    return _clonedAliasManager;
+    return *_clonedAliasManager;
 }
 
-
 void AliasesModel::revert()
 {
-    if (!_configChanged)
+    if (!_clonedAliasManager)
         return;
 
-    _configChanged = false;
-    emit configChanged(false);
     beginResetModel();
+    _clonedAliasManager.reset();
     endResetModel();
+    emit configChanged(false);
 }
 
-
 void AliasesModel::commit()
 {
-    if (!_configChanged)
+    if (!_clonedAliasManager)
         return;
 
-    Client::aliasManager()->requestUpdate(_clonedAliasManager.toVariantMap());
+    Client::aliasManager()->requestUpdate(_clonedAliasManager->toVariantMap());
     revert();
 }
 
-
 void AliasesModel::initDone()
 {
     _modelReady = true;
@@ -261,23 +290,20 @@ void AliasesModel::initDone()
     emit modelReady(true);
 }
 
-
 void AliasesModel::clientConnected()
 {
-    connect(Client::aliasManager(), SIGNAL(updated()), SLOT(revert()));
+    connect(Client::aliasManager(), &AliasManager::updated, this, &AliasesModel::revert);
     if (Client::aliasManager()->isInitialized())
         initDone();
     else
-        connect(Client::aliasManager(), SIGNAL(initDone()), SLOT(initDone()));
+        connect(Client::aliasManager(), &SyncableObject::initDone, this, &AliasesModel::initDone);
 }
 
-
 void AliasesModel::clientDisconnected()
 {
-    // clear
-    _clonedAliasManager = ClientAliasManager();
     _modelReady = false;
     beginResetModel();
+    _clonedAliasManager.reset();
     endResetModel();
     emit modelReady(false);
 }