File indexing completed on 2024-04-21 16:32:32
0001 /*************************************************************************** 0002 krenamemodel.cpp - description 0003 ------------------- 0004 begin : Sun Apr 25 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 "krenamemodel.h" 0019 #include "threadedlister.h" 0020 0021 #include <QMimeData> 0022 #include <QPixmap> 0023 #include <QApplication> 0024 0025 #include <KLocalizedString> 0026 #include <krun.h> 0027 #include <kio/previewjob.h> 0028 0029 KRenameModel::KRenameModel(KRenameFile::List *vector) 0030 : QAbstractListModel(), 0031 m_vector(vector), 0032 m_preview(false), 0033 m_text(false), 0034 m_maxDots(0), 0035 m_mimeType("text/uri-list"), 0036 m_eSortMode(eSortMode_Unsorted), 0037 m_customSortToken("creationdate;yyyyMMddHHmm"), 0038 m_eCustomSortMode(KRenameTokenSorter::eSimpleSortMode_Ascending) 0039 { 0040 0041 } 0042 0043 KRenameModel::~KRenameModel() 0044 { 0045 0046 } 0047 0048 int KRenameModel::rowCount(const QModelIndex &index) const 0049 { 0050 if (!index.isValid()) { 0051 return m_vector->size(); 0052 } 0053 0054 return 0; 0055 } 0056 0057 QVariant KRenameModel::data(const QModelIndex &index, int role) const 0058 { 0059 if (!index.isValid()) { 0060 return QVariant(); 0061 } 0062 0063 if (index.row() >= m_vector->size()) { 0064 return QVariant(); 0065 } 0066 0067 if (role == Qt::DisplayRole) { 0068 if (!m_preview) { 0069 // Only return path 0070 return m_vector->at(index.row()).toString(); 0071 } else if (m_preview && m_text) { 0072 // Short filename as first line in bold 0073 // Path as second line 0074 const KRenameFile &file = m_vector->at(index.row()); 0075 QString filename = file.srcFilename(); 0076 if (!file.srcExtension().isEmpty()) { 0077 filename = filename + '.' + file.srcExtension(); 0078 } 0079 0080 const QString &prettyUrl = file.toString(); 0081 return "<qt><b>" + filename + "</b><br/>" + 0082 prettyUrl + "</qt>"; 0083 } 0084 } else if (role == Qt::DecorationRole && m_preview) { 0085 return m_vector->at(index.row()).icon(); 0086 } else if (role == Qt::UserRole) { 0087 return m_vector->at(index.row()).toString(); 0088 } 0089 0090 return QVariant(); 0091 } 0092 0093 Qt::ItemFlags KRenameModel::flags(const QModelIndex &index) const 0094 { 0095 if (!index.isValid()) { 0096 return Qt::ItemIsDropEnabled; 0097 } 0098 0099 return QAbstractItemModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDropEnabled; 0100 } 0101 0102 Qt::DropActions KRenameModel::supportedDropActions() const 0103 { 0104 return Qt::CopyAction | Qt::MoveAction; 0105 } 0106 0107 QStringList KRenameModel::mimeTypes() const 0108 { 0109 QStringList types; 0110 types << m_mimeType; 0111 return types; 0112 } 0113 0114 bool KRenameModel::dropMimeData(const QMimeData *data, 0115 Qt::DropAction action, 0116 int, int, 0117 const QModelIndex &) 0118 { 0119 if (action == Qt::IgnoreAction) { 0120 return true; 0121 } 0122 0123 if (!data->hasFormat(m_mimeType)) { 0124 return false; 0125 } 0126 0127 QList<QUrl> dirs; 0128 KRenameFile::List files; 0129 QList<QUrl> urls = data->urls(); 0130 QList<QUrl>::const_iterator it = urls.constBegin(); 0131 0132 QApplication::setOverrideCursor(Qt::BusyCursor); 0133 0134 while (it != urls.constEnd()) { 0135 if ((*it).isValid()) { 0136 KRenameFile file(*it, m_eSplitMode, m_dot); 0137 0138 if (file.isValid() && !file.isDirectory()) { 0139 files.append(file); 0140 } else if (file.isValid() && file.isDirectory()) 0141 // Add directories recursively 0142 { 0143 dirs.append(*it); 0144 } 0145 } 0146 0147 ++it; 0148 } 0149 0150 this->addFiles(files); 0151 if (dirs.count()) { 0152 QList<QUrl>::const_iterator it = dirs.constBegin(); 0153 0154 while (it != dirs.constEnd()) { 0155 ThreadedLister *thl = new ThreadedLister(*it, nullptr, this); 0156 connect(thl, &ThreadedLister::listerDone, 0157 this, &KRenameModel::slotListerDone); 0158 0159 thl->setListDirnamesOnly(false); 0160 thl->setListHidden(false); 0161 thl->setListRecursively(true); 0162 thl->setListDirnames(false); 0163 0164 thl->start(); 0165 0166 ++it; 0167 } 0168 } else { 0169 QApplication::restoreOverrideCursor(); 0170 emit filesDropped(); 0171 } 0172 0173 return true; 0174 } 0175 0176 void KRenameModel::slotListerDone(ThreadedLister *lister) 0177 { 0178 // Delete the listener 0179 delete lister; 0180 0181 // restore cursor 0182 QApplication::restoreOverrideCursor(); 0183 0184 emit filesDropped(); 0185 } 0186 0187 bool KRenameModel::setData(const QModelIndex &index, 0188 const QVariant &, int role) 0189 { 0190 if (index.isValid() && role == Qt::EditRole) { 0191 0192 //stringList.replace(index.row(), value.toString()); 0193 emit dataChanged(index, index); 0194 return true; 0195 } 0196 0197 return false; 0198 } 0199 0200 void KRenameModel::addFiles(const KRenameFile::List &files) 0201 { 0202 if (files.count()) { 0203 int oldMaxDots = m_maxDots; 0204 m_vector->reserve(m_vector->count() + files.count()); 0205 0206 this->beginInsertRows(QModelIndex(), m_vector->size(), m_vector->size() + files.count() - 1); 0207 0208 KRenameFile::List::const_iterator it = files.begin(); 0209 while (it != files.end()) { 0210 m_vector->push_back(*it); 0211 0212 int dots = (*it).dots(); 0213 if (dots > m_maxDots) { 0214 m_maxDots = dots; 0215 } 0216 0217 ++it; 0218 } 0219 this->endInsertRows(); 0220 0221 if (m_maxDots > oldMaxDots) { 0222 emit maxDotsChanged(m_maxDots); 0223 } 0224 0225 // Update sorting 0226 this->sortFiles(m_eSortMode, m_customSortToken, m_eCustomSortMode); 0227 0228 // Generate previews if necessary 0229 if (m_preview) { 0230 // Construct a list of KFileItems 0231 // Only do this is necessary, 0232 // as this might create new KFileItems which is slow. 0233 KFileItemList fileItems; 0234 it = files.begin(); 0235 while (it != files.end()) { 0236 fileItems << (*it).fileItem(); 0237 0238 ++it; 0239 } 0240 0241 // TODO: Enable this job, it currently crashes for me 0242 0243 // Start a job to create the real file previews 0244 KIO::PreviewJob *job = KIO::filePreview(fileItems, QSize(KRenameFile::iconSize(), KRenameFile::iconSize())); 0245 0246 connect(job, &KIO::PreviewJob::gotPreview, 0247 this, &KRenameModel::gotPreview); 0248 job->start(); 0249 } 0250 } 0251 } 0252 0253 void KRenameModel::gotPreview(const KFileItem &item, const QPixmap &preview) 0254 { 0255 /* 0256 const KRenameFile* file = 0257 static_cast<const KRenameFile*>(item.extraData(KRenameFile::EXTRA_DATA_KEY)); 0258 */ 0259 0260 KRenameFile *file = nullptr; 0261 // TODO: Find a more optimal "search algorithm" .... 0262 KRenameFile::List::iterator it = m_vector->begin(); 0263 while (it != m_vector->end()) { 0264 if ((*it).srcUrl() == item.url()) { 0265 file = &(*it); 0266 break; 0267 } 0268 0269 ++it; 0270 } 0271 0272 //it = find( m_vector->begin(), m_vector->end(), item ); 0273 if (file != nullptr) { // && file->fileItem() == item ) 0274 file->setIcon(preview); 0275 } 0276 } 0277 0278 void KRenameModel::removeFiles(const QList<int> &remove) 0279 { 0280 int offset = 0; 0281 0282 QList<int> copy(remove); 0283 std::sort(copy.begin(), copy.end()); 0284 0285 QList<int>::const_iterator it = copy.constBegin(); 0286 this->beginRemoveRows(QModelIndex(), *it, copy.back()); 0287 while (it != copy.constEnd()) { 0288 m_vector->erase(m_vector->begin() + *it - offset); 0289 0290 ++offset; 0291 ++it; 0292 } 0293 0294 this->endRemoveRows(); 0295 } 0296 0297 void KRenameModel::sortFiles(ESortMode mode, const QString &customSortToken, KRenameTokenSorter::ESimpleSortMode customSortMode) 0298 { 0299 beginResetModel(); 0300 const QString dateSortToken = "creationdate;yyyyMMddHHmm"; 0301 0302 m_eSortMode = mode; 0303 m_customSortToken = customSortToken; 0304 m_eCustomSortMode = customSortMode; 0305 0306 if (mode == eSortMode_Ascending) { 0307 std::sort(m_vector->begin(), m_vector->end(), ascendingKRenameFileLessThan); 0308 } else if (mode == eSortMode_Descending) { 0309 std::sort(m_vector->begin(), m_vector->end(), descendingKRenameFileLessThan); 0310 } else if (mode == eSortMode_Numeric) { 0311 std::sort(m_vector->begin(), m_vector->end(), numericKRenameFileLessThan); 0312 } else if (mode == eSortMode_Random) { 0313 std::sort(m_vector->begin(), m_vector->end(), randomKRenameFileLessThan); 0314 } else if (mode == eSortMode_AscendingDate) { 0315 KRenameTokenSorter sorter(m_renamer, dateSortToken, *m_vector, 0316 KRenameTokenSorter::eSimpleSortMode_Ascending); 0317 std::sort(m_vector->begin(), m_vector->end(), sorter); 0318 } else if (mode == eSortMode_DescendingDate) { 0319 KRenameTokenSorter sorter(m_renamer, dateSortToken, *m_vector, 0320 KRenameTokenSorter::eSimpleSortMode_Descending); 0321 std::sort(m_vector->begin(), m_vector->end(), sorter); 0322 } else if (mode == eSortMode_Token) { 0323 KRenameTokenSorter sorter(m_renamer, customSortToken, *m_vector, 0324 customSortMode); 0325 std::sort(m_vector->begin(), m_vector->end(), sorter); 0326 } 0327 0328 endResetModel(); 0329 } 0330 0331 void KRenameModel::run(const QModelIndex &index, QWidget *window) const 0332 { 0333 KRenameFile file = m_vector->at(index.row()); 0334 new KRun(file.srcUrl(), window); 0335 } 0336 0337 const QModelIndex KRenameModel::createIndex(int row) const 0338 { 0339 return QAbstractItemModel::createIndex(row, 0); 0340 } 0341 0342 void KRenameModel::moveFilesUp(const QList<int> &files) 0343 { 0344 int index; 0345 KRenameFile tmp; 0346 0347 QList<int> copy(files); 0348 std::sort(copy.begin(), copy.end()); 0349 0350 beginResetModel(); 0351 QList<int>::const_iterator it = copy.constBegin(); 0352 while (it != copy.constEnd()) { 0353 index = *it; 0354 if (index <= 0) { // cannot swap top item 0355 ++it; 0356 continue; 0357 } 0358 0359 // swap items 0360 tmp = m_vector->at(index); 0361 (*m_vector)[index] = KRenameFile(m_vector->at(index - 1)); 0362 (*m_vector)[index - 1] = tmp; 0363 0364 ++it; 0365 } 0366 0367 endResetModel(); 0368 } 0369 0370 void KRenameModel::moveFilesDown(const QList<int> &files) 0371 { 0372 int index; 0373 KRenameFile tmp; 0374 0375 QList<int> copy(files); 0376 // sort the list in reverse order 0377 std::sort(copy.begin(), copy.end(), std::greater<int>()); 0378 0379 beginResetModel(); 0380 QList<int>::const_iterator it = copy.constBegin(); 0381 while (it != copy.constEnd()) { 0382 index = *it; 0383 if (index + 1 >= m_vector->size()) { // cannot swap bottom item 0384 ++it; 0385 continue; 0386 } 0387 0388 // swap items 0389 tmp = m_vector->at(index); 0390 (*m_vector)[index] = KRenameFile(m_vector->at(index + 1)); 0391 (*m_vector)[index + 1] = tmp; 0392 0393 ++it; 0394 } 0395 0396 endResetModel(); 0397 } 0398 0399 ////////////////////////////////////////////////////////////// 0400 // Preview model starts below 0401 ////////////////////////////////////////////////////////////// 0402 KRenamePreviewModel::KRenamePreviewModel(KRenameFile::List *vector) 0403 : m_vector(vector) 0404 { 0405 0406 } 0407 0408 KRenamePreviewModel::~KRenamePreviewModel() 0409 { 0410 0411 } 0412 0413 int KRenamePreviewModel::rowCount(const QModelIndex &parent) const 0414 { 0415 if (!parent.isValid()) { 0416 return m_vector->size(); 0417 } 0418 0419 return 0; 0420 } 0421 0422 int KRenamePreviewModel::columnCount(const QModelIndex &) const 0423 { 0424 return 2; 0425 } 0426 0427 QVariant KRenamePreviewModel::headerData(int section, Qt::Orientation orientation, int role) const 0428 { 0429 if (orientation != Qt::Horizontal || section > 1 || role != Qt::DisplayRole) { 0430 return QVariant(); 0431 } 0432 0433 return (section == 0) ? i18n("Origin") : i18n("Renamed"); 0434 } 0435 0436 QVariant KRenamePreviewModel::data(const QModelIndex &index, int role) const 0437 { 0438 if (!index.isValid()) { 0439 return QVariant(); 0440 } 0441 0442 if (index.row() >= m_vector->size()) { 0443 return QVariant(); 0444 } 0445 0446 if (index.column() >= 2) { 0447 return QVariant(); 0448 } 0449 0450 if (role == Qt::DisplayRole) { 0451 const KRenameFile &file = m_vector->at(index.row()); 0452 QString filename; 0453 QString extension; 0454 QString manual; 0455 0456 if (index.column()) { 0457 manual = file.manualChanges(); 0458 if (manual.isNull()) { 0459 filename = file.dstFilename(); 0460 extension = file.dstExtension(); 0461 } else { 0462 filename = manual; 0463 } 0464 } else { 0465 filename = file.srcFilename(); 0466 extension = file.srcExtension(); 0467 } 0468 0469 if (!extension.isEmpty()) { 0470 filename += '.'; 0471 filename += extension; 0472 } 0473 0474 if (file.isDirectory()) { 0475 filename = (index.column() ? file.dstDirectory() : file.srcDirectory()) + '/' + filename; 0476 } 0477 0478 return filename; 0479 } else if (role == Qt::ForegroundRole) { 0480 const KRenameFile &file = m_vector->at(index.row()); 0481 if (!file.manualChanges().isNull()) { 0482 return QVariant(QColor(Qt::blue)); 0483 } 0484 } 0485 /* 0486 Icons are to large, so this is disabled 0487 else if( role == Qt::DecorationRole && index.column() == 0 ) 0488 { 0489 return m_vector->at(index.row()).icon(); 0490 } 0491 */ 0492 0493 return QVariant(); 0494 0495 } 0496 0497 QModelIndex KRenamePreviewModel::parent(const QModelIndex &) const 0498 { 0499 return QModelIndex(); 0500 } 0501 0502 QModelIndex KRenamePreviewModel::sibling(int, int, const QModelIndex &) const 0503 { 0504 return QModelIndex(); 0505 } 0506 0507 void KRenamePreviewModel::refresh() 0508 { 0509 beginResetModel(); 0510 endResetModel(); 0511 }