File indexing completed on 2024-05-12 17:22:01

0001 /*
0002     SPDX-FileCopyrightText: 2002 Shie Erlich <erlich@users.sourceforge.net>
0003     SPDX-FileCopyrightText: 2002 Rafi Yanai <yanai@users.sourceforge.net>
0004     SPDX-FileCopyrightText: 2010 Jan Lepper <dehtris@yahoo.de>
0005     SPDX-FileCopyrightText: 2004-2022 Krusader Krew <https://krusader.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "krinterview.h"
0011 
0012 #include <QDebug>
0013 
0014 #include "../FileSystem/dirlisterinterface.h"
0015 #include "../FileSystem/fileitem.h"
0016 #include "../krcolorcache.h"
0017 #include "../krpreviews.h"
0018 #include "krmousehandler.h"
0019 #include "krviewitem.h"
0020 #include "listmodel.h"
0021 
0022 KrInterView::KrInterView(KrViewInstance &instance, KConfig *cfg, QAbstractItemView *itemView)
0023     : KrView(instance, cfg)
0024     , _itemView(itemView)
0025     , _mouseHandler(nullptr)
0026 {
0027     _model = new ListModel(this);
0028 
0029     // fix the context menu problem
0030     int j = QFontMetrics(_itemView->font()).height() * 2;
0031     _mouseHandler = new KrMouseHandler(this, j);
0032 }
0033 
0034 KrInterView::~KrInterView()
0035 {
0036     // any references to the model should be cleared ar this point,
0037     // but sometimes for some reason it is still referenced by
0038     // QPersistentModelIndex instances held by QAbstractItemView and/or QItemSelectionModel(child object) -
0039     // so schedule _model for later deletion
0040     _model->clear(false);
0041     _model->deleteLater();
0042     _model = nullptr;
0043     delete _mouseHandler;
0044     _mouseHandler = nullptr;
0045     QHashIterator<FileItem *, KrViewItem *> it(_itemHash);
0046     while (it.hasNext())
0047         delete it.next().value();
0048     _itemHash.clear();
0049 }
0050 
0051 void KrInterView::selectRegion(KrViewItem *i1, KrViewItem *i2, bool select)
0052 {
0053     auto *file1 = const_cast<FileItem *>(i1->getFileItem());
0054     QModelIndex mi1 = _model->fileItemIndex(file1);
0055     auto *file2 = const_cast<FileItem *>(i2->getFileItem());
0056     QModelIndex mi2 = _model->fileItemIndex(file2);
0057 
0058     if (mi1.isValid() && mi2.isValid()) {
0059         int r1 = mi1.row();
0060         int r2 = mi2.row();
0061 
0062         if (r1 > r2) {
0063             int t = r1;
0064             r1 = r2;
0065             r2 = t;
0066         }
0067 
0068         op()->setMassSelectionUpdate(true);
0069         for (int row = r1; row <= r2; row++)
0070             setSelected(_model->fileItemAt(_model->index(row, 0)), select);
0071         op()->setMassSelectionUpdate(false);
0072 
0073         redraw();
0074 
0075     } else if (mi1.isValid() && !mi2.isValid())
0076         i1->setSelected(select);
0077     else if (mi2.isValid() && !mi1.isValid())
0078         i2->setSelected(select);
0079 }
0080 
0081 void KrInterView::intSetSelected(const FileItem *item, bool select)
0082 {
0083     if (select)
0084         _selection.insert(item);
0085     else
0086         _selection.remove(item);
0087 }
0088 
0089 bool KrInterView::isSelected(const QModelIndex &ndx)
0090 {
0091     return isSelected(_model->fileItemAt(ndx));
0092 }
0093 
0094 KrViewItem *KrInterView::findItemByName(const QString &name)
0095 {
0096     if (!_model->ready())
0097         return nullptr;
0098 
0099     QModelIndex ndx = _model->nameIndex(name);
0100     if (!ndx.isValid())
0101         return nullptr;
0102     return getKrViewItem(ndx);
0103 }
0104 
0105 KrViewItem *KrInterView::findItemByUrl(const QUrl &url)
0106 {
0107     if (!_model->ready())
0108         return nullptr;
0109 
0110     const QModelIndex ndx = _model->indexFromUrl(url);
0111     if (!ndx.isValid())
0112         return nullptr;
0113 
0114     return getKrViewItem(ndx);
0115 }
0116 
0117 QString KrInterView::getCurrentItem() const
0118 {
0119     if (!_model->ready())
0120         return QString();
0121 
0122     FileItem *fileItem = _model->fileItemAt(_itemView->currentIndex());
0123     return fileItem ? fileItem->getName() : QString();
0124 }
0125 
0126 KrViewItem *KrInterView::getCurrentKrViewItem()
0127 {
0128     if (!_model->ready())
0129         return nullptr;
0130 
0131     return getKrViewItem(_itemView->currentIndex());
0132 }
0133 
0134 KrViewItem *KrInterView::getFirst()
0135 {
0136     if (!_model->ready())
0137         return nullptr;
0138 
0139     return getKrViewItem(_model->index(0, 0, QModelIndex()));
0140 }
0141 
0142 KrViewItem *KrInterView::getLast()
0143 {
0144     if (!_model->ready())
0145         return nullptr;
0146 
0147     return getKrViewItem(_model->index(_model->rowCount() - 1, 0, QModelIndex()));
0148 }
0149 
0150 KrViewItem *KrInterView::getNext(KrViewItem *current)
0151 {
0152     auto *fileItem = const_cast<FileItem *>(current->getFileItem());
0153     QModelIndex ndx = _model->fileItemIndex(fileItem);
0154     if (ndx.row() >= _model->rowCount() - 1)
0155         return nullptr;
0156     return getKrViewItem(_model->index(ndx.row() + 1, 0, QModelIndex()));
0157 }
0158 
0159 KrViewItem *KrInterView::getPrev(KrViewItem *current)
0160 {
0161     auto *fileItem = const_cast<FileItem *>(current->getFileItem());
0162     QModelIndex ndx = _model->fileItemIndex(fileItem);
0163     if (ndx.row() <= 0)
0164         return nullptr;
0165     return getKrViewItem(_model->index(ndx.row() - 1, 0, QModelIndex()));
0166 }
0167 
0168 KrViewItem *KrInterView::getKrViewItemAt(const QPoint &vp)
0169 {
0170     if (!_model->ready())
0171         return nullptr;
0172 
0173     return getKrViewItem(_itemView->indexAt(vp));
0174 }
0175 
0176 KrViewItem *KrInterView::getKrViewItem(FileItem *fileItem)
0177 {
0178     QHash<FileItem *, KrViewItem *>::iterator it = _itemHash.find(fileItem);
0179     if (it == _itemHash.end()) {
0180         auto *newItem = new KrViewItem(fileItem, this);
0181         _itemHash[fileItem] = newItem;
0182         return newItem;
0183     }
0184     return *it;
0185 }
0186 
0187 KrViewItem *KrInterView::getKrViewItem(const QModelIndex &ndx)
0188 {
0189     if (!ndx.isValid())
0190         return nullptr;
0191     FileItem *fileitem = _model->fileItemAt(ndx);
0192     if (fileitem == nullptr)
0193         return nullptr;
0194     else
0195         return getKrViewItem(fileitem);
0196 }
0197 
0198 void KrInterView::makeCurrentVisible()
0199 {
0200     makeItemVisible(getCurrentKrViewItem());
0201 }
0202 
0203 void KrInterView::makeItemVisible(const KrViewItem *item)
0204 {
0205     if (item == nullptr)
0206         return;
0207 
0208     auto *fileitem = const_cast<FileItem *>(item->getFileItem());
0209     const QModelIndex index = _model->fileItemIndex(fileitem);
0210     qDebug() << "scroll to item; name=" << fileitem->getName() << " index=" << index;
0211     if (index.isValid())
0212         _itemView->scrollTo(index);
0213 }
0214 
0215 bool KrInterView::isItemVisible(const KrViewItem *item)
0216 {
0217     return item && _itemView->viewport()->rect().contains(item->itemRect());
0218 }
0219 
0220 void KrInterView::setCurrentItem(const QString &name, bool scrollToCurrent, const QModelIndex &fallbackToIndex)
0221 {
0222     // find index by given name and set it as current
0223     const QModelIndex index = _model->nameIndex(name);
0224     if (index.isValid()) {
0225         setCurrent(index, scrollToCurrent);
0226     } else if (fallbackToIndex.isValid()) {
0227         // set fallback index as current if not too big, else set the last item as current
0228         if (fallbackToIndex.row() < _itemView->model()->rowCount()) {
0229             setCurrent(fallbackToIndex, scrollToCurrent);
0230         } else {
0231             setCurrentKrViewItem(getLast(), scrollToCurrent);
0232         }
0233     } else {
0234         // when given parameters fail, set the first item as current
0235         setCurrentKrViewItem(getFirst(), scrollToCurrent);
0236     }
0237 }
0238 
0239 void KrInterView::setCurrentKrViewItem(KrViewItem *item, bool scrollToCurrent)
0240 {
0241     if (!item) {
0242         setCurrent(QModelIndex(), scrollToCurrent);
0243         return;
0244     }
0245 
0246     auto *fileitem = const_cast<FileItem *>(item->getFileItem());
0247     const QModelIndex index = _model->fileItemIndex(fileitem);
0248     if (index.isValid() && index.row() != _itemView->currentIndex().row()) {
0249         setCurrent(index, scrollToCurrent);
0250     }
0251 }
0252 
0253 void KrInterView::setCurrent(const QModelIndex &index, bool scrollToCurrent)
0254 {
0255     const bool disableAutoScroll = _itemView->hasAutoScroll() && !scrollToCurrent;
0256     if (disableAutoScroll) {
0257         // setCurrentIndex() scrolls to current if autoScroll is turned on
0258         _itemView->setAutoScroll(false);
0259     }
0260 
0261     _mouseHandler->cancelTwoClickRename();
0262     _itemView->setCurrentIndex(index);
0263 
0264     if (disableAutoScroll) {
0265         _itemView->setAutoScroll(true);
0266     }
0267 }
0268 
0269 void KrInterView::sort()
0270 {
0271     _model->sort();
0272 }
0273 
0274 void KrInterView::clear()
0275 {
0276     _selection.clear();
0277     _itemView->clearSelection();
0278     _itemView->setCurrentIndex(QModelIndex());
0279     _model->clear();
0280     QHashIterator<FileItem *, KrViewItem *> it(_itemHash);
0281     while (it.hasNext())
0282         delete it.next().value();
0283     _itemHash.clear();
0284 
0285     KrView::clear();
0286 }
0287 
0288 void KrInterView::populate(const QList<FileItem *> &fileItems, FileItem *dummy)
0289 {
0290     _model->populate(fileItems, dummy);
0291 }
0292 
0293 KrViewItem *KrInterView::preAddItem(FileItem *fileitem)
0294 {
0295     const QModelIndex index = _model->addItem(fileitem);
0296     return getKrViewItem(index);
0297 }
0298 
0299 void KrInterView::preDeleteItem(KrViewItem *item)
0300 {
0301     // update selection
0302     setSelected(item->getFileItem(), false);
0303 
0304     // close editor if it's opened for the item
0305     auto file_item = const_cast<FileItem *>(item->getFileItem());
0306     _itemView->closePersistentEditor(_model->fileItemIndex(file_item));
0307 
0308     // remove the item from the structures
0309     _model->removeItem(file_item);
0310     _itemHash.remove(file_item);
0311 }
0312 
0313 void KrInterView::prepareForActive()
0314 {
0315     _focused = true;
0316     _itemView->setFocus();
0317 }
0318 
0319 void KrInterView::prepareForPassive()
0320 {
0321     _focused = false;
0322     _mouseHandler->cancelTwoClickRename();
0323     // if ( renameLineEdit() ->isVisible() )
0324     // renameLineEdit() ->clearFocus();
0325 }
0326 
0327 void KrInterView::redraw()
0328 {
0329     _itemView->viewport()->update();
0330 }
0331 
0332 void KrInterView::refreshColors()
0333 {
0334     QPalette p(_itemView->palette());
0335     KrColorGroup cg;
0336     KrColorCache::getColorCache().getColors(cg, KrColorItemType(KrColorItemType::File, false, _focused, false, false));
0337     p.setColor(QPalette::Text, cg.text());
0338     p.setColor(QPalette::Base, cg.background());
0339     _itemView->setPalette(p);
0340     redraw();
0341 }
0342 
0343 void KrInterView::sortModeUpdated(int column, Qt::SortOrder order)
0344 {
0345     KrView::sortModeUpdated(static_cast<KrViewProperties::ColumnType>(column), order == Qt::DescendingOrder);
0346 }
0347 
0348 KIO::filesize_t KrInterView::calcSize()
0349 {
0350     KIO::filesize_t size = 0;
0351     foreach (FileItem *fileitem, _model->fileItems()) {
0352         size += fileitem->getSize();
0353     }
0354     return size;
0355 }
0356 
0357 KIO::filesize_t KrInterView::calcSelectedSize()
0358 {
0359     KIO::filesize_t size = 0;
0360     foreach (const FileItem *fileitem, _selection) {
0361         size += fileitem->getSize();
0362     }
0363     return size;
0364 }
0365 
0366 QList<QUrl> KrInterView::selectedUrls()
0367 {
0368     QList<QUrl> list;
0369     foreach (const FileItem *fileitem, _selection) {
0370         list << fileitem->getUrl();
0371     }
0372     return list;
0373 }
0374 
0375 void KrInterView::setSelectionUrls(const QList<QUrl> urls)
0376 {
0377     op()->setMassSelectionUpdate(true);
0378 
0379     _selection.clear();
0380 
0381     foreach (const QUrl &url, urls) {
0382         const QModelIndex idx = _model->indexFromUrl(url);
0383         if (idx.isValid())
0384             setSelected(_model->fileItemAt(idx), true);
0385     }
0386 
0387     op()->setMassSelectionUpdate(false);
0388 }