File indexing completed on 2024-05-19 05:49:14
0001 /* 0002 SPDX-FileCopyrightText: 2007 Nicolas Ternisien <nicolas.ternisien@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "multipleFileList.h" 0008 0009 #include <QAction> 0010 #include <QHeaderView> 0011 #include <QPushButton> 0012 0013 #include <KLocalizedString> 0014 0015 #include <QFileInfo> 0016 #include <QIcon> 0017 0018 #include "defaults.h" 0019 0020 #include "ksystemlog_debug.h" 0021 0022 MultipleFileList::MultipleFileList(QWidget *parent, const QString &descriptionText) 0023 : QWidget(parent) 0024 , mFileListHelper(this) 0025 { 0026 qCDebug(KSYSTEMLOG) << "Initializing multiple file list..."; 0027 0028 setupUi(this); 0029 0030 mWarningBox = new KMessageWidget(this); 0031 mWarningBox->setVisible(false); 0032 mWarningBox->setMessageType(KMessageWidget::Warning); 0033 mWarningBox->setText( 0034 i18n("Some log files do not exist.\n" 0035 "Modes with missing log files will be unavailable.")); 0036 mWarningBox->setCloseButtonVisible(false); 0037 mWarningBox->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); 0038 vboxLayout->insertWidget(1, mWarningBox); 0039 0040 description->setText(descriptionText); 0041 0042 mFileListHelper.prepareButton(modify, QIcon::fromTheme(QStringLiteral("document-open")), this, SLOT(modifyItem()), fileList); 0043 0044 fileList->header()->setVisible(false); 0045 0046 // Add a separator in the MultipleFileList 0047 auto separator = new QAction(this); 0048 separator->setSeparator(true); 0049 fileList->addAction(separator); 0050 0051 mFileListHelper.prepareButton(remove, QIcon::fromTheme(QStringLiteral("list-remove")), this, SLOT(removeSelectedItem()), fileList); 0052 0053 mFileListHelper.prepareButton(up, QIcon::fromTheme(QStringLiteral("go-up")), this, SLOT(moveUpItem()), fileList); 0054 0055 mFileListHelper.prepareButton(down, QIcon::fromTheme(QStringLiteral("go-down")), this, SLOT(moveDownItem()), fileList); 0056 0057 mFileListHelper.prepareButton(removeAll, QIcon::fromTheme(QStringLiteral("trash-empty")), this, SLOT(removeAllItems()), fileList); 0058 0059 connect(fileList, &QTreeWidget::itemSelectionChanged, this, &MultipleFileList::updateButtons); 0060 connect(fileList, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(modifyItem(QTreeWidgetItem *))); 0061 connect(this, &MultipleFileList::fileListChanged, this, &MultipleFileList::updateButtons); 0062 0063 connect(&mAddButtons, &QButtonGroup::buttonClicked, this, &MultipleFileList::addItem); 0064 0065 updateButtons(); 0066 0067 qCDebug(KSYSTEMLOG) << "Multiple File list initialized"; 0068 } 0069 0070 MultipleFileList::~MultipleFileList() 0071 { 0072 } 0073 0074 void MultipleFileList::updateButtons() 0075 { 0076 qCDebug(KSYSTEMLOG) << "Updating buttons..."; 0077 0078 if (isFileListsEmpty()) { 0079 mFileListHelper.setEnabledAction(removeAll, false); 0080 } else { 0081 mFileListHelper.setEnabledAction(removeAll, true); 0082 } 0083 0084 const QList<QTreeWidgetItem *> selectedItems = fileList->selectedItems(); 0085 0086 // If the selection is not empty and a empty item is not selected 0087 QTreeWidgetItem *categoryItem = nullptr; 0088 if (!selectedItems.isEmpty() && !isEmptyItem(selectedItems.at(0))) { 0089 categoryItem = findCategoryOfChild(selectedItems.at(0)); 0090 } 0091 0092 if (categoryItem) { 0093 const int categoryIndex = fileList->indexOfTopLevelItem(categoryItem); 0094 0095 mFileListHelper.setEnabledAction(remove, true); 0096 mFileListHelper.setEnabledAction(modify, true); 0097 0098 QTreeWidgetItem *selectedItem = selectedItems.at(0); 0099 0100 // If the item is at the top of the list, it could not be upped anymore 0101 if (categoryItem->indexOfChild(selectedItem) == 0) { 0102 mFileListHelper.setEnabledAction(up, false); 0103 } else { 0104 mFileListHelper.setEnabledAction(up, true); 0105 } 0106 0107 // If the item is at bottom of the list, it could not be downed anymore 0108 if (categoryItem->indexOfChild(selectedItem) == categoryCount(categoryIndex) - 1) { 0109 mFileListHelper.setEnabledAction(down, false); 0110 } else { 0111 mFileListHelper.setEnabledAction(down, true); 0112 } 0113 } 0114 // If nothing is selected, disabled special buttons 0115 else { 0116 mFileListHelper.setEnabledAction(remove, false); 0117 mFileListHelper.setEnabledAction(modify, false); 0118 mFileListHelper.setEnabledAction(up, false); 0119 mFileListHelper.setEnabledAction(down, false); 0120 } 0121 0122 qCDebug(KSYSTEMLOG) << "Buttons updated"; 0123 } 0124 0125 bool MultipleFileList::isFileListsEmpty() const 0126 { 0127 for (int i = 0, total = fileList->topLevelItemCount(); i < total; ++i) { 0128 if (categoryCount(i) != 0) { 0129 qCDebug(KSYSTEMLOG) << "Is not empty"; 0130 return false; 0131 } 0132 } 0133 0134 qCDebug(KSYSTEMLOG) << "Is empty"; 0135 return true; 0136 } 0137 0138 bool MultipleFileList::isOneOfCategoryEmpty() const 0139 { 0140 for (int i = 0, total = fileList->topLevelItemCount(); i < total; ++i) { 0141 if (categoryCount(i) == 0) { 0142 qCDebug(KSYSTEMLOG) << "A category is empty"; 0143 return true; 0144 } 0145 } 0146 0147 qCDebug(KSYSTEMLOG) << "No category is empty"; 0148 return false; 0149 } 0150 0151 int MultipleFileList::categoryCount(int index) const 0152 { 0153 QTreeWidgetItem *item = fileList->topLevelItem(index); 0154 if (!item) { 0155 qCCritical(KSYSTEMLOG) << "Index out of range" << index; 0156 return 0; 0157 } 0158 0159 int count = 0; 0160 for (int i = 0, total = item->childCount(); i < total; ++i) { 0161 QTreeWidgetItem *childItem = item->child(i); 0162 if (!isEmptyItem(childItem)) { 0163 count++; 0164 } 0165 } 0166 0167 return count; 0168 } 0169 0170 int MultipleFileList::addCategory(const QString &itemName, const QString &buttonName) 0171 { 0172 auto item = new QTreeWidgetItem(fileList, QStringList(itemName)); 0173 item->setExpanded(true); 0174 QFont font = item->font(0); 0175 font.setBold(true); 0176 item->setFont(0, font); 0177 0178 int const index = fileList->indexOfTopLevelItem(item); 0179 0180 auto addButton = new QPushButton(buttonName, this); 0181 QAction *action = mFileListHelper.prepareButtonAndAction(addButton, QIcon::fromTheme(QStringLiteral("document-new"))); 0182 0183 // Insert the action in first position 0184 fileList->insertAction(fileList->actions().at(mAddButtons.buttons().size()), action); 0185 0186 mAddButtons.addButton(addButton, index); 0187 0188 vboxLayout1->insertWidget(index, addButton); 0189 0190 updateEmptyItems(); 0191 0192 updateButtons(); 0193 0194 return index; 0195 } 0196 0197 void MultipleFileList::addItem(QAbstractButton *button) 0198 { 0199 const int category = mAddButtons.id(button); 0200 qCDebug(KSYSTEMLOG) << "Adding item" << category; 0201 0202 // Open a standard Filedialog 0203 const QList<QUrl> urls = mFileListHelper.openUrls(); 0204 0205 QTreeWidgetItem *categoryItem = fileList->topLevelItem(category); 0206 0207 const QStringList paths = mFileListHelper.findPaths(urls); 0208 for (const QString &path : paths) { 0209 addItemInternal(categoryItem, path); 0210 } 0211 0212 updateEmptyItems(); 0213 0214 Q_EMIT fileListChanged(); 0215 } 0216 0217 void MultipleFileList::addItemInternal(QTreeWidgetItem *categoryItem, const QString &path) 0218 { 0219 qCDebug(KSYSTEMLOG) << "Adding" << path << "to" << categoryItem->text(0); 0220 auto item = new QTreeWidgetItem(QStringList(path)); 0221 0222 QFileInfo const checkFile(path); 0223 if (!checkFile.exists()) { 0224 mMissingFiles = true; 0225 item->setForeground(0, Qt::red); 0226 } 0227 0228 categoryItem->addChild(item); 0229 categoryItem->setExpanded(true); 0230 } 0231 0232 QTreeWidgetItem *MultipleFileList::findCategoryOfChild(QTreeWidgetItem *childItem) 0233 { 0234 qCDebug(KSYSTEMLOG) << "Finding Category of" << childItem->text(0); 0235 0236 for (int i = 0, total = fileList->topLevelItemCount(); i < total; ++i) { 0237 QTreeWidgetItem *item = fileList->topLevelItem(i); 0238 0239 if (item->indexOfChild(childItem) != -1) { 0240 qCDebug(KSYSTEMLOG) << "Category of" << childItem->text(0) << "is" << item->text(0); 0241 return item; 0242 } 0243 } 0244 0245 qCDebug(KSYSTEMLOG) << "No Category of" << childItem->text(0); 0246 return nullptr; 0247 } 0248 0249 void MultipleFileList::modifyItem() 0250 { 0251 const QList<QTreeWidgetItem *> selectedItems = fileList->selectedItems(); 0252 modifyItem(selectedItems.at(0)); 0253 } 0254 0255 void MultipleFileList::modifyItem(QTreeWidgetItem *item) 0256 { 0257 // If the user tries to modify a category item, we do nothing 0258 if (!findCategoryOfChild(item) || isEmptyItem(item)) { 0259 return; 0260 } 0261 0262 const QString previousPath = item->text(0); 0263 0264 // Open a standard Filedialog 0265 const QUrl url = mFileListHelper.openUrl(previousPath); 0266 if (url.isEmpty()) { 0267 return; 0268 } 0269 0270 QList<QUrl> urls; 0271 urls.append(url); 0272 const QStringList paths = mFileListHelper.findPaths(urls); 0273 0274 // We only take the first path 0275 if (paths.count() >= 1) { 0276 item->setText(0, paths.at(0)); 0277 } 0278 0279 Q_EMIT fileListChanged(); 0280 } 0281 0282 void MultipleFileList::removeSelectedItem() 0283 { 0284 const QList<QTreeWidgetItem *> selectedItems = fileList->selectedItems(); 0285 0286 for (QTreeWidgetItem *item : selectedItems) { 0287 QTreeWidgetItem *categoryItem = findCategoryOfChild(item); 0288 delete categoryItem->takeChild(categoryItem->indexOfChild(item)); 0289 } 0290 0291 updateEmptyItems(); 0292 0293 Q_EMIT fileListChanged(); 0294 } 0295 0296 void MultipleFileList::moveItem(int direction) 0297 { 0298 QList<QTreeWidgetItem *> const selectedItems = fileList->selectedItems(); 0299 0300 QTreeWidgetItem *item = selectedItems.at(0); 0301 0302 QTreeWidgetItem *categoryItem = findCategoryOfChild(item); 0303 int const itemIndex = categoryItem->indexOfChild(item); 0304 0305 categoryItem->takeChild(itemIndex); 0306 0307 unselectAllItems(); 0308 0309 categoryItem->insertChild(itemIndex + direction, item); 0310 0311 fileList->setCurrentItem(item); 0312 // item->setSelected(true); 0313 0314 Q_EMIT fileListChanged(); 0315 } 0316 0317 void MultipleFileList::moveUpItem() 0318 { 0319 moveItem(-1); 0320 } 0321 0322 void MultipleFileList::moveDownItem() 0323 { 0324 moveItem(1); 0325 } 0326 0327 void MultipleFileList::removeAllItems() 0328 { 0329 QTreeWidgetItemIterator it(fileList, QTreeWidgetItemIterator::All); 0330 while (*it) { 0331 QTreeWidgetItem *item = *it; 0332 0333 const QList<QTreeWidgetItem *> children = item->takeChildren(); 0334 for (QTreeWidgetItem *childItem : children) { 0335 delete childItem; 0336 } 0337 0338 ++it; 0339 } 0340 0341 updateEmptyItems(); 0342 0343 Q_EMIT fileListChanged(); 0344 } 0345 0346 void MultipleFileList::unselectAllItems() 0347 { 0348 const QList<QTreeWidgetItem *> selectedItems = fileList->selectedItems(); 0349 for (QTreeWidgetItem *item : selectedItems) { 0350 item->setSelected(false); 0351 } 0352 } 0353 0354 void MultipleFileList::updateEmptyItems() 0355 { 0356 qCDebug(KSYSTEMLOG) << "Updating empty items..."; 0357 0358 qCDebug(KSYSTEMLOG) << "Adding empty items..."; 0359 0360 for (int i = 0, total = fileList->topLevelItemCount(); i < total; ++i) { 0361 QTreeWidgetItem *categoryItem = fileList->topLevelItem(i); 0362 0363 // If it's a category item and it's empty 0364 if (categoryItem->childCount() == 0) { 0365 addEmptyItem(categoryItem); 0366 } 0367 } 0368 0369 removeEmptyItems(); 0370 0371 qCDebug(KSYSTEMLOG) << "Empty items updated"; 0372 } 0373 0374 void MultipleFileList::removeEmptyItems() 0375 { 0376 qCDebug(KSYSTEMLOG) << "Removing empty items..."; 0377 0378 // Remove empty items of lists 0379 for (int categoryIndex = 0; categoryIndex < fileList->topLevelItemCount(); ++categoryIndex) { 0380 QTreeWidgetItem *categoryItem = fileList->topLevelItem(categoryIndex); 0381 0382 qCDebug(KSYSTEMLOG) << "Removing empty items of " << categoryItem->text(0); 0383 0384 for (int i = 0; i < categoryItem->childCount(); ++i) { 0385 QTreeWidgetItem *childItem = categoryItem->child(i); 0386 0387 if (isEmptyItem(childItem) && categoryItem->childCount() > 1) { 0388 qCDebug(KSYSTEMLOG) << "Remove a child item"; 0389 delete categoryItem->takeChild(i); 0390 break; 0391 } 0392 } 0393 0394 qCDebug(KSYSTEMLOG) << "Empty items of " << categoryItem->text(0) << "removed"; 0395 } 0396 } 0397 0398 bool MultipleFileList::isEmptyItem(QTreeWidgetItem *item) const 0399 { 0400 if (item->font(0).italic()) { 0401 return true; 0402 } else { 0403 return false; 0404 } 0405 } 0406 0407 void MultipleFileList::addEmptyItem(QTreeWidgetItem *item) 0408 { 0409 qCDebug(KSYSTEMLOG) << "Adding an empty item..."; 0410 0411 auto emptyItem = new QTreeWidgetItem(item, QStringList(i18n("No log file..."))); 0412 item->setExpanded(true); 0413 QFont font = emptyItem->font(0); 0414 font.setItalic(true); 0415 emptyItem->setFont(0, font); 0416 } 0417 0418 void MultipleFileList::addPaths(int category, const QStringList &paths) 0419 { 0420 mMissingFiles = false; 0421 QTreeWidgetItem *categoryItem = fileList->topLevelItem(category); 0422 0423 for (const QString &path : paths) { 0424 addItemInternal(categoryItem, path); 0425 } 0426 0427 updateEmptyItems(); 0428 0429 updateButtons(); 0430 0431 mWarningBox->setVisible(mMissingFiles); 0432 } 0433 0434 QStringList MultipleFileList::paths(int category) 0435 { 0436 QTreeWidgetItem *categoryItem = fileList->topLevelItem(category); 0437 QTreeWidgetItemIterator it(fileList, QTreeWidgetItemIterator::All); 0438 0439 QStringList paths; 0440 while (*it) { 0441 QTreeWidgetItem *item = *it; 0442 0443 if (categoryItem->indexOfChild(item) != -1) { 0444 paths.append(item->text(0)); 0445 } 0446 0447 ++it; 0448 } 0449 0450 return paths; 0451 } 0452 0453 #include "moc_multipleFileList.cpp"