File indexing completed on 2024-05-12 16:40:01
0001 /* This file is part of the KDE project 0002 Copyright (C) 2004-2016 Jarosław Staniek <staniek@kde.org> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "kexifinddialog.h" 0021 #include <kexiutils/utils.h> 0022 0023 #include <KStandardGuiItem> 0024 #include <KStandardAction> 0025 #include <KComboBox> 0026 #include <KConfigGroup> 0027 #include <KSharedConfig> 0028 #include <KLocalizedString> 0029 0030 #include <QDebug> 0031 #include <QDialog> 0032 #include <QCheckBox> 0033 #include <QLayout> 0034 #include <QList> 0035 #include <QShortcut> 0036 #include <QPointer> 0037 #include <QAction> 0038 #include <QDesktopWidget> 0039 #include <QKeyEvent> 0040 0041 #include <kexi_global.h> 0042 0043 //! @internal 0044 class Q_DECL_HIDDEN KexiFindDialog::Private 0045 { 0046 public: 0047 Private() : 0048 confGroup(KSharedConfig::openConfig()->group("FindDialog")) 0049 { 0050 } 0051 ~Private() { 0052 qDeleteAll(shortcuts); 0053 shortcuts.clear(); 0054 } 0055 //! Connects action \a action with appropriate signal \a member 0056 //! and optionally adds shortcut that will receive shortcut for \a action 0057 //! at global scope of the dialog \a parent. 0058 void setActionAndShortcut(QAction *action, QWidget* parent, const char* member) { 0059 //! @todo KEXI3 not tested: setActionAndShortcut::setActionAndShortcut() 0060 if (!action) 0061 return; 0062 QObject::connect(parent, member, action, SLOT(trigger())); 0063 if (action->shortcut().isEmpty()) 0064 return; 0065 // we want to handle dialog-wide shortcut as well 0066 if (!action->shortcut().isEmpty()) { 0067 QShortcut *shortcut = new QShortcut(action->shortcut(), parent, member); 0068 shortcuts.append(shortcut); 0069 } 0070 } 0071 0072 QStringList lookInColumnNames; 0073 QStringList lookInColumnCaptions; 0074 QString objectName; //!< for caption 0075 QPointer<QAction> findnextAction; 0076 QPointer<QAction> findprevAction; 0077 QPointer<QAction> replaceAction; 0078 QPointer<QAction> replaceallAction; 0079 QList<QShortcut*> shortcuts; 0080 KConfigGroup confGroup; 0081 bool replaceMode; 0082 }; 0083 0084 //------------------------------------------ 0085 0086 KexiFindDialog::KexiFindDialog(QWidget* parent) 0087 : QDialog(parent, 0088 Qt::Dialog | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::Tool 0089 | Qt::WindowCloseButtonHint) 0090 , d(new Private()) 0091 { 0092 setObjectName("KexiFindDialog"); 0093 setupUi(this); 0094 m_search->setCurrentIndex( 0095 (int)KexiSearchAndReplaceViewInterface::Options::SearchDown); 0096 layout()->setMargin(KexiUtils::marginHint()); 0097 layout()->setSpacing(KexiUtils::spacingHint()); 0098 QAction *a = KStandardAction::findNext(0, 0, 0); 0099 m_btnFind->setText(a->text()); 0100 m_btnFind->setIcon(a->icon()); 0101 delete a; 0102 connect(m_btnFind, SIGNAL(clicked()), this, SIGNAL(findNext())); 0103 connect(m_btnReplace, SIGNAL(clicked()), this, SIGNAL(replaceNext())); 0104 connect(m_btnReplaceAll, SIGNAL(clicked()), this, SIGNAL(replaceAll())); 0105 connect(m_textToFind, SIGNAL(activated(int)), this, SLOT(addToFindHistory())); 0106 connect(m_btnFind, SIGNAL(clicked()), this, SLOT(addToFindHistory())); 0107 connect(m_textToReplace, SIGNAL(activated(int)), this, SLOT(addToReplaceHistory())); 0108 connect(m_btnReplace, SIGNAL(clicked()), this, SLOT(addToReplaceHistory())); 0109 connect(m_btnReplaceAll, SIGNAL(clicked()), this, SLOT(addToReplaceHistory())); 0110 // clear message after the text is changed 0111 connect(m_textToFind, SIGNAL(editTextChanged(QString)), this, SLOT(updateMessage(QString))); 0112 connect(m_textToReplace, SIGNAL(editTextChanged(QString)), this, SLOT(updateMessage(QString))); 0113 0114 d->replaceMode = true; //to force updating by setReplaceMode() 0115 setReplaceMode(false); 0116 0117 setLookInColumnList(QStringList(), QStringList()); 0118 0119 QRect g = d->confGroup.readEntry("Geometry", QRect()); 0120 updateGeometry(); 0121 #ifndef Q_OS_WIN // not needed for Windows: this kind of dialog is centered by default 0122 if (g.isNull()) { 0123 g = geometry(); 0124 g.moveCenter((parentWidget() ? parentWidget()->geometry() 0125 : QApplication::desktop()->availableGeometry(this)).center()); 0126 } 0127 #endif 0128 if (!g.isNull()) { 0129 setGeometry(g); 0130 } 0131 } 0132 0133 KexiFindDialog::~KexiFindDialog() 0134 { 0135 d->confGroup.writeEntry("Geometry", geometry()); 0136 delete d; 0137 } 0138 0139 void KexiFindDialog::setActions(QAction *findnext, QAction *findprev, 0140 QAction *replace, QAction *replaceall) 0141 { 0142 d->findnextAction = findnext; 0143 d->findprevAction = findprev; 0144 d->replaceAction = replace; 0145 d->replaceallAction = replaceall; 0146 qDeleteAll(d->shortcuts); 0147 d->setActionAndShortcut(d->findnextAction, this, SIGNAL(findNext())); 0148 d->setActionAndShortcut(d->findprevAction, this, SIGNAL(findPrevious())); 0149 d->setActionAndShortcut(d->replaceAction, this, SIGNAL(replaceNext())); 0150 d->setActionAndShortcut(d->replaceallAction, this, SIGNAL(replaceAll())); 0151 } 0152 0153 QStringList KexiFindDialog::lookInColumnNames() const 0154 { 0155 return d->lookInColumnNames; 0156 } 0157 0158 QStringList KexiFindDialog::lookInColumnCaptions() const 0159 { 0160 return d->lookInColumnCaptions; 0161 } 0162 0163 QString KexiFindDialog::currentLookInColumnName() const 0164 { 0165 int index = m_lookIn->currentIndex(); 0166 if (index <= 0 || index >= (int)d->lookInColumnNames.count()) 0167 return QString(); 0168 else if (index == 1) 0169 return "(field)"; 0170 return d->lookInColumnNames[index - 1/*"(All fields)"*/ - 1/*"(Current field)"*/]; 0171 } 0172 0173 QVariant KexiFindDialog::valueToFind() const 0174 { 0175 return m_textToFind->currentText(); 0176 } 0177 0178 QVariant KexiFindDialog::valueToReplaceWith() const 0179 { 0180 return m_textToReplace->currentText(); 0181 } 0182 0183 void KexiFindDialog::setLookInColumnList(const QStringList& columnNames, 0184 const QStringList& columnCaptions) 0185 { 0186 d->lookInColumnNames = columnNames; 0187 d->lookInColumnCaptions = columnCaptions; 0188 m_lookIn->clear(); 0189 m_lookIn->addItem(xi18n("(All fields)")); 0190 m_lookIn->addItem(xi18n("(Current field)")); 0191 m_lookIn->addItems(d->lookInColumnCaptions); 0192 } 0193 0194 void KexiFindDialog::setCurrentLookInColumnName(const QString& columnName) 0195 { 0196 int index; 0197 if (columnName.isEmpty()) 0198 index = 0; 0199 else if (columnName == "(field)") 0200 index = 1; 0201 else { 0202 index = d->lookInColumnNames.indexOf(columnName); 0203 if (index == -1) { 0204 qWarning() << QString( 0205 "KexiFindDialog::setCurrentLookInColumn(%1) column name not found on the list") 0206 .arg(columnName); 0207 return; 0208 } 0209 index = index + 1/*"(All fields)"*/ + 1/*"(Current field)"*/; 0210 } 0211 m_lookIn->setCurrentIndex(index); 0212 } 0213 0214 void KexiFindDialog::setReplaceMode(bool set) 0215 { 0216 if (d->replaceMode == set) 0217 return; 0218 d->replaceMode = set; 0219 if (d->replaceMode) { 0220 m_promptOnReplace->show(); 0221 m_replaceLbl->show(); 0222 m_textToReplace->show(); 0223 m_btnReplace->show(); 0224 m_btnReplaceAll->show(); 0225 } else { 0226 m_promptOnReplace->hide(); 0227 m_replaceLbl->hide(); 0228 m_textToReplace->hide(); 0229 m_btnReplace->hide(); 0230 m_btnReplaceAll->hide(); 0231 resize(width(), height() - 30); 0232 } 0233 setObjectNameForCaption(d->objectName); 0234 updateGeometry(); 0235 } 0236 0237 void KexiFindDialog::setObjectNameForCaption(const QString& name) 0238 { 0239 d->objectName = name; 0240 if (d->replaceMode) { 0241 if (name.isEmpty()) 0242 setWindowTitle(xi18nc("@title:window", "Replace")); 0243 else 0244 setWindowTitle(xi18nc("@title:window", "Replace in <resource>%1</resource>", name)); 0245 } else { 0246 if (name.isEmpty()) 0247 setWindowTitle(xi18nc("@title:window", "Find")); 0248 else 0249 setWindowTitle(xi18nc("@title:window", "Find in <resource>%1</resource>", name)); 0250 } 0251 } 0252 0253 void KexiFindDialog::setButtonsEnabled(bool enable) 0254 { 0255 m_btnFind->setEnabled(enable); 0256 m_btnReplace->setEnabled(enable); 0257 m_btnReplaceAll->setEnabled(enable); 0258 if (!enable) 0259 setObjectNameForCaption(QString()); 0260 } 0261 0262 void KexiFindDialog::setMessage(const QString& message) 0263 { 0264 m_messageLabel->setText(message); 0265 } 0266 0267 void KexiFindDialog::updateMessage(bool found) 0268 { 0269 if (found) 0270 setMessage(QString()); 0271 else 0272 setMessage(xi18n("The search item was not found")); 0273 } 0274 0275 void KexiFindDialog::addToFindHistory() 0276 { 0277 m_textToFind->addToHistory(m_textToFind->currentText()); 0278 } 0279 0280 void KexiFindDialog::addToReplaceHistory() 0281 { 0282 m_textToReplace->addToHistory(m_textToReplace->currentText()); 0283 } 0284 0285 void KexiFindDialog::show() 0286 { 0287 m_textToFind->setFocus(); 0288 QDialog::show(); 0289 } 0290 0291 KexiSearchAndReplaceViewInterface::Options KexiFindDialog::options() const 0292 { 0293 KexiSearchAndReplaceViewInterface::Options options; 0294 if (m_lookIn->currentIndex() <= 0) //"(All fields)" 0295 options.columnNumber = KexiSearchAndReplaceViewInterface::Options::AllColumns; 0296 else if (m_lookIn->currentIndex() == 1) //"(Current field)" 0297 options.columnNumber = KexiSearchAndReplaceViewInterface::Options::CurrentColumn; 0298 else 0299 options.columnNumber = m_lookIn->currentIndex() - 1/*"(All fields)"*/ - 1/*"(Current field)"*/; 0300 options.textMatching 0301 = (KexiSearchAndReplaceViewInterface::Options::TextMatching)m_match->currentIndex(); 0302 options.searchDirection 0303 = (KexiSearchAndReplaceViewInterface::Options::SearchDirection)m_search->currentIndex(); 0304 options.caseSensitive = m_caseSensitive->isChecked(); 0305 options.wholeWordsOnly = m_wholeWords->isChecked(); 0306 options.promptOnReplace = m_promptOnReplace->isChecked(); 0307 return options; 0308 } 0309 0310 bool KexiFindDialog::event(QEvent *e) 0311 { 0312 if (e->type() == QEvent::ShortcutOverride && static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape 0313 && static_cast<QKeyEvent*>(e)->modifiers() == Qt::NoModifier) 0314 { 0315 reject(); 0316 return true; 0317 } 0318 return QDialog::event(e); 0319 }