File indexing completed on 2022-09-27 16:33:57

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