File indexing completed on 2024-05-05 05:00:08
0001 /* 0002 SPDX-FileCopyrightText: 2005 Ivor Hewitt <ivor@ivor.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 // Own 0008 #include "filteropts.h" 0009 0010 // Qt 0011 #include <QRegularExpression> 0012 #include <QTextStream> 0013 #include <QDBusConnection> 0014 #include <QDBusMessage> 0015 #include <QCheckBox> 0016 #include <QLabel> 0017 #include <QTreeView> 0018 #include <QWhatsThis> 0019 #include <QVBoxLayout> 0020 #include <QHBoxLayout> 0021 #include <QListWidget> 0022 #include <QPushButton> 0023 #include <QUrl> 0024 #include <QFileDialog> 0025 0026 // KDE 0027 #include <kaboutdata.h> 0028 #include <kconfig.h> 0029 #include <KLocalizedString> 0030 #include <KPluginFactory> 0031 #include <klistwidgetsearchline.h> 0032 #include <klineedit.h> 0033 #include <kpluralhandlingspinbox.h> 0034 #include <KConfigGroup> 0035 #include <KSharedConfig> 0036 0037 KCMFilter::KCMFilter(QObject *parent, const KPluginMetaData &md, const QVariantList &) 0038 : KCModule(parent, md), 0039 mGroupname(QStringLiteral("Filter Settings")), 0040 mSelCount(0), 0041 mOriginalString(QString()) 0042 { 0043 mConfig = KSharedConfig::openConfig(QStringLiteral("khtmlrc"), KConfig::NoGlobals); 0044 setButtons(Default | Apply | Help); 0045 0046 QVBoxLayout *topLayout = new QVBoxLayout(widget()); 0047 0048 mEnableCheck = new QCheckBox(i18n("Enable filters"), widget()); 0049 topLayout->addWidget(mEnableCheck); 0050 0051 mKillCheck = new QCheckBox(i18n("Hide filtered images"), widget()); 0052 topLayout->addWidget(mKillCheck); 0053 0054 mFilterWidget = new QTabWidget(widget()); 0055 topLayout->addWidget(mFilterWidget); 0056 0057 QWidget *container = new QWidget(mFilterWidget); 0058 mFilterWidget->addTab(container, i18n("Manual Filter")); 0059 0060 QVBoxLayout *vbox = new QVBoxLayout; 0061 0062 mListBox = new QListWidget; 0063 mListBox->setSelectionMode(QListWidget::ExtendedSelection); 0064 0065 // If the filter list were sensitive to ordering, then we would need to 0066 // preserve the order of items inserted or arranged by the user (and the 0067 // GUI would need "Move Up" and "Move Down" buttons to reorder the filters). 0068 // However, now the filters are applied in an unpredictable order because 0069 // of the new hashed matching algorithm. So the list can stay sorted. 0070 mListBox->setSortingEnabled(true); 0071 0072 QWidget *searchBox = new QWidget; 0073 QHBoxLayout *searchBoxHBoxLayout = new QHBoxLayout(searchBox); 0074 searchBoxHBoxLayout->setContentsMargins(0, 0, 0, 0); 0075 searchBoxHBoxLayout->setSpacing(-1); 0076 new QLabel(i18n("Search:"), searchBox); 0077 0078 mSearchLine = new KListWidgetSearchLine(searchBox, mListBox); 0079 0080 vbox->addWidget(searchBox); 0081 0082 vbox->addWidget(mListBox); 0083 0084 QLabel *exprLabel = new QLabel(i18n("<qt>Filter expression (e.g. <tt>http://www.example.com/ad/*</tt>, <a href=\"filterhelp\">more information</a>):"), widget()); 0085 connect(exprLabel, &QLabel::linkActivated, this, &KCMFilter::slotInfoLinkActivated); 0086 vbox->addWidget(exprLabel); 0087 0088 mString = new KLineEdit; 0089 vbox->addWidget(mString); 0090 0091 QWidget *buttonBox = new QWidget; 0092 QHBoxLayout *buttonBoxHBoxLayout = new QHBoxLayout(buttonBox); 0093 buttonBoxHBoxLayout->setContentsMargins(0, 0, 0, 0); 0094 vbox->addWidget(buttonBox); 0095 0096 container->setLayout(vbox); 0097 0098 /** tab for automatic filter lists */ 0099 container = new QWidget(mFilterWidget); 0100 mFilterWidget->addTab(container, i18n("Automatic Filter")); 0101 QGridLayout *grid = new QGridLayout; 0102 grid->setColumnStretch(2, 1); 0103 container->setLayout(grid); 0104 0105 mAutomaticFilterList = new QTreeView(container); 0106 mAutomaticFilterList->setModel(&mAutomaticFilterModel); 0107 grid->addWidget(mAutomaticFilterList, 0, 0, 1, 3); 0108 0109 QLabel *label = new QLabel(i18n("Automatic update interval:"), container); 0110 grid->addWidget(label, 1, 0); 0111 mRefreshFreqSpinBox = new KPluralHandlingSpinBox(container); 0112 grid->addWidget(mRefreshFreqSpinBox, 1, 1); 0113 mRefreshFreqSpinBox->setRange(1, 365); 0114 mRefreshFreqSpinBox->setSuffix(ki18np(" day", " days")); 0115 0116 /** connect signals and slots */ 0117 #if QT_VERSION_MAJOR < 6 0118 connect(&mAutomaticFilterModel, &AutomaticFilterModel::changed, this, QOverload<bool>::of(&KCModule::changed)); 0119 #else 0120 connect(&mAutomaticFilterModel, &AutomaticFilterModel::changed, this, [this](bool changed){setNeedsSave(changed);}); 0121 #endif 0122 connect(mRefreshFreqSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &KCMFilter::spinBoxChanged); 0123 0124 mInsertButton = new QPushButton(QIcon::fromTheme(QStringLiteral("list-add")), i18n("Insert"), buttonBox); 0125 buttonBoxHBoxLayout->addWidget(mInsertButton); 0126 connect(mInsertButton, &QAbstractButton::clicked, this, &KCMFilter::insertFilter); 0127 mUpdateButton = new QPushButton(QIcon::fromTheme(QStringLiteral("document-edit")), i18n("Update"), buttonBox); 0128 buttonBoxHBoxLayout->addWidget(mUpdateButton); 0129 connect(mUpdateButton, &QAbstractButton::clicked, this, &KCMFilter::updateFilter); 0130 mRemoveButton = new QPushButton(QIcon::fromTheme(QStringLiteral("list-remove")), i18n("Remove"), buttonBox); 0131 buttonBoxHBoxLayout->addWidget(mRemoveButton); 0132 connect(mRemoveButton, &QAbstractButton::clicked, this, &KCMFilter::removeFilter); 0133 0134 mImportButton = new QPushButton(QIcon::fromTheme(QStringLiteral("document-import")), i18n("Import..."), buttonBox); 0135 buttonBoxHBoxLayout->addWidget(mImportButton); 0136 connect(mImportButton, &QAbstractButton::clicked, this, &KCMFilter::importFilters); 0137 mExportButton = new QPushButton(QIcon::fromTheme(QStringLiteral("document-export")), i18n("Export..."), buttonBox); 0138 buttonBoxHBoxLayout->addWidget(mExportButton); 0139 connect(mExportButton, &QAbstractButton::clicked, this, &KCMFilter::exportFilters); 0140 0141 QWidget *impexpBox = new QWidget; 0142 QHBoxLayout *impexpBoxHBoxLayout = new QHBoxLayout(impexpBox); 0143 impexpBoxHBoxLayout->setContentsMargins(0, 0, 0, 0); 0144 QLabel *impexpLabel = new QLabel(i18n("<qt>More information on " 0145 "<a href=\"importhelp\">import format</a>, " 0146 "<a href=\"exporthelp\">export format</a>"), impexpBox); 0147 connect(impexpLabel, &QLabel::linkActivated, this, &KCMFilter::slotInfoLinkActivated); 0148 impexpBoxHBoxLayout->addWidget(impexpLabel); 0149 vbox->addWidget(impexpBox, 0, Qt::AlignRight); 0150 0151 connect(mEnableCheck, &QAbstractButton::toggled, this, &KCMFilter::slotEnableChecked); 0152 connect(mKillCheck, &QAbstractButton::clicked, this, &KCMFilter::slotKillChecked); 0153 connect(mListBox, &QListWidget::itemSelectionChanged, this, &KCMFilter::slotItemSelected); 0154 connect(mString, &QLineEdit::textChanged, this, &KCMFilter::updateButton); 0155 /* 0156 * Whats this items 0157 */ 0158 mEnableCheck->setToolTip(i18n("Enable or disable AdBlocK filters. When enabled, a set of URL expressions " 0159 "should be defined in the filter list for blocking to take effect.")); 0160 mKillCheck->setToolTip(i18n("When enabled blocked images will be removed from the page completely, " 0161 "otherwise a placeholder 'blocked' image will be used.")); 0162 0163 // The list is no longer sensitive to order, because of the new hashed 0164 // matching. So this tooltip doesn't imply that. 0165 // 0166 // FIXME: blocking of frames is not currently implemented by KHTML 0167 mListBox->setToolTip(i18n("This is the list of URL filters that will be applied to all embedded " 0168 "images and media objects.")); 0169 // "images, objects and frames.") ); 0170 0171 mString->setToolTip(i18n("<qt><p>Enter an expression to filter. Filters can be defined as either:" 0172 "<ul><li>a shell-style wildcard, e.g. <tt>http://www.example.com/ads*</tt>, the wildcards <tt>*?[]</tt> may be used</li>" 0173 "<li>a full regular expression by surrounding the string with '<tt>/</tt>', e.g. <tt>/\\/(ad|banner)\\./</tt></li></ul>" 0174 "<p>Any filter string can be preceded by '<tt>@@</tt>' to whitelist (allow) any matching URL, " 0175 "which takes priority over any blacklist (blocking) filter.")); 0176 } 0177 0178 KCMFilter::~KCMFilter() 0179 { 0180 } 0181 0182 void KCMFilter::slotInfoLinkActivated(const QString &url) 0183 { 0184 if (url == QLatin1String("filterhelp")) { 0185 QWhatsThis::showText(QCursor::pos(), mString->toolTip()); 0186 } else if (url == QLatin1String("importhelp")) 0187 QWhatsThis::showText(QCursor::pos(), i18n("<qt><p>The filter import format is a plain text file. " 0188 "Blank lines, comment lines starting with '<tt>!</tt>' " 0189 "and the header line <tt>[AdBlock]</tt> are ignored. " 0190 "Any other line is added as a filter expression.")); 0191 else if (url == QLatin1String("exporthelp")) 0192 QWhatsThis::showText(QCursor::pos(), i18n("<qt><p>The filter export format is a plain text file. " 0193 "The file begins with a header line <tt>[AdBlock]</tt>, then all of " 0194 "the filters follow each on a separate line.")); 0195 } 0196 0197 void KCMFilter::slotKillChecked() 0198 { 0199 setNeedsSave(true); 0200 } 0201 0202 void KCMFilter::slotEnableChecked() 0203 { 0204 updateButton(); 0205 setNeedsSave(true); 0206 } 0207 0208 void KCMFilter::slotItemSelected() 0209 { 0210 int currentId = -1; 0211 int i; 0212 for (i = 0, mSelCount = 0; i < mListBox->count() && mSelCount < 2; ++i) { 0213 if (mListBox->item(i)->isSelected()) { 0214 currentId = i; 0215 mSelCount++; 0216 } 0217 } 0218 0219 if (currentId >= 0) { 0220 mOriginalString = mListBox->item(currentId)->text(); 0221 mString->setText(mOriginalString); 0222 mString->setFocus(Qt::OtherFocusReason); 0223 } 0224 updateButton(); 0225 } 0226 0227 void KCMFilter::updateButton() 0228 { 0229 bool state = mEnableCheck->isChecked(); 0230 bool expressionIsNotEmpty = !mString->text().isEmpty(); 0231 bool filterEdited = expressionIsNotEmpty && mOriginalString != mString->text(); 0232 0233 mInsertButton->setEnabled(state && expressionIsNotEmpty && filterEdited); 0234 mUpdateButton->setEnabled(state && (mSelCount == 1) && expressionIsNotEmpty && filterEdited); 0235 mRemoveButton->setEnabled(state && (mSelCount > 0)); 0236 mImportButton->setEnabled(state); 0237 mExportButton->setEnabled(state && mListBox->count() > 0); 0238 0239 mListBox->setEnabled(state); 0240 mString->setEnabled(state); 0241 mKillCheck->setEnabled(state); 0242 0243 if (filterEdited) { 0244 if (mSelCount == 1 && mUpdateButton->isEnabled()) { 0245 mUpdateButton->setDefault(true); 0246 } else if (mInsertButton->isEnabled()) { 0247 mInsertButton->setDefault(true); 0248 } 0249 } else { 0250 mInsertButton->setDefault(false); 0251 mUpdateButton->setDefault(false); 0252 } 0253 0254 mAutomaticFilterList->setEnabled(state); 0255 mRefreshFreqSpinBox->setEnabled(state); 0256 } 0257 0258 void KCMFilter::importFilters() 0259 { 0260 QString inFile = QFileDialog::getOpenFileName(widget(), i18n("Import Filters")); 0261 if (!inFile.isEmpty()) { 0262 QFile f(inFile); 0263 if (f.open(QIODevice::ReadOnly)) { 0264 QTextStream ts(&f); 0265 QStringList paths; 0266 QString line; 0267 while (!ts.atEnd()) { 0268 line = ts.readLine(); 0269 if (line.isEmpty() || line.compare(QLatin1String("[adblock]"), Qt::CaseInsensitive) == 0) { 0270 continue; 0271 } 0272 0273 // Treat leading ! as filter comment, otherwise check expressions 0274 // are valid. 0275 if (!line.startsWith(QLatin1String("!"))) { //krazy:exclude=doublequote_chars 0276 if (line.length() > 2 && line[0] == '/' && line[line.length() - 1] == '/') { 0277 QString inside = line.mid(1, line.length() - 2); 0278 QRegularExpression rx(inside); 0279 if (!rx.isValid()) { 0280 continue; 0281 } 0282 } else { 0283 QRegularExpression rx(QRegularExpression::wildcardToRegularExpression(line)); 0284 if (!rx.isValid()) { 0285 continue; 0286 } 0287 } 0288 0289 if (mListBox->findItems(line, Qt::MatchCaseSensitive | Qt::MatchExactly).isEmpty()) { 0290 paths.append(line); 0291 } 0292 } 0293 } 0294 f.close(); 0295 0296 mListBox->addItems(paths); 0297 setNeedsSave(true); 0298 } 0299 } 0300 } 0301 0302 void KCMFilter::exportFilters() 0303 { 0304 QString outFile = QFileDialog::getSaveFileName(widget(), i18n("Export Filters")); 0305 if (!outFile.isEmpty()) { 0306 0307 QFile f(outFile); 0308 if (f.open(QIODevice::WriteOnly)) { 0309 QTextStream ts(&f); 0310 #if QT_VERSION_MAJOR < 6 0311 ts.setCodec("UTF-8"); 0312 #endif 0313 ts << "[AdBlock]" << Qt::endl; 0314 0315 int nbLine = mListBox->count(); 0316 for (int i = 0; i < nbLine; ++i) { 0317 ts << mListBox->item(i)->text() << Qt::endl; 0318 } 0319 0320 f.close(); 0321 } 0322 } 0323 } 0324 0325 void KCMFilter::defaults() 0326 { 0327 mAutomaticFilterModel.defaults(); 0328 0329 mListBox->clear(); 0330 mEnableCheck->setChecked(false); 0331 mKillCheck->setChecked(false); 0332 mString->clear(); 0333 updateButton(); 0334 0335 #if QT_VERSION_MAJOR > 5 0336 setRepresentsDefaults(true); 0337 #endif 0338 } 0339 0340 void KCMFilter::save() 0341 { 0342 KConfigGroup cg(mConfig, mGroupname); 0343 cg.deleteGroup(); 0344 cg = KConfigGroup(mConfig, mGroupname); 0345 0346 cg.writeEntry("Enabled", mEnableCheck->isChecked()); 0347 cg.writeEntry("Shrink", mKillCheck->isChecked()); 0348 0349 int i; 0350 for (i = 0; i < mListBox->count(); ++i) { 0351 QString key = "Filter-" + QString::number(i); 0352 cg.writeEntry(key, mListBox->item(i)->text()); 0353 } 0354 cg.writeEntry("Count", mListBox->count()); 0355 0356 mAutomaticFilterModel.save(cg); 0357 cg.writeEntry("HTMLFilterListMaxAgeDays", mRefreshFreqSpinBox->value()); 0358 0359 cg.sync(); 0360 0361 QDBusMessage message = 0362 QDBusMessage::createSignal(QStringLiteral("/KonqMain"), QStringLiteral("org.kde.Konqueror.Main"), QStringLiteral("reparseConfiguration")); 0363 QDBusConnection::sessionBus().send(message); 0364 0365 KCModule::save(); 0366 } 0367 0368 void KCMFilter::load() 0369 { 0370 QStringList paths; 0371 0372 KConfigGroup cg(mConfig, mGroupname); 0373 mAutomaticFilterModel.load(cg); 0374 mAutomaticFilterList->resizeColumnToContents(0); 0375 int refreshFreq = cg.readEntry("HTMLFilterListMaxAgeDays", 7); 0376 mRefreshFreqSpinBox->setValue(refreshFreq < 1 ? 1 : refreshFreq); 0377 0378 mEnableCheck->setChecked(cg.readEntry("Enabled", false)); 0379 mKillCheck->setChecked(cg.readEntry("Shrink", false)); 0380 0381 QMap<QString, QString> entryMap = cg.entryMap(); 0382 QMap<QString, QString>::ConstIterator it; 0383 int num = cg.readEntry("Count", 0); 0384 for (int i = 0; i < num; ++i) { 0385 QString key = "Filter-" + QString::number(i); 0386 it = entryMap.constFind(key); 0387 if (it != entryMap.constEnd()) { 0388 paths.append(it.value()); 0389 } 0390 } 0391 0392 mListBox->addItems(paths); 0393 updateButton(); 0394 KCModule::load(); 0395 } 0396 0397 void KCMFilter::insertFilter() 0398 { 0399 QString newFilter = mString->text(); 0400 0401 if (!newFilter.isEmpty() && mListBox->findItems(newFilter, Qt::MatchCaseSensitive | Qt::MatchExactly).isEmpty()) { 0402 mListBox->clearSelection(); 0403 mListBox->addItem(newFilter); 0404 0405 // The next line assumed that the new item would be added at the end 0406 // of the list, but that may not be the case if sorting is enabled. 0407 // So we search again to locate the just-added item. 0408 //int id = mListBox->count()-1; 0409 QListWidgetItem *newItem = mListBox->findItems(newFilter, Qt::MatchCaseSensitive | Qt::MatchExactly).first(); 0410 if (newItem != nullptr) { 0411 int id = mListBox->row(newItem); 0412 0413 mListBox->item(id)->setSelected(true); 0414 mListBox->setCurrentRow(id); 0415 } 0416 0417 updateButton(); 0418 setNeedsSave(true); 0419 } 0420 } 0421 0422 void KCMFilter::removeFilter() 0423 { 0424 for (int i = mListBox->count(); i >= 0; --i) { 0425 if (mListBox->item(i) && mListBox->item(i)->isSelected()) { 0426 delete mListBox->takeItem(i); 0427 } 0428 } 0429 mString->clear(); 0430 setNeedsSave(true); 0431 updateButton(); 0432 } 0433 0434 void KCMFilter::updateFilter() 0435 { 0436 if (!mString->text().isEmpty()) { 0437 int index = mListBox->currentRow(); 0438 if (index >= 0) { 0439 mListBox->item(index)->setText(mString->text()); 0440 setNeedsSave(true); 0441 } 0442 } 0443 updateButton(); 0444 } 0445 0446 void KCMFilter::spinBoxChanged(int) 0447 { 0448 setNeedsSave(true); 0449 } 0450 0451 AutomaticFilterModel::AutomaticFilterModel(QObject *parent) 0452 : QAbstractItemModel(parent), 0453 mGroupname(QStringLiteral("Filter Settings")) 0454 { 0455 //mConfig = KSharedConfig::openConfig("khtmlrc", KConfig::NoGlobals); 0456 mConfig = KSharedConfig::openConfig(QStringLiteral("khtmlrc"), KConfig::IncludeGlobals); 0457 } 0458 0459 void AutomaticFilterModel::load(KConfigGroup &cg) 0460 { 0461 beginResetModel(); 0462 mFilters.clear(); 0463 const int maxNumFilters = 1024; 0464 const bool defaultHTMLFilterListEnabled = false; 0465 0466 for (int numFilters = 1; numFilters < maxNumFilters; ++numFilters) { 0467 struct FilterConfig filterConfig; 0468 filterConfig.filterName = cg.readEntry(QStringLiteral("HTMLFilterListName-") + QString::number(numFilters), ""); 0469 if (filterConfig.filterName == QLatin1String("")) { 0470 break; 0471 } 0472 0473 filterConfig.enableFilter = cg.readEntry(QStringLiteral("HTMLFilterListEnabled-") + QString::number(numFilters), defaultHTMLFilterListEnabled); 0474 filterConfig.filterURL = cg.readEntry(QStringLiteral("HTMLFilterListURL-") + QString::number(numFilters), ""); 0475 filterConfig.filterLocalFilename = cg.readEntry(QStringLiteral("HTMLFilterListLocalFilename-") + QString::number(numFilters), ""); 0476 0477 mFilters << filterConfig; 0478 } 0479 endResetModel(); 0480 } 0481 0482 void AutomaticFilterModel::save(KConfigGroup &cg) 0483 { 0484 for (int i = mFilters.count() - 1; i >= 0; --i) { 0485 cg.writeEntry(QStringLiteral("HTMLFilterListLocalFilename-") + QString::number(i + 1), mFilters[i].filterLocalFilename); 0486 cg.writeEntry(QStringLiteral("HTMLFilterListURL-") + QString::number(i + 1), mFilters[i].filterURL); 0487 cg.writeEntry(QStringLiteral("HTMLFilterListName-") + QString::number(i + 1), mFilters[i].filterName); 0488 cg.writeEntry(QStringLiteral("HTMLFilterListEnabled-") + QString::number(i + 1), mFilters[i].enableFilter); 0489 } 0490 } 0491 0492 void AutomaticFilterModel::defaults() 0493 { 0494 mConfig = KSharedConfig::openConfig(QStringLiteral("khtmlrc"), KConfig::IncludeGlobals); 0495 KConfigGroup cg(mConfig, mGroupname); 0496 load(cg); 0497 } 0498 0499 QModelIndex AutomaticFilterModel::index(int row, int column, const QModelIndex & /*parent*/) const 0500 { 0501 return createIndex(row, column, (void *)nullptr); 0502 } 0503 0504 QModelIndex AutomaticFilterModel::parent(const QModelIndex & /*index*/) const 0505 { 0506 return QModelIndex(); 0507 } 0508 0509 bool AutomaticFilterModel::hasChildren(const QModelIndex &parent) const 0510 { 0511 return parent == QModelIndex(); 0512 } 0513 0514 int AutomaticFilterModel::rowCount(const QModelIndex & /*parent*/) const 0515 { 0516 return mFilters.count(); 0517 } 0518 0519 int AutomaticFilterModel::columnCount(const QModelIndex & /*parent*/) const 0520 { 0521 return 2; 0522 } 0523 0524 QVariant AutomaticFilterModel::data(const QModelIndex &index, int role) const 0525 { 0526 if (!index.isValid()) { 0527 return QVariant(); 0528 } 0529 0530 if (role == Qt::DisplayRole && index.row() < mFilters.count()) 0531 switch (index.column()) { 0532 case 0: return QVariant(mFilters[index.row()].filterName); 0533 case 1: return QVariant(mFilters[index.row()].filterURL); 0534 default: return QVariant("?"); 0535 } 0536 else if (role == Qt::CheckStateRole && index.column() == 0 && index.row() < mFilters.count()) { 0537 return mFilters[index.row()].enableFilter ? Qt::Checked : Qt::Unchecked; 0538 } else { 0539 return QVariant(); 0540 } 0541 0542 } 0543 0544 bool AutomaticFilterModel::setData(const QModelIndex &index, const QVariant &value, int role) 0545 { 0546 if (role == Qt::CheckStateRole && index.column() == 0 && index.row() < mFilters.count()) { 0547 mFilters[index.row()].enableFilter = static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked; 0548 emit dataChanged(index, index); 0549 emit changed(true); 0550 return true; 0551 } 0552 0553 return false; 0554 } 0555 0556 QVariant AutomaticFilterModel::headerData(int section, Qt::Orientation orientation, int role) const 0557 { 0558 if (role != Qt::DisplayRole || orientation != Qt::Horizontal) { 0559 return QVariant(); 0560 } 0561 0562 switch (section) { 0563 case 0: return QVariant(i18n("Name")); 0564 case 1: return QVariant(i18n("URL")); 0565 default: return QVariant("?"); 0566 } 0567 } 0568 0569 Qt::ItemFlags AutomaticFilterModel::flags(const QModelIndex &index) const 0570 { 0571 Qt::ItemFlags rc = Qt::ItemIsSelectable | Qt::ItemIsEnabled; 0572 if (index.column() == 0) { 0573 rc |= Qt::ItemIsUserCheckable; 0574 } 0575 return rc; 0576 }