File indexing completed on 2024-12-08 13:34:36

0001 /***************************************************************************
0002                        tokenhelpdialog.cpp  -  description
0003                              -------------------
0004     begin                : Mon Jul 30 2007
0005     copyright            : (C) 2007 by Dominik Seichter
0006     email                : domseichter@web.de
0007 ***************************************************************************/
0008 
0009 /***************************************************************************
0010  *                                                                         *
0011  *   This program is free software; you can redistribute it and/or modify  *
0012  *   it under the terms of the GNU General Public License as published by  *
0013  *   the Free Software Foundation; either version 2 of the License, or     *
0014  *   (at your option) any later version.                                   *
0015  *                                                                         *
0016  ***************************************************************************/
0017 
0018 #include "tokenhelpdialog.h"
0019 
0020 #include "batchrenamer.h"
0021 #include "krenamemodel.h"
0022 
0023 #include <kiconloader.h>
0024 #include <KSharedConfig>
0025 #include <KTreeWidgetSearchLine>
0026 #include <QPushButton>
0027 #include <KConfigGroup>
0028 #include <QDialogButtonBox>
0029 #include <QVBoxLayout>
0030 #include <QLineEdit>
0031 
0032 #define COLUMN_PREVIEW 2
0033 
0034 /**
0035  * A wrapper class for KRenameModel that
0036  * replaces display role with customer Qt::UserRole
0037  * so that the KRenameModel will always return unformatted
0038  * data, because QComboBox cannot display richtext.
0039  */
0040 class KRenameUnformattedWrappedModel : public QAbstractListModel
0041 {
0042 public:
0043     KRenameUnformattedWrappedModel(KRenameModel *model)
0044         : m_model(model)
0045     {
0046     }
0047 
0048     /** Get the file at position index.
0049      *
0050      *  @param a valid index in the internal vector
0051      *
0052      *  @returns a KRenameFile object
0053      */
0054     const KRenameFile &file(int index) const
0055     {
0056         return m_model->file(index);
0057     }
0058 
0059     /** Get the file at position index.
0060      *
0061      *  @param a valid index in the internal vector
0062      *
0063      *  @returns a KRenameFile object
0064      */
0065     KRenameFile &file(int index)
0066     {
0067         return m_model->file(index);
0068     }
0069 
0070     virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
0071     {
0072         if (role == Qt::DisplayRole) {
0073             return static_cast<KRenameModel *>(m_model)->data(index, Qt::UserRole);
0074         } else {
0075             return static_cast<KRenameModel *>(m_model)->data(index, role);
0076         }
0077     }
0078 
0079     virtual int rowCount(const QModelIndex &parent = QModelIndex()) const
0080     {
0081         return m_model->rowCount(parent);
0082     }
0083 
0084 private:
0085     KRenameModel *m_model;
0086 };
0087 
0088 const int TokenHelpDialog::S_MAX_RECENT = 10;
0089 
0090 TokenHelpDialog::TokenHelpDialog(KRenameModel *model, BatchRenamer *renamer,
0091                                  QLineEdit *edit, QWidget *parent)
0092     : QDialog(parent), m_edit(edit), m_renamer(renamer)
0093 {
0094     m_model = new KRenameUnformattedWrappedModel(model);
0095 
0096     QWidget *mainWidget = new QWidget(this);
0097     QVBoxLayout *mainLayout = new QVBoxLayout;
0098     setLayout(mainLayout);
0099     mainLayout->addWidget(mainWidget);
0100     m_widget.setupUi(mainWidget);
0101 
0102     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
0103     QPushButton *insert = new QPushButton;
0104     buttonBox->addButton(insert, QDialogButtonBox::ActionRole);
0105     this->connect(buttonBox, &QDialogButtonBox::accepted,
0106                   this, &TokenHelpDialog::accept);
0107     this->connect(buttonBox, &QDialogButtonBox::rejected,
0108                   this, &TokenHelpDialog::reject);
0109     mainLayout->addWidget(buttonBox);
0110     insert->setText(i18n("&Insert"));
0111 
0112     QPushButton *close = buttonBox->button(QDialogButtonBox::Close);
0113 
0114     m_widget.searchCategory->searchLine()->setTreeWidget(m_widget.listCategories);
0115     m_widget.searchToken   ->searchLine()->setTreeWidget(m_widget.listTokens);
0116     m_widget.comboPreview->setModel(m_model);
0117     m_widget.listTokens->sortItems(0, Qt::AscendingOrder);
0118 
0119     connect(insert, &QPushButton::clicked,
0120             this, &TokenHelpDialog::slotInsert);
0121     connect(close, &QPushButton::clicked,
0122             this, &TokenHelpDialog::saveConfig);
0123 
0124     connect(m_widget.listCategories, &QTreeWidget::itemClicked,
0125             this, &TokenHelpDialog::slotCategoryChanged);
0126     connect(m_widget.listTokens, &QTreeWidget::itemClicked,
0127             this, &TokenHelpDialog::slotInsert);
0128     connect(m_widget.checkPreview, &QCheckBox::clicked,
0129             this, &TokenHelpDialog::slotPreviewClicked);
0130     connect(m_widget.comboPreview, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
0131             this, &TokenHelpDialog::slotUpdatePreview);
0132 
0133     slotEnableControls();
0134     loadConfig();
0135 }
0136 
0137 TokenHelpDialog::~TokenHelpDialog()
0138 {
0139     delete m_model;
0140 }
0141 
0142 const QString TokenHelpDialog::getTokenSeparator()
0143 {
0144     return QString::fromLatin1(";;");
0145 }
0146 
0147 void TokenHelpDialog::add(const QString &headline, const QStringList &commands, const QPixmap &icon, bool first)
0148 {
0149     m_map[headline] = commands;
0150 
0151     QTreeWidgetItem *item = new QTreeWidgetItem(m_widget.listCategories);
0152     item->setText(0, headline);
0153     item->setIcon(0, icon);
0154 
0155     if (first) {
0156         m_first = headline;
0157     }
0158 }
0159 
0160 int TokenHelpDialog::exec()
0161 {
0162     addRecentTokens();
0163 
0164     m_widget.listCategories->sortItems(0, Qt::AscendingOrder);
0165 
0166     if (!m_lastSelected.isEmpty()) {
0167         selectCategory(m_lastSelected);
0168     } else if (!m_first.isEmpty()) {
0169         selectCategory(m_first);
0170     }
0171 
0172     return QDialog::exec();
0173 }
0174 
0175 void TokenHelpDialog::selectCategory(const QString &category)
0176 {
0177     for (int i = 0; i < m_widget.listCategories->topLevelItemCount(); i++)
0178         if (m_widget.listCategories->topLevelItem(i)->text(0) == category) {
0179             m_widget.listCategories->topLevelItem(i)->setSelected(true);
0180             this->slotCategoryChanged(m_widget.listCategories->topLevelItem(i));
0181             break;
0182         }
0183 }
0184 
0185 void TokenHelpDialog::slotCategoryChanged(QTreeWidgetItem *item)
0186 {
0187     m_widget.listTokens->clear();
0188 
0189     const QStringList &commands = m_map[item->text(0)];
0190     for (int i = 0; i < commands.count(); i++) {
0191         QTreeWidgetItem *item = new QTreeWidgetItem(m_widget.listTokens);
0192         item->setText(0, commands[i].section(getTokenSeparator(), 0, 0));
0193         item->setText(1, commands[i].section(getTokenSeparator(), 1, 1));
0194     }
0195 
0196     slotUpdatePreview();
0197 }
0198 
0199 void TokenHelpDialog::slotInsert()
0200 {
0201     QTreeWidgetItem *category = m_widget.listCategories->currentItem();
0202     if (category) {
0203         m_lastSelected = category->text(0);
0204     }
0205 
0206     QTreeWidgetItem *item = m_widget.listTokens->currentItem();
0207     if (item) {
0208         const QString &token = item->text(0);
0209         const QString &help = item->text(1);
0210 
0211         addToRecentTokens(token, help);
0212         saveConfig();
0213 
0214         m_edit->insert(token);
0215     }
0216 
0217     this->accept();
0218 }
0219 
0220 void TokenHelpDialog::loadConfig()
0221 {
0222     KSharedConfigPtr config = KSharedConfig::openConfig();
0223 
0224     KConfigGroup groupGui = config->group(QString("TokenHelpDialog"));
0225 
0226     m_lastSelected = groupGui.readEntry("LastSelectedCategory", m_lastSelected);
0227     m_recent = groupGui.readEntry("RecentTokens", m_recent);
0228 
0229     bool preview = groupGui.readEntry("Preview",  m_widget.checkPreview->isChecked());
0230     m_widget.checkPreview->setChecked(preview);
0231 
0232     int width = groupGui.readEntry("Column0", QVariant(m_widget.listTokens->columnWidth(0))).toInt();
0233     if (width > 0) {
0234         m_widget.listTokens->setColumnWidth(0, width);
0235     }
0236 
0237     width = groupGui.readEntry("Column1", QVariant(m_widget.listTokens->columnWidth(1))).toInt();
0238     if (width > 0) {
0239         m_widget.listTokens->setColumnWidth(1, width);
0240     }
0241 
0242     width = groupGui.readEntry("Column2", QVariant(m_widget.listTokens->columnWidth(2))).toInt();
0243     if (width > 0) {
0244         m_widget.listTokens->setColumnWidth(2, width);
0245     }
0246 
0247     restoreGeometry(groupGui.readEntry<QByteArray>("Geometry", QByteArray()));
0248 
0249     QList<int> sizes = groupGui.readEntry("Splitter", QList<int>());
0250     if (sizes.size() == 2) {
0251         m_widget.splitter->setSizes(sizes);
0252     }
0253 }
0254 
0255 void TokenHelpDialog::saveConfig()
0256 {
0257     KSharedConfigPtr config = KSharedConfig::openConfig();
0258 
0259     KConfigGroup groupGui = config->group(QString("TokenHelpDialog"));
0260 
0261     groupGui.writeEntry("Column0",  m_widget.listTokens->columnWidth(0));
0262     groupGui.writeEntry("Column1",  m_widget.listTokens->columnWidth(1));
0263     groupGui.writeEntry("Column2",  m_widget.listTokens->columnWidth(2));
0264     groupGui.writeEntry("Splitter", m_widget.splitter->sizes());
0265     groupGui.writeEntry("Preview",  m_widget.checkPreview->isChecked());
0266     groupGui.writeEntry("LastSelectedCategory", m_lastSelected);
0267     groupGui.writeEntry("RecentTokens", m_recent);
0268 
0269     groupGui.writeEntry("Geometry", saveGeometry());
0270 }
0271 
0272 void TokenHelpDialog::slotEnableControls()
0273 {
0274     m_widget.comboPreview->setEnabled(m_widget.checkPreview->isChecked());
0275     m_widget.labelPreview->setEnabled(m_widget.checkPreview->isChecked());
0276 }
0277 
0278 void TokenHelpDialog::slotPreviewClicked(bool bPreview)
0279 {
0280     slotEnableControls();
0281 
0282     if (bPreview) {
0283         m_widget.listTokens->setColumnHidden(COLUMN_PREVIEW, false);
0284         slotUpdatePreview();
0285 
0286         // make sure preview column is visible
0287         m_widget.listTokens->resizeColumnToContents(0);
0288         m_widget.listTokens->resizeColumnToContents(1);
0289     } else {
0290         m_widget.listTokens->setColumnHidden(COLUMN_PREVIEW, true);
0291     }
0292 }
0293 
0294 void TokenHelpDialog::slotUpdatePreview()
0295 {
0296     if (!m_widget.checkPreview->isChecked()) {
0297         return;
0298     }
0299 
0300     int index = m_widget.comboPreview->currentIndex();
0301     if (index >= 0 && m_widget.listCategories->currentItem() != nullptr) {
0302         QString       name   = m_widget.listCategories->currentItem()->text(0);
0303 
0304         const KRenameFile &file = m_model->file(index);
0305         QApplication::setOverrideCursor(Qt::WaitCursor);
0306 
0307         QString token;
0308         for (int i = 0; i < m_widget.listTokens->topLevelItemCount(); i++) {
0309             QTreeWidgetItem *item = m_widget.listTokens->topLevelItem(i);
0310             if (item) {
0311                 token = m_renamer->processString(item->text(0), file.srcFilename(), index);
0312                 item->setText(COLUMN_PREVIEW, token);
0313             }
0314         }
0315         QApplication::restoreOverrideCursor();
0316     }
0317 }
0318 
0319 void TokenHelpDialog::addRecentTokens()
0320 {
0321     const QPixmap &icon =
0322         KIconLoader::global()->loadIcon("document-open-recent", KIconLoader::NoGroup, KIconLoader::SizeSmall);
0323     this->add(i18n("Recent"), m_recent, icon);
0324 }
0325 
0326 void TokenHelpDialog::addToRecentTokens(const QString &token, const QString &help)
0327 {
0328     // 1. Check if m_recent contains token and remove it
0329     QStringList::iterator it = m_recent.begin();
0330     while (it != m_recent.end()) {
0331         if ((*it).startsWith(token + getTokenSeparator())) {
0332             m_recent.erase(it);
0333             break;
0334         }
0335 
0336         ++it;
0337     }
0338 
0339     // 2. remove first token if more than 10
0340     if (m_recent.count() >= S_MAX_RECENT) {
0341         m_recent.removeAt(0);
0342     }
0343 
0344     // 3. append token
0345     QString recent = token + getTokenSeparator() + help;
0346     m_recent << recent;
0347 }