diff --git a/krusader/GUI/krstyleproxy.cpp b/krusader/GUI/krstyleproxy.cpp index 880ff6c6..a5af4ba9 100644 --- a/krusader/GUI/krstyleproxy.cpp +++ b/krusader/GUI/krstyleproxy.cpp @@ -1,66 +1,87 @@ /*************************************************************************** krstyleproxy.cpp ------------------- copyright : (C) 2008+ by Csaba Karai email : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "krstyleproxy.h" // QtGui #include #include // QtWidgets #include +#include + +#include "../krglobal.h" + void KrStyleProxy::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { if (element == QStyle::PE_FrameFocusRect) { if (const QStyleOptionFocusRect *fropt = qstyleoption_cast(option)) { QColor bg = fropt->backgroundColor; QPen oldPen = painter->pen(); QPen newPen; if (bg.isValid()) { int h, s, v; bg.getHsv(&h, &s, &v); if (v >= 128) newPen.setColor(Qt::black); else newPen.setColor(Qt::white); } else { newPen.setColor(option->palette.foreground().color()); } newPen.setWidth(0); newPen.setStyle(Qt::DotLine); painter->setPen(newPen); QRect focusRect = option->rect /*.adjusted(1, 1, -1, -1) */; painter->drawRect(focusRect.adjusted(0, 0, -1, -1)); //draw pen inclusive painter->setPen(oldPen); } } else QProxyStyle::drawPrimitive(element, option, painter, widget); } + +int KrStyleProxy::styleHint(QStyle::StyleHint hint, const QStyleOption *option, + const QWidget *widget, QStyleHintReturn *returnData) const +{ + if (hint == QStyle::SH_ToolTip_WakeUpDelay) { + KConfigGroup group(krConfig, "Look&Feel"); + const int delay = group.readEntry("Panel Tooltip Delay", 1000); + return delay < 0 ? INT_MAX : delay; + } + + // disable instant consecutive tooltips + if (hint == QStyle::SH_ToolTip_FallAsleepDelay) { + return 0; + } + + return QProxyStyle::styleHint(hint, option, widget, returnData); +} diff --git a/krusader/GUI/krstyleproxy.h b/krusader/GUI/krstyleproxy.h index cd43a4a0..cd7609bc 100644 --- a/krusader/GUI/krstyleproxy.h +++ b/krusader/GUI/krstyleproxy.h @@ -1,44 +1,49 @@ /*************************************************************************** krstyleproxy.h ------------------- copyright : (C) 2008+ by Csaba Karai email : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD H e a d e r F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KRSTYLEPROXY_H #define KRSTYLEPROXY_H // QtWidgets #include class KrStyleProxy: public QProxyStyle { public: void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const Q_DECL_OVERRIDE; + + int styleHint(StyleHint hint, + const QStyleOption *option, + const QWidget *widget, + QStyleHintReturn *returnData) const Q_DECL_OVERRIDE; }; #endif /* KRSTYLEPROXY_H */ diff --git a/krusader/Panel/krinterbriefview.cpp b/krusader/Panel/krinterbriefview.cpp index b34a4a81..1beee8ec 100644 --- a/krusader/Panel/krinterbriefview.cpp +++ b/krusader/Panel/krinterbriefview.cpp @@ -1,716 +1,698 @@ /***************************************************************************** * Copyright (C) 2009 Csaba Karai * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This package is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this package; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ #include "krinterbriefview.h" // QtCore #include #include #include #include // QtGui #include #include #include // QtWidgets #include #include #include #include #include #include #include #include "krviewfactory.h" #include "krviewitemdelegate.h" #include "krviewitem.h" #include "krvfsmodel.h" #include "krmousehandler.h" #include "krcolorcache.h" #include "../FileSystem/krpermhandler.h" #include "../defaults.h" #include "../GUI/krstyleproxy.h" KrInterBriefView::KrInterBriefView(QWidget *parent, KrViewInstance &instance, KConfig *cfg) : QAbstractItemView(parent), KrInterView(instance, cfg, this), _header(0) { setWidget(this); setModel(_model); setSelectionMode(QAbstractItemView::NoSelection); setSelectionModel(new DummySelectionModel(_model, this)); KConfigGroup grpSvr(_config, "Look&Feel"); _viewFont = grpSvr.readEntry("Filelist Font", _FilelistFont); KrStyleProxy *style = new KrStyleProxy(); style->setParent(this); setStyle(style); + viewport()->setStyle(style); // for custom tooltip delay setItemDelegate(new KrViewItemDelegate()); setMouseTracking(true); setAcceptDrops(true); setDropIndicatorShown(true); connect(_mouseHandler, SIGNAL(renameCurrentItem()), SLOT(renameCurrentItem())); _model->setExtensionEnabled(false); _model->setAlternatingTable(true); connect(_model, SIGNAL(layoutChanged()), SLOT(updateGeometries())); } KrInterBriefView::~KrInterBriefView() { delete _properties; _properties = 0; delete _operator; _operator = 0; } void KrInterBriefView::doRestoreSettings(KConfigGroup group) { _properties->numberOfColumns = group.readEntry("Number Of Brief Columns", _NumberOfBriefColumns); if (_properties->numberOfColumns < 1) _properties->numberOfColumns = 1; else if (_properties->numberOfColumns > MAX_BRIEF_COLS) _properties->numberOfColumns = MAX_BRIEF_COLS; _numOfColumns = _properties->numberOfColumns; KrInterView::doRestoreSettings(group); updateGeometries(); } void KrInterBriefView::saveSettings(KConfigGroup grp, KrViewProperties::PropertyType properties) { KrInterView::saveSettings(grp, properties); if(properties & KrViewProperties::PropColumns) grp.writeEntry("Number Of Brief Columns", _numOfColumns); } int KrInterBriefView::itemsPerPage() { int height = getItemHeight(); if (height == 0) height ++; int numRows = viewport()->height() / height; return numRows; } void KrInterBriefView::updateView() { } void KrInterBriefView::setup() { _header = new QHeaderView(Qt::Horizontal, this); _header->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter); _header->setParent(this); _header->setModel(_model); _header->hideSection(KrViewProperties::Type); _header->hideSection(KrViewProperties::Permissions); _header->hideSection(KrViewProperties::KrPermissions); _header->hideSection(KrViewProperties::Owner); _header->hideSection(KrViewProperties::Group); _header->setStretchLastSection(true); _header->setSectionResizeMode(QHeaderView::Fixed); _header->setSectionsClickable(true); _header->setSortIndicatorShown(true); connect(_header, SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), _model, SLOT(sort(int,Qt::SortOrder))); _header->installEventFilter(this); _numOfColumns = _properties->numberOfColumns; setSortMode(_properties->sortColumn, (_properties->sortOptions & KrViewProperties::Descending)); } void KrInterBriefView::keyPressEvent(QKeyEvent *e) { if (!e || !_model->ready()) return ; // subclass bug if (handleKeyEvent(e)) return; QAbstractItemView::keyPressEvent(e); } bool KrInterBriefView::handleKeyEvent(QKeyEvent *e) { if ((e->key() != Qt::Key_Left && e->key() != Qt::Key_Right) && (KrView::handleKeyEvent(e))) // did the view class handled the event? return true; switch (e->key()) { case Qt::Key_Right : { if (e->modifiers() == Qt::ControlModifier) { // let the panel handle it e->ignore(); break; } KrViewItem *i = getCurrentKrViewItem(); KrViewItem *newCurrent = i; if (!i) break; int num = itemsPerPage() + 1; if (e->modifiers() & Qt::ShiftModifier) i->setSelected(!i->isSelected()); while (i && num > 0) { if (e->modifiers() & Qt::ShiftModifier) i->setSelected(!i->isSelected()); newCurrent = i; i = getNext(i); num--; } if (newCurrent) { setCurrentKrViewItem(newCurrent); makeCurrentVisible(); } if (e->modifiers() & Qt::ShiftModifier) op()->emitSelectionChanged(); return true; } case Qt::Key_Left : { if (e->modifiers() == Qt::ControlModifier) { // let the panel handle it e->ignore(); break; } KrViewItem *i = getCurrentKrViewItem(); KrViewItem *newCurrent = i; if (!i) break; int num = itemsPerPage() + 1; if (e->modifiers() & Qt::ShiftModifier) i->setSelected(!i->isSelected()); while (i && num > 0) { if (e->modifiers() & Qt::ShiftModifier) i->setSelected(!i->isSelected()); newCurrent = i; i = getPrev(i); num--; } if (newCurrent) { setCurrentKrViewItem(newCurrent); makeCurrentVisible(); } if (e->modifiers() & Qt::ShiftModifier) op()->emitSelectionChanged(); return true; } } return false; } void KrInterBriefView::wheelEvent(QWheelEvent *ev) { if (!_mouseHandler->wheelEvent(ev)) QApplication::sendEvent(horizontalScrollBar(), ev); } bool KrInterBriefView::eventFilter(QObject *object, QEvent *event) { if (object == _header) { if (event->type() == QEvent::ContextMenu) { QContextMenuEvent *me = (QContextMenuEvent *)event; showContextMenu(me->globalPos()); return true; } } return false; } void KrInterBriefView::showContextMenu(const QPoint & p) { QMenu popup(this); popup.setTitle(i18n("Columns")); int COL_ID = 14700; for (int i = 1; i <= MAX_BRIEF_COLS; i++) { QAction *act = popup.addAction(QString("%1").arg(i)); act->setData(QVariant(COL_ID + i)); act->setCheckable(true); act->setChecked(properties()->numberOfColumns == i); } QAction * res = popup.exec(p); int result = -1; if (res && res->data().canConvert()) result = res->data().toInt(); if (result > COL_ID && result <= COL_ID + MAX_BRIEF_COLS) { _properties->numberOfColumns = result - COL_ID; _numOfColumns = _properties->numberOfColumns; updateGeometries(); op()->settingsChanged(KrViewProperties::PropColumns); } } QRect KrInterBriefView::visualRect(const QModelIndex&ndx) const { int width = (viewport()->width()) / _numOfColumns; if ((viewport()->width()) % _numOfColumns) width++; int height = getItemHeight(); int numRows = viewport()->height() / height; if (numRows == 0) numRows++; int x = width * (ndx.row() / numRows); int y = height * (ndx.row() % numRows); return mapToViewport(QRect(x, y, width, height)); } void KrInterBriefView::scrollTo(const QModelIndex &ndx, QAbstractItemView::ScrollHint hint) { const QRect rect = visualRect(ndx); if (hint == EnsureVisible && viewport()->rect().contains(rect)) { setDirtyRegion(rect); return; } const QRect area = viewport()->rect(); const bool leftOf = rect.left() < area.left(); const bool rightOf = rect.right() > area.right(); int horizontalValue = horizontalScrollBar()->value(); if (leftOf) horizontalValue -= area.left() - rect.left(); else if (rightOf) horizontalValue += rect.right() - area.right(); horizontalScrollBar()->setValue(horizontalValue); } QModelIndex KrInterBriefView::indexAt(const QPoint& p) const { int x = p.x() + horizontalOffset(); int y = p.y() + verticalOffset(); int itemWidth = (viewport()->width()) / _numOfColumns; if ((viewport()->width()) % _numOfColumns) itemWidth++; int itemHeight = getItemHeight(); int numRows = viewport()->height() / itemHeight; if (numRows == 0) numRows++; int row = y / itemHeight; int col = x / itemWidth; int numColsTotal = _model->rowCount() / numRows; if(_model->rowCount() % numRows) numColsTotal++; if(row < numRows && col < numColsTotal) return _model->index((col * numRows) + row, 0); return QModelIndex(); } QModelIndex KrInterBriefView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers) { if (_model->rowCount() == 0) return QModelIndex(); QModelIndex current = currentIndex(); if (!current.isValid()) return _model->index(0, 0); switch (cursorAction) { case MoveLeft: case MovePageDown: { int newRow = current.row() - itemsPerPage(); if (newRow < 0) newRow = 0; return _model->index(newRow, 0); } case MoveRight: case MovePageUp: { int newRow = current.row() + itemsPerPage(); if (newRow >= _model->rowCount()) newRow = _model->rowCount() - 1; return _model->index(newRow, 0); } case MovePrevious: case MoveUp: { int newRow = current.row() - 1; if (newRow < 0) newRow = 0; return _model->index(newRow, 0); } case MoveNext: case MoveDown: { int newRow = current.row() + 1; if (newRow >= _model->rowCount()) newRow = _model->rowCount() - 1; return _model->index(newRow, 0); } case MoveHome: return _model->index(0, 0); case MoveEnd: return _model->index(_model->rowCount() - 1, 0); } return current; } int KrInterBriefView::horizontalOffset() const { return horizontalScrollBar()->value(); } int KrInterBriefView::verticalOffset() const { return 0; } bool KrInterBriefView::isIndexHidden(const QModelIndex&ndx) const { return ndx.column() != 0; } #if 0 QRegion KrInterBriefView::visualRegionForSelection(const QItemSelection &selection) const { if (selection.isEmpty()) return QRegion(); QRegion selectionRegion; for (int i = 0; i < selection.count(); ++i) { QItemSelectionRange range = selection.at(i); if (!range.isValid()) continue; QModelIndex leftIndex = range.topLeft(); if (!leftIndex.isValid()) continue; const QRect leftRect = visualRect(leftIndex); int top = leftRect.top(); QModelIndex rightIndex = range.bottomRight(); if (!rightIndex.isValid()) continue; const QRect rightRect = visualRect(rightIndex); int bottom = rightRect.bottom(); if (top > bottom) qSwap(top, bottom); int height = bottom - top + 1; QRect combined = leftRect | rightRect; combined.setX(range.left()); selectionRegion += combined; } return selectionRegion; } #endif void KrInterBriefView::paintEvent(QPaintEvent *e) { QStyleOptionViewItem option = viewOptions(); option.widget = this; option.decorationSize = QSize(_fileIconSize, _fileIconSize); option.decorationPosition = QStyleOptionViewItem::Left; QPainter painter(viewport()); QModelIndex curr = currentIndex(); QVector intersectVector; QRect area = e->rect(); area.adjust(horizontalOffset(), verticalOffset(), horizontalOffset(), verticalOffset()); intersectionSet(area, intersectVector); foreach(const QModelIndex &mndx, intersectVector) { option.state = QStyle::State_None; option.rect = visualRect(mndx); painter.save(); itemDelegate()->paint(&painter, option, mndx); // (always) draw dashed line border around current item row const bool isCurrent = curr.isValid() && curr.row() == mndx.row(); if (isCurrent) { QStyleOptionFocusRect o; o.QStyleOption::operator=(option); QPalette::ColorGroup cg = QPalette::Normal; o.backgroundColor = option.palette.color(cg, QPalette::Background); style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, &painter); } painter.restore(); } } int KrInterBriefView::getItemHeight() const { int textHeight = QFontMetrics(_viewFont).height(); int height = textHeight; int iconSize = 0; if (properties()->displayIcons) iconSize = _fileIconSize; if (iconSize > textHeight) height = iconSize; if (height == 0) height++; return height; } void KrInterBriefView::updateGeometries() { if (_header) { QSize hint = _header->sizeHint(); setViewportMargins(0, hint.height(), 0, 0); QRect vg = viewport()->geometry(); QRect geometryRect(vg.left(), vg.top() - hint.height(), vg.width(), hint.height()); _header->setGeometry(geometryRect); int items = 0; for (int i = 0; i != _header->count(); i++) if (!_header->isSectionHidden(i)) items++; if (items == 0) items++; int sectWidth = viewport()->width() / items; for (int i = 0; i != _header->count(); i++) if (!_header->isSectionHidden(i)) _header->resizeSection(i, sectWidth); QMetaObject::invokeMethod(_header, "updateGeometries"); } if (_model->rowCount() <= 0) horizontalScrollBar()->setRange(0, 0); else { int itemsPerColumn = viewport()->height() / getItemHeight(); if (itemsPerColumn <= 0) itemsPerColumn = 1; int columnWidth = (viewport()->width()) / _numOfColumns; if ((viewport()->width()) % _numOfColumns) columnWidth++; int maxWidth = _model->rowCount() / itemsPerColumn; if (_model->rowCount() % itemsPerColumn) maxWidth++; maxWidth *= columnWidth; if (maxWidth > viewport()->width()) { horizontalScrollBar()->setSingleStep(columnWidth); horizontalScrollBar()->setPageStep(columnWidth * _numOfColumns); horizontalScrollBar()->setRange(0, maxWidth - viewport()->width()); } else { horizontalScrollBar()->setRange(0, 0); } } QAbstractItemView::updateGeometries(); } void KrInterBriefView::setSortMode(KrViewProperties::ColumnType sortColumn, bool descending) { Qt::SortOrder sortDir = descending ? Qt::DescendingOrder : Qt::AscendingOrder; _header->setSortIndicator(sortColumn, sortDir); } int KrInterBriefView::elementWidth(const QModelIndex & index) { QString text = index.data(Qt::DisplayRole).toString(); int textWidth = QFontMetrics(_viewFont).width(text); const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; textWidth += 2 * textMargin; QVariant decor = index.data(Qt::DecorationRole); if (decor.isValid() && decor.type() == QVariant::Pixmap) { QPixmap p = decor.value(); textWidth += p.width() + 2 * textMargin; } return textWidth; } void KrInterBriefView::intersectionSet(const QRect &rect, QVector &ndxList) { int maxNdx = _model->rowCount(); int width = (viewport()->width()) / _numOfColumns; if ((viewport()->width()) % _numOfColumns) width++; int height = getItemHeight(); int items = viewport()->height() / height; if (items == 0) items++; int xmin = -1; int ymin = -1; int xmax = -1; int ymax = -1; xmin = rect.x() / width; ymin = rect.y() / height; xmax = (rect.x() + rect.width()) / width; if ((rect.x() + rect.width()) % width) xmax++; ymax = (rect.y() + rect.height()) / height; if ((rect.y() + rect.height()) % height) ymax++; for (int i = ymin; i < ymax; i++) for (int j = xmin; j < xmax; j++) { int ndx = j * items + i; if (ndx < maxNdx) ndxList.append(_model->index(ndx, 0)); } } QRect KrInterBriefView::itemRect(const FileItem *item) { return visualRect(_model->fileItemIndex(item)); } void KrInterBriefView::copySettingsFrom(KrView *other) { if(other->instance() == instance()) { // the other view is of the same type KrInterBriefView *v = static_cast(other); int column = v->_model->lastSortOrder(); Qt::SortOrder sortDir = v->_model->lastSortDir(); _header->setSortIndicator(column, sortDir); _model->sort(column, sortDir); setFileIconSize(v->fileIconSize()); } } void KrInterBriefView::setFileIconSize(int size) { KrView::setFileIconSize(size); setIconSize(QSize(fileIconSize(), fileIconSize())); updateGeometries(); } void KrInterBriefView::currentChanged(const QModelIndex & current, const QModelIndex & previous) { if (_model->ready()) { KrViewItem * item = getKrViewItem(currentIndex()); op()->emitCurrentChanged(item); } QAbstractItemView::currentChanged(current, previous); } void KrInterBriefView::renameCurrentItem() { QModelIndex cIndex = currentIndex(); QModelIndex nameIndex = _model->index(cIndex.row(), KrViewProperties::Name); edit(nameIndex); updateEditorData(); update(nameIndex); } bool KrInterBriefView::event(QEvent * e) { _mouseHandler->otherEvent(e); return QAbstractItemView::event(e); } void KrInterBriefView::mousePressEvent(QMouseEvent * ev) { if (!_mouseHandler->mousePressEvent(ev)) QAbstractItemView::mousePressEvent(ev); } void KrInterBriefView::mouseReleaseEvent(QMouseEvent * ev) { if (!_mouseHandler->mouseReleaseEvent(ev)) QAbstractItemView::mouseReleaseEvent(ev); } void KrInterBriefView::mouseDoubleClickEvent(QMouseEvent *ev) { if (!_mouseHandler->mouseDoubleClickEvent(ev)) QAbstractItemView::mouseDoubleClickEvent(ev); } void KrInterBriefView::mouseMoveEvent(QMouseEvent * ev) { if (!_mouseHandler->mouseMoveEvent(ev)) QAbstractItemView::mouseMoveEvent(ev); } void KrInterBriefView::dragEnterEvent(QDragEnterEvent *ev) { if (!_mouseHandler->dragEnterEvent(ev)) QAbstractItemView::dragEnterEvent(ev); } void KrInterBriefView::dragMoveEvent(QDragMoveEvent *ev) { QAbstractItemView::dragMoveEvent(ev); _mouseHandler->dragMoveEvent(ev); } void KrInterBriefView::dragLeaveEvent(QDragLeaveEvent *ev) { if (!_mouseHandler->dragLeaveEvent(ev)) QAbstractItemView::dragLeaveEvent(ev); } void KrInterBriefView::dropEvent(QDropEvent *ev) { if (!_mouseHandler->dropEvent(ev)) QAbstractItemView::dropEvent(ev); } -bool KrInterBriefView::viewportEvent(QEvent * event) -{ - if (event->type() == QEvent::ToolTip) { - QHelpEvent *he = static_cast(event); - const QModelIndex index = indexAt(he->pos()); - - if (index.isValid()) { - int width = visualRect(index).width(); - int textWidth = elementWidth(index); - - if (textWidth <= width) { - event->accept(); - return true; - } - } - } - return QAbstractItemView::viewportEvent(event); -} - QRect KrInterBriefView::mapToViewport(const QRect &rect) const { if (!rect.isValid()) return rect; QRect result = rect; int dx = -horizontalOffset(); int dy = -verticalOffset(); result.adjust(dx, dy, dx, dy); return result; } diff --git a/krusader/Panel/krinterbriefview.h b/krusader/Panel/krinterbriefview.h index 0e96e98f..88bc0230 100644 --- a/krusader/Panel/krinterbriefview.h +++ b/krusader/Panel/krinterbriefview.h @@ -1,120 +1,119 @@ /***************************************************************************** * Copyright (C) 2009 Csaba Karai * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This package is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this package; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ #ifndef KRINTERBRIEFVIEW_H #define KRINTERBRIEFVIEW_H // QtCore #include // QtGui #include // QtWidgets #include #include #include #include "krinterview.h" /** * @brief Compact view showing only icon and file name of view items */ class KrInterBriefView : public QAbstractItemView, public KrInterView { Q_OBJECT public: KrInterBriefView(QWidget *parent, KrViewInstance &instance, KConfig *cfg); virtual ~KrInterBriefView(); // ---- reimplemented from QAbstractItemView ---- QRect visualRect(const QModelIndex&) const Q_DECL_OVERRIDE; QModelIndex indexAt(const QPoint&) const Q_DECL_OVERRIDE; void scrollTo(const QModelIndex &, QAbstractItemView::ScrollHint = QAbstractItemView::EnsureVisible) Q_DECL_OVERRIDE; // ---- reimplemented from KrView ---- int itemsPerPage() Q_DECL_OVERRIDE; void updateView() Q_DECL_OVERRIDE; bool ensureVisibilityAfterSelect() Q_DECL_OVERRIDE { return false; } void setSortMode(KrViewProperties::ColumnType sortColumn, bool descending) Q_DECL_OVERRIDE; // ---- reimplemented from QAbstractItemView ---- // Don't do anything, selections are handled by the mouse handler void setSelection(const QRect &, QItemSelectionModel::SelectionFlags) Q_DECL_OVERRIDE {} void selectAll() Q_DECL_OVERRIDE {} // this shouldn't be called QRegion visualRegionForSelection(const QItemSelection&) const Q_DECL_OVERRIDE { return QRegion(); } // ---- reimplemented from KrView ---- void setFileIconSize(int size) Q_DECL_OVERRIDE; protected slots: // ---- reimplemented from QAbstractItemView ---- void updateGeometries() Q_DECL_OVERRIDE; // ---- reimplemented from KrView ---- void currentChanged(const QModelIndex & current, const QModelIndex & previous) Q_DECL_OVERRIDE; void renameCurrentItem() Q_DECL_OVERRIDE; protected: // ---- reimplemented from KrView ---- bool handleKeyEvent(QKeyEvent *e) Q_DECL_OVERRIDE; // ---- reimplemented from QAbstractItemView ---- bool eventFilter(QObject *object, QEvent *event) Q_DECL_OVERRIDE; void keyPressEvent(QKeyEvent *e) Q_DECL_OVERRIDE; void paintEvent(QPaintEvent *e) Q_DECL_OVERRIDE; QModelIndex moveCursor(QAbstractItemView::CursorAction, Qt::KeyboardModifiers) Q_DECL_OVERRIDE; int horizontalOffset() const Q_DECL_OVERRIDE; int verticalOffset() const Q_DECL_OVERRIDE; bool isIndexHidden(const QModelIndex&) const Q_DECL_OVERRIDE; // QRegion visualRegionForSelection(const QItemSelection&) const Q_DECL_OVERRIDE; bool event(QEvent * e) Q_DECL_OVERRIDE; void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE; void mouseReleaseEvent(QMouseEvent *) Q_DECL_OVERRIDE; void mouseDoubleClickEvent(QMouseEvent *ev) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent *) Q_DECL_OVERRIDE; void wheelEvent(QWheelEvent *) Q_DECL_OVERRIDE; void dragEnterEvent(QDragEnterEvent *e) Q_DECL_OVERRIDE; void dragMoveEvent(QDragMoveEvent *e) Q_DECL_OVERRIDE; void dragLeaveEvent(QDragLeaveEvent *e) Q_DECL_OVERRIDE; void dropEvent(QDropEvent *) Q_DECL_OVERRIDE; - bool viewportEvent(QEvent * event) Q_DECL_OVERRIDE; // ---- reimplemented from KrView ---- void setup() Q_DECL_OVERRIDE; void doRestoreSettings(KConfigGroup group) Q_DECL_OVERRIDE; void saveSettings(KConfigGroup grp, KrViewProperties::PropertyType properties) Q_DECL_OVERRIDE; void copySettingsFrom(KrView *other) Q_DECL_OVERRIDE; QRect itemRect(const FileItem *fileitem) Q_DECL_OVERRIDE; void showContextMenu(const QPoint & p) Q_DECL_OVERRIDE; QRect mapToViewport(const QRect &rect) const; int getItemHeight() const; int elementWidth(const QModelIndex & index); void intersectionSet(const QRect &, QVector &); private: QFont _viewFont; int _numOfColumns; QHeaderView * _header; }; #endif // KRINTERBRIEFVIEW_H diff --git a/krusader/Panel/krinterdetailedview.cpp b/krusader/Panel/krinterdetailedview.cpp index 7cdd17c9..16f1b2b3 100644 --- a/krusader/Panel/krinterdetailedview.cpp +++ b/krusader/Panel/krinterdetailedview.cpp @@ -1,421 +1,429 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 Rafi Yanai * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This package is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this package; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ #include "krinterdetailedview.h" // QtCore #include #include // QtWidgets +#include #include #include #include -#include +#include #include #include #include #include "krviewfactory.h" #include "krviewitemdelegate.h" #include "krviewitem.h" #include "krvfsmodel.h" #include "../FileSystem/krpermhandler.h" #include "../defaults.h" #include "../krglobal.h" #include "krmousehandler.h" #include "krcolorcache.h" #include "../GUI/krstyleproxy.h" KrInterDetailedView::KrInterDetailedView(QWidget *parent, KrViewInstance &instance, KConfig *cfg): QTreeView(parent), KrInterView(instance, cfg, this), _autoResizeColumns(true) { connect(_mouseHandler, SIGNAL(renameCurrentItem()), this, SLOT(renameCurrentItem())); setWidget(this); KConfigGroup grpSvr(_config, "Look&Feel"); _viewFont = grpSvr.readEntry("Filelist Font", _FilelistFont); setModel(_model); setRootIsDecorated(false); setItemsExpandable(false); setAllColumnsShowFocus(true); setUniformRowHeights(true); - KrStyleProxy *krstyle = new KrStyleProxy(); - krstyle->setParent(this); - setStyle(krstyle); - setItemDelegate(new KrViewItemDelegate(this)); setMouseTracking(true); setAcceptDrops(true); setDropIndicatorShown(true); setSelectionMode(QAbstractItemView::NoSelection); setSelectionModel(new DummySelectionModel(_model, this)); header()->installEventFilter(this); header()->setSectionResizeMode(QHeaderView::Interactive); header()->setStretchLastSection(false); + KrStyleProxy *style = new KrStyleProxy(); + style->setParent(this); + setStyle(style); + viewport()->setStyle(style); // for custom tooltip delay + + setItemDelegate(new KrViewItemDelegate(this)); + connect(header(), SIGNAL(sectionResized(int,int,int)), this, SLOT(sectionResized(int,int,int))); connect(header(), SIGNAL(sectionMoved(int,int,int)), this, SLOT(sectionMoved(int,int,int))); } KrInterDetailedView::~KrInterDetailedView() { delete _properties; _properties = 0; delete _operator; _operator = 0; } void KrInterDetailedView::currentChanged(const QModelIndex & current, const QModelIndex & previous) { if (_model->ready()) { KrViewItem * item = getKrViewItem(currentIndex()); op()->emitCurrentChanged(item); } QTreeView::currentChanged(current, previous); } void KrInterDetailedView::doRestoreSettings(KConfigGroup grp) { _autoResizeColumns = grp.readEntry("AutoResizeColumns", true); QByteArray savedState = grp.readEntry("Saved State", QByteArray()); if (savedState.isEmpty()) { hideColumn(KrViewProperties::Type); hideColumn(KrViewProperties::Permissions); hideColumn(KrViewProperties::Owner); hideColumn(KrViewProperties::Group); header()->resizeSection(KrViewProperties::Ext, QFontMetrics(_viewFont).width("tar.bz2 ")); header()->resizeSection(KrViewProperties::KrPermissions, QFontMetrics(_viewFont).width("rwx ")); header()->resizeSection(KrViewProperties::Size, QFontMetrics(_viewFont).width("9") * 10); QDateTime tmp(QDate(2099, 12, 29), QTime(23, 59)); QString desc = QLocale().toString(tmp, QLocale::ShortFormat) + " "; header()->resizeSection(KrViewProperties::Modified, QFontMetrics(_viewFont).width(desc)); } else { header()->restoreState(savedState); _model->setExtensionEnabled(!isColumnHidden(KrViewProperties::Ext)); } KrInterView::doRestoreSettings(grp); } void KrInterDetailedView::saveSettings(KConfigGroup grp, KrViewProperties::PropertyType properties) { KrInterView::saveSettings(grp, properties); grp.writeEntry("AutoResizeColumns", _autoResizeColumns); if(properties & KrViewProperties::PropColumns) { QByteArray state = header()->saveState(); grp.writeEntry("Saved State", state); } } int KrInterDetailedView::itemsPerPage() { QRect rect = visualRect(currentIndex()); if (!rect.isValid()) { for (int i = 0; i != _model->rowCount(); i++) { rect = visualRect(_model->index(i, 0)); if (rect.isValid()) break; } } if (!rect.isValid()) return 0; int size = (height() - header()->height()) / rect.height(); if (size < 0) size = 0; return size; } void KrInterDetailedView::updateView() { } void KrInterDetailedView::setup() { setSortMode(_properties->sortColumn, (_properties->sortOptions & KrViewProperties::Descending)); setSortingEnabled(true); } void KrInterDetailedView::keyPressEvent(QKeyEvent *e) { if (!e || !_model->ready()) return ; // subclass bug if (handleKeyEvent(e)) // did the view class handled the event? return; QTreeView::keyPressEvent(e); } void KrInterDetailedView::mousePressEvent(QMouseEvent * ev) { if (!_mouseHandler->mousePressEvent(ev)) QTreeView::mousePressEvent(ev); } void KrInterDetailedView::mouseReleaseEvent(QMouseEvent * ev) { if (!_mouseHandler->mouseReleaseEvent(ev)) QTreeView::mouseReleaseEvent(ev); } void KrInterDetailedView::mouseDoubleClickEvent(QMouseEvent *ev) { if (!_mouseHandler->mouseDoubleClickEvent(ev)) QTreeView::mouseDoubleClickEvent(ev); } void KrInterDetailedView::mouseMoveEvent(QMouseEvent * ev) { if (!_mouseHandler->mouseMoveEvent(ev)) QTreeView::mouseMoveEvent(ev); } void KrInterDetailedView::wheelEvent(QWheelEvent *ev) { if (!_mouseHandler->wheelEvent(ev)) QTreeView::wheelEvent(ev); } void KrInterDetailedView::dragEnterEvent(QDragEnterEvent *ev) { if (!_mouseHandler->dragEnterEvent(ev)) QTreeView::dragEnterEvent(ev); } void KrInterDetailedView::dragMoveEvent(QDragMoveEvent *ev) { QTreeView::dragMoveEvent(ev); _mouseHandler->dragMoveEvent(ev); } void KrInterDetailedView::dragLeaveEvent(QDragLeaveEvent *ev) { if (!_mouseHandler->dragLeaveEvent(ev)) QTreeView::dragLeaveEvent(ev); } void KrInterDetailedView::dropEvent(QDropEvent *ev) { if (!_mouseHandler->dropEvent(ev)) QTreeView::dropEvent(ev); } bool KrInterDetailedView::event(QEvent * e) { _mouseHandler->otherEvent(e); return QTreeView::event(e); } void KrInterDetailedView::renameCurrentItem() { QModelIndex cIndex = currentIndex(); QModelIndex nameIndex = _model->index(cIndex.row(), KrViewProperties::Name); edit(nameIndex); updateEditorData(); update(nameIndex); } bool KrInterDetailedView::eventFilter(QObject *object, QEvent *event) { if (object == header()) { if (event->type() == QEvent::ContextMenu) { QContextMenuEvent *me = (QContextMenuEvent *)event; showContextMenu(me->globalPos()); return true; } else if (event->type() == QEvent::Resize) { recalculateColumnSizes(); return false; } } return false; } void KrInterDetailedView::showContextMenu(const QPoint & p) { QMenu popup(this); popup.setTitle(i18n("Columns")); QVector actions; for(int i = KrViewProperties::Ext; i < KrViewProperties::MAX_COLUMNS; i++) { QString text = (_model->headerData(i, Qt::Horizontal)).toString(); QAction *act = popup.addAction(text); act->setCheckable(true); act->setChecked(!header()->isSectionHidden(i)); act->setData(i); actions.append(act); } popup.addSeparator(); QAction *actAutoResize = popup.addAction(i18n("Automatically Resize Columns")); actAutoResize->setCheckable(true); actAutoResize->setChecked(_autoResizeColumns); QAction *res = popup.exec(p); if (res == 0) return; if(res == actAutoResize) { _autoResizeColumns = actAutoResize->isChecked(); recalculateColumnSizes(); } else { int column = res->data().toInt(); if(header()->isSectionHidden(column)) header()->showSection(column); else header()->hideSection(column); if(KrViewProperties::Ext == column) _model->setExtensionEnabled(!header()->isSectionHidden(KrViewProperties::Ext)); } op()->settingsChanged(KrViewProperties::PropColumns); } void KrInterDetailedView::sectionResized(int /*column*/, int oldSize, int newSize) { // *** taken from dolphin *** // If the user changes the size of the headers, the autoresize feature should be // turned off. As there is no dedicated interface to find out whether the header // section has been resized by the user or by a resize event, another approach is used. // Attention: Take care when changing the if-condition to verify that there is no // regression in combination with bug 178630 (see fix in comment #8). if ((QApplication::mouseButtons() & Qt::LeftButton) && header()->underMouse()) { _autoResizeColumns = false; op()->settingsChanged(KrViewProperties::PropColumns); } if (oldSize == newSize || !_model->ready()) return; recalculateColumnSizes(); } void KrInterDetailedView::sectionMoved(int /*logicalIndex*/, int /*oldVisualIndex*/, int /*newVisualIndex*/) { op()->settingsChanged(KrViewProperties::PropColumns); } void KrInterDetailedView::recalculateColumnSizes() { if(!_autoResizeColumns) return; int sum = 0; for (int i = 0; i != _model->columnCount(); i++) { if (!isColumnHidden(i)) sum += header()->sectionSize(i); } if (sum != header()->width()) { int delta = sum - header()->width(); int nameSize = header()->sectionSize(KrViewProperties::Name); if (nameSize - delta > 20) header()->resizeSection(KrViewProperties::Name, nameSize - delta); } } bool KrInterDetailedView::viewportEvent(QEvent * event) { if (event->type() == QEvent::ToolTip) { + // only show tooltip if column is not wide enough to show all text. In this case the column + // data text is abbreviated and the full text is shown as tooltip, see KrVfsModel::data(). + QHelpEvent *he = static_cast(event); const QModelIndex index = indexAt(he->pos()); - - if (index.isValid()) { + // name column has a detailed tooltip + if (index.isValid() && index.column() != KrViewProperties::Name) { int width = header()->sectionSize(index.column()); QString text = index.data(Qt::DisplayRole).toString(); int textWidth = QFontMetrics(_viewFont).width(text); const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; textWidth += 2 * textMargin; QVariant decor = index.data(Qt::DecorationRole); if (decor.isValid() && decor.type() == QVariant::Pixmap) { QPixmap p = decor.value(); textWidth += p.width() + 2 * textMargin; } if (textWidth <= width) { + QToolTip::hideText(); event->accept(); return true; } } } return QTreeView::viewportEvent(event); } void KrInterDetailedView::drawRow(QPainter *painter, const QStyleOptionViewItem &options, const QModelIndex &index) const { QTreeView::drawRow(painter, options, index); // (always) draw dashed line border around current item row. This is done internally in // QTreeView::drawRow() only when panel is focused, we have to repeat it here. if (index == currentIndex()) { QStyleOptionFocusRect o; o.backgroundColor = options.palette.color(QPalette::Normal, QPalette::Background); const QRect focusRect(0, options.rect.y(), header()->length(), options.rect.height()); o.rect = style()->visualRect(layoutDirection(), viewport()->rect(), focusRect); style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter); } } void KrInterDetailedView::setSortMode(KrViewProperties::ColumnType sortColumn, bool descending) { Qt::SortOrder sortDir = descending ? Qt::DescendingOrder : Qt::AscendingOrder; sortByColumn(sortColumn, sortDir); } void KrInterDetailedView::setFileIconSize(int size) { KrView::setFileIconSize(size); setIconSize(QSize(fileIconSize(), fileIconSize())); } QRect KrInterDetailedView::itemRect(const FileItem *item) { QRect r = visualRect(_model->fileItemIndex(item)); r.setLeft(0); r.setWidth(header()->length()); return r; } void KrInterDetailedView::copySettingsFrom(KrView *other) { if(other->instance() == instance()) { // the other view is of the same type KrInterDetailedView *v = static_cast(other); _autoResizeColumns = v->_autoResizeColumns; header()->restoreState(v->header()->saveState()); _model->setExtensionEnabled(!isColumnHidden(KrViewProperties::Ext)); recalculateColumnSizes(); setFileIconSize(v->fileIconSize()); } } diff --git a/krusader/Panel/krsort.cpp b/krusader/Panel/krsort.cpp index 24b90d22..3a754b55 100644 --- a/krusader/Panel/krsort.cpp +++ b/krusader/Panel/krsort.cpp @@ -1,356 +1,344 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 Rafi Yanai * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This package is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this package; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ #include "krsort.h" -// QtCore -#include -#include - #include "krview.h" #include "../FileSystem/fileitem.h" -#include "../FileSystem/krpermhandler.h" namespace KrSort { void SortProps::init(FileItem *fileitem, int col, const KrViewProperties * props, bool isDummy, bool asc, int origNdx, QVariant customData) { _col = col; _prop = props; _isdummy = isDummy; _ascending = asc; _fileItem = fileitem; _index = origNdx; _name = fileitem->getName(); _customData = customData; if(_prop->sortOptions & KrViewProperties::IgnoreCase) _name = _name.toLower(); switch (_col) { case KrViewProperties::Ext: { if (fileitem->isDir()) { _ext = ""; } else { // check if the file has an extension const QString& fileitemName = fileitem->getName(); int loc = fileitemName.lastIndexOf('.'); if (loc > 0) { // avoid mishandling of .bashrc and friend // check if it has one of the predefined 'atomic extensions' for (QStringList::const_iterator i = props->atomicExtensions.begin(); i != props->atomicExtensions.end(); ++i) { if (fileitemName.endsWith(*i) && fileitemName != *i) { loc = fileitemName.length() - (*i).length(); break; } } _ext = _name.mid(loc); } else _ext = ""; } break; } case KrViewProperties::Type: { if (isDummy) _data = ""; else { - QMimeDatabase db; - QMimeType mt = db.mimeTypeForName(fileitem->getMime()); - if (mt.isValid()) - _data = mt.comment(); + _data = KrView::mimeTypeText(fileitem); } break; } case KrViewProperties::Permissions: { if (isDummy) _data = ""; else { - if (properties()->numericPermissions) { - QString perm; - _data = perm.sprintf("%.4o", fileitem->getMode() & PERM_BITMASK); - } else - _data = fileitem->getPerm(); + _data = KrView::permissionsText(properties(), fileitem); } break; } case KrViewProperties::KrPermissions: { if (isDummy) _data = ""; else { - _data = KrView::krPermissionString(fileitem); + _data = KrView::krPermissionText(fileitem); } break; } case KrViewProperties::Owner: { if (isDummy) _data = ""; else _data = fileitem->getOwner(); } case KrViewProperties::Group: { if (isDummy) _data = ""; else _data = fileitem->getGroup(); } default: break; } } // compares numbers within two strings int compareNumbers(QString& aS1, int& aPos1, QString& aS2, int& aPos2) { int res = 0; int start1 = aPos1; int start2 = aPos2; while (aPos1 < aS1.length() && aS1.at(aPos1).isDigit()) aPos1++; while (aPos2 < aS2.length() && aS2.at(aPos2).isDigit()) aPos2++; // the left-most difference determines what's bigger int i1 = aPos1 - 1; int i2 = aPos2 - 1; for (; i1 >= start1 || i2 >= start2; i1--, i2--) { int c1 = 0; int c2 = 0; if (i1 >= start1) c1 = aS1.at(i1).digitValue(); if (i2 >= start2) c2 = aS2.at(i2).digitValue(); if (c1 < c2) res = -1; else if (c1 > c2) res = 1; } return res; } bool compareTextsAlphabetical(QString& aS1, QString& aS2, const KrViewProperties * _viewProperties, bool aNumbers) { int lPositionS1 = 0; int lPositionS2 = 0; // sometimes, localeAwareCompare is not case sensitive. in that case, we need to fallback to a simple string compare (KDE bug #40131) bool lUseLocaleAware = ((_viewProperties->sortOptions & KrViewProperties::IgnoreCase) || _viewProperties->localeAwareCompareIsCaseSensitive) && (_viewProperties->sortOptions & KrViewProperties::LocaleAwareSort); int j = 0; QChar lchar1; QChar lchar2; while (true) { lchar1 = aS1[lPositionS1]; lchar2 = aS2[lPositionS2]; // detect numbers if (aNumbers && lchar1.isDigit() && lchar2.isDigit()) { int j = compareNumbers(aS1, lPositionS1, aS2, lPositionS2); if (j != 0) return j < 0; } else if (lUseLocaleAware && ((lchar1 >= 128 && ((lchar2 >= 'A' && lchar2 <= 'Z') || (lchar2 >= 'a' && lchar2 <= 'z') || lchar2 >= 128)) || (lchar2 >= 128 && ((lchar1 >= 'A' && lchar1 <= 'Z') || (lchar1 >= 'a' && lchar1 <= 'z') || lchar1 >= 128)) ) ) { // use localeAwareCompare when a unicode character is encountered j = QString::localeAwareCompare(lchar1, lchar2); if (j != 0) return j < 0; lPositionS1++; lPositionS2++; } else { // if characters are latin or localeAwareCompare is not case sensitive then use simple characters compare is enough if (lchar1 < lchar2) return true; if (lchar1 > lchar2) return false; lPositionS1++; lPositionS2++; } // at this point strings are equal, check if ends of strings are reached if (lPositionS1 == aS1.length() && lPositionS2 == aS2.length()) return false; if (lPositionS1 == aS1.length() && lPositionS2 < aS2.length()) return true; if (lPositionS1 < aS1.length() && lPositionS2 == aS2.length()) return false; } } bool compareTextsCharacterCode(QString& aS1, QString& aS2, const KrViewProperties * _viewProperties, bool aNumbers) { Q_UNUSED(_viewProperties); int lPositionS1 = 0; int lPositionS2 = 0; while (true) { // detect numbers if (aNumbers && aS1[lPositionS1].isDigit() && aS2[lPositionS2].isDigit()) { int j = compareNumbers(aS1, lPositionS1, aS2, lPositionS2); if (j != 0) return j < 0; } else { if (aS1[lPositionS1] < aS2[lPositionS2]) return true; if (aS1[lPositionS1] > aS2[lPositionS2]) return false; lPositionS1++; lPositionS2++; } // at this point strings are equal, check if ends of strings are reached if (lPositionS1 == aS1.length() && lPositionS2 == aS2.length()) return false; if (lPositionS1 == aS1.length() && lPositionS2 < aS2.length()) return true; if (lPositionS1 < aS1.length() && lPositionS2 == aS2.length()) return false; } } bool compareTextsKrusader(const QString &aS1, const QString &aS2, const KrViewProperties *_viewProperties) { // sometimes, localeAwareCompare is not case sensitive. in that case, we need to fallback to a simple string compare (KDE bug #40131) if (((_viewProperties->sortOptions & KrViewProperties::IgnoreCase) || _viewProperties->localeAwareCompareIsCaseSensitive) && (_viewProperties->sortOptions & KrViewProperties::LocaleAwareSort)) return QString::localeAwareCompare(aS1, aS2) < 0; else // if localeAwareCompare is not case sensitive then use simple compare is enough return QString::compare(aS1, aS2) < 0; } bool compareTexts(QString aS1, QString aS2, const KrViewProperties * _viewProperties, bool asc, bool isName) { //check empty strings if (aS1.length() == 0 && aS2.length() == 0) { return false; } else if (aS1.length() == 0) { return true; } else if (aS2.length() == 0) { return false; } if (isName) { if (aS1 == "..") { return !asc; } else { if (aS2 == "..") return asc; } } switch (_viewProperties->sortMethod) { case KrViewProperties::Alphabetical: return compareTextsAlphabetical(aS1, aS2, _viewProperties, false); case KrViewProperties::AlphabeticalNumbers: return compareTextsAlphabetical(aS1, aS2, _viewProperties, true); case KrViewProperties::CharacterCode: return compareTextsCharacterCode(aS1, aS2, _viewProperties, false); case KrViewProperties::CharacterCodeNumbers: return compareTextsCharacterCode(aS1, aS2, _viewProperties, true); case KrViewProperties::Krusader: default: return compareTextsKrusader(aS1, aS2, _viewProperties); } } bool itemLessThan(SortProps *sp, SortProps *sp2) { FileItem * file1 = sp->fileitem(); FileItem * file2 = sp2->fileitem(); bool isdir1 = file1->isDir(); bool isdir2 = file2->isDir(); bool dirsFirst = sp->properties()->sortOptions & KrViewProperties::DirsFirst; bool alwaysSortDirsByName = sp->properties()->sortOptions & KrViewProperties::AlwaysSortDirsByName && dirsFirst && isdir1 && isdir2; if(dirsFirst) { if (isdir1 && !isdir2) return sp->isAscending(); if (isdir2 && !isdir1) return !sp->isAscending(); } if (sp->isDummy()) return sp->isAscending(); if (sp2->isDummy()) return !sp->isAscending(); int column = sp->column(); if (dirsFirst && isdir1 && isdir2 && alwaysSortDirsByName) { alwaysSortDirsByName = !sp->isAscending(); column = KrViewProperties::Name; } switch (column) { case KrViewProperties::Name: return compareTexts(sp->name(), sp2->name(), sp->properties(), sp->isAscending(), true) ^ alwaysSortDirsByName; case KrViewProperties::Ext: if (sp->extension() == sp2->extension()) return compareTexts(sp->name(), sp2->name(), sp->properties(), sp->isAscending(), true); return compareTexts(sp->extension(), sp2->extension(), sp->properties(), sp->isAscending(), true); case KrViewProperties::Size: if (file1->getSize() == file2->getSize()) return compareTexts(sp->name(), sp2->name(), sp->properties(), sp->isAscending(), true); return file1->getSize() < file2->getSize(); case KrViewProperties::Modified: if (file1->getTime_t() == file2->getTime_t()) return compareTexts(sp->name(), sp2->name(), sp->properties(), sp->isAscending(), true); return file1->getTime_t() < file2->getTime_t(); case KrViewProperties::Type: case KrViewProperties::Permissions: case KrViewProperties::KrPermissions: case KrViewProperties::Owner: case KrViewProperties::Group: if (sp->data() == sp2->data()) return compareTexts(sp->name(), sp2->name(), sp->properties(), sp->isAscending(), true); return compareTexts(sp->data(), sp2->data(), sp->properties(), sp->isAscending(), true); } return sp->name() < sp2->name(); } bool itemGreaterThan(SortProps *sp, SortProps *sp2) { return !itemLessThan(sp, sp2); } Sorter::Sorter(int reserveItems, const KrViewProperties *viewProperties, LessThanFunc lessThanFunc, LessThanFunc greaterThanFunc) : _viewProperties(viewProperties), _lessThanFunc(lessThanFunc), _greaterThanFunc(greaterThanFunc) { _items.reserve(reserveItems); _itemStore.reserve(reserveItems); } void Sorter::addItem(FileItem *fileitem, bool isDummy, int idx, QVariant customData) { _itemStore << SortProps(fileitem, _viewProperties->sortColumn, _viewProperties, isDummy, !descending(), idx, customData); _items << &_itemStore.last(); } void Sorter::sort() { qStableSort(_items.begin(), _items.end(), descending() ? _greaterThanFunc : _lessThanFunc); } int Sorter::insertIndex(FileItem *fileitem, bool isDummy, QVariant customData) { SortProps props(fileitem, _viewProperties->sortColumn, _viewProperties, isDummy, !descending(), -1, customData); const QVector::iterator it = qLowerBound(_items.begin(), _items.end(), &props, descending() ? _greaterThanFunc : _lessThanFunc); if(it != _items.end()) return _items.indexOf((*it)); else return _items.count(); } bool Sorter::descending() const { return _viewProperties->sortOptions & KrViewProperties::Descending; } } // namespace KrSort diff --git a/krusader/Panel/krsort.h b/krusader/Panel/krsort.h index dc49d996..21d79d2c 100644 --- a/krusader/Panel/krsort.h +++ b/krusader/Panel/krsort.h @@ -1,125 +1,123 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 Rafi Yanai * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This package is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this package; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ #ifndef KRSORT_H #define KRSORT_H // QtCore #include #include #include -#define PERM_BITMASK (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) - class FileItem; class KrViewProperties; namespace KrSort { class SortProps { public: SortProps() {} SortProps(const SortProps& other) { init(other.fileitem(), other.column(), other.properties(), other.isDummy(), other.isAscending(), other.originalIndex(), other.customData()); } SortProps(FileItem *fileitem, int col, const KrViewProperties * props, bool isDummy, bool asc, int origNdx, QVariant customData) { init(fileitem, col, props, isDummy, asc, origNdx, customData); } inline int column() const { return _col; } inline const KrViewProperties * properties() const { return _prop; } inline bool isDummy() const { return _isdummy; } inline bool isAscending() const { return _ascending; } inline QString name() const { return _name; } inline QString extension() const { return _ext; } inline FileItem * fileitem() const { return _fileItem; } inline int originalIndex() const { return _index; } inline QString data() const { return _data; } inline const QVariant& customData() const { return _customData; } private: void init(FileItem *fileitem, int col, const KrViewProperties * props, bool isDummy, bool asc, int origNdx, QVariant customData); int _col; const KrViewProperties * _prop; bool _isdummy; FileItem * _fileItem; bool _ascending; QString _name; QString _ext; int _index; QString _data; QVariant _customData; }; bool compareTexts(QString aS1, QString aS2, const KrViewProperties * _viewProperties, bool asc, bool isName); bool itemLessThan(SortProps *sp, SortProps *sp2); bool itemGreaterThan(SortProps *sp, SortProps *sp2); typedef bool(*LessThanFunc)(SortProps*, SortProps*); class Sorter { public: Sorter(int reserveItems, const KrViewProperties *viewProperties, LessThanFunc lessThanFunc, LessThanFunc greaterThanFunc); Sorter(const Sorter &other); const QVector &items() const { return _items; } void sort(); void addItem(FileItem *fileitem, bool isDummy, int idx, QVariant customData); int insertIndex(FileItem *fileitem, bool isDummy, QVariant customData); private: bool descending() const; const KrViewProperties *_viewProperties; QVector _items; QVector _itemStore; LessThanFunc _lessThanFunc, _greaterThanFunc; }; } // namespace KrSort #endif // KRSORT_H diff --git a/krusader/Panel/krvfsmodel.cpp b/krusader/Panel/krvfsmodel.cpp index a90edc7e..f1cc4941 100644 --- a/krusader/Panel/krvfsmodel.cpp +++ b/krusader/Panel/krvfsmodel.cpp @@ -1,579 +1,597 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 Rafi Yanai * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This package is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this package; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ #include "krvfsmodel.h" #include "krcolorcache.h" #include "krinterview.h" #include "krpanel.h" #include "krview.h" #include "../defaults.h" #include "../krglobal.h" #include "../FileSystem/fileitem.h" -#include "../FileSystem/krpermhandler.h" - -// QtCore -#include -#include -#include -#include #include #include KrVfsModel::KrVfsModel(KrInterView * view): QAbstractListModel(0), _extensionEnabled(true), _view(view), _dummyFileItem(0), _ready(false), _justForSizeHint(false), _alternatingTable(false) { KConfigGroup grpSvr(krConfig, "Look&Feel"); _defaultFont = grpSvr.readEntry("Filelist Font", _FilelistFont); } void KrVfsModel::populate(const QList &files, FileItem *dummy) { _fileItems = files; _dummyFileItem = dummy; _ready = true; if(lastSortOrder() != KrViewProperties::NoColumn) sort(); else { emit layoutAboutToBeChanged(); for(int i = 0; i < _fileItems.count(); i++) { updateIndices(_fileItems[i], i); } emit layoutChanged(); } } KrVfsModel::~KrVfsModel() { } void KrVfsModel::clear(bool emitLayoutChanged) { if(!_fileItems.count()) return; emit layoutAboutToBeChanged(); // clear persistent indexes QModelIndexList oldPersistentList = persistentIndexList(); QModelIndexList newPersistentList; newPersistentList.reserve(oldPersistentList.size()); for (int i=0; i< oldPersistentList.size(); ++i) newPersistentList.append(QModelIndex()); changePersistentIndexList(oldPersistentList, newPersistentList); _fileItems.clear(); _fileItemNdx.clear(); _nameNdx.clear(); _urlNdx.clear(); _dummyFileItem = 0; if (emitLayoutChanged) emit layoutChanged(); } int KrVfsModel::rowCount(const QModelIndex& /*parent*/) const { return _fileItems.count(); } int KrVfsModel::columnCount(const QModelIndex& /*parent*/) const { return KrViewProperties::MAX_COLUMNS; } QVariant KrVfsModel::data(const QModelIndex& index, int role) const { if (!index.isValid() || index.row() >= rowCount()) return QVariant(); FileItem *fileitem = _fileItems.at(index.row()); if (fileitem == 0) return QVariant(); switch (role) { case Qt::FontRole: return _defaultFont; case Qt::EditRole: { if (index.column() == 0) { return fileitem->getName(); } return QVariant(); } case Qt::UserRole: { if (index.column() == 0) { return nameWithoutExtension(fileitem, false); } return QVariant(); } - case Qt::ToolTipRole: + case Qt::ToolTipRole: { + if (index.column() == KrViewProperties::Name) { + return fileitem == _dummyFileItem ? QVariant() : toolTipText(fileitem); + } + // breaktrough + } case Qt::DisplayRole: { switch (index.column()) { case KrViewProperties::Name: { return nameWithoutExtension(fileitem); } case KrViewProperties::Ext: { QString nameOnly = nameWithoutExtension(fileitem); const QString& fileitemName = fileitem->getName(); return fileitemName.mid(nameOnly.length() + 1); } case KrViewProperties::Size: { if (fileitem->isDir() && fileitem->getSize() <= 0) { //HACK add <> brackets AFTER translating - otherwise KUIT thinks it's a tag static QString label = QString("<") + i18nc("Show the string 'DIR' instead of file size in detailed view (for folders)", "DIR") + '>'; return label; } else - return KrView::sizeToString(properties(), fileitem->getSize()); + return KrView::sizeText(properties(), fileitem->getSize()); } case KrViewProperties::Type: { if (fileitem == _dummyFileItem) return QVariant(); - QMimeDatabase db; - QMimeType mt = db.mimeTypeForName(fileitem->getMime()); - if (mt.isValid()) - return mt.comment(); - return QVariant(); + const QString mimeType = KrView::mimeTypeText(fileitem); + return mimeType.isEmpty() ? QVariant() : mimeType; } case KrViewProperties::Modified: { if (fileitem == _dummyFileItem) return QVariant(); - time_t time = fileitem->getTime_t(); - struct tm* t = localtime((time_t *) & time); - - QDateTime tmp(QDate(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday), QTime(t->tm_hour, t->tm_min)); - return QLocale().toString(tmp, QLocale::ShortFormat); + return dateText(fileitem->getTime_t()); } case KrViewProperties::Permissions: { if (fileitem == _dummyFileItem) return QVariant(); - if (properties()->numericPermissions) { - QString perm; - return perm.sprintf("%.4o", fileitem->getMode() & PERM_BITMASK); - } - return fileitem->getPerm(); + return KrView::permissionsText(properties(), fileitem); } case KrViewProperties::KrPermissions: { if (fileitem == _dummyFileItem) return QVariant(); - return KrView::krPermissionString(fileitem); + return KrView::krPermissionText(fileitem); } case KrViewProperties::Owner: { if (fileitem == _dummyFileItem) return QVariant(); return fileitem->getOwner(); } case KrViewProperties::Group: { if (fileitem == _dummyFileItem) return QVariant(); return fileitem->getGroup(); } default: return QString(); } return QVariant(); } case Qt::DecorationRole: { switch (index.column()) { case KrViewProperties::Name: { if (properties()->displayIcons) { if (_justForSizeHint) return QPixmap(_view->fileIconSize(), _view->fileIconSize()); return _view->getIcon(fileitem); } break; } default: break; } return QVariant(); } case Qt::TextAlignmentRole: { switch (index.column()) { case KrViewProperties::Size: return QVariant(Qt::AlignRight | Qt::AlignVCenter); default: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); } return QVariant(); } case Qt::BackgroundRole: case Qt::ForegroundRole: { KrColorItemType colorItemType; colorItemType.m_activePanel = _view->isFocused(); int actRow = index.row(); if (_alternatingTable) { int itemNum = _view->itemsPerPage(); if (itemNum == 0) itemNum++; if ((itemNum & 1) == 0) actRow += (actRow / itemNum); } colorItemType.m_alternateBackgroundColor = (actRow & 1); colorItemType.m_currentItem = _view->getCurrentIndex().row() == index.row(); colorItemType.m_selectedItem = _view->isSelected(index); if (fileitem->isSymLink()) { if (fileitem->isBrokenLink()) colorItemType.m_fileType = KrColorItemType::InvalidSymlink; else colorItemType.m_fileType = KrColorItemType::Symlink; } else if (fileitem->isDir()) colorItemType.m_fileType = KrColorItemType::Directory; else if (fileitem->isExecutable()) colorItemType.m_fileType = KrColorItemType::Executable; else colorItemType.m_fileType = KrColorItemType::File; KrColorGroup cols; KrColorCache::getColorCache().getColors(cols, colorItemType); if (colorItemType.m_selectedItem) { if (role == Qt::ForegroundRole) return cols.highlightedText(); else return cols.highlight(); } if (role == Qt::ForegroundRole) return cols.text(); else return cols.background(); } default: return QVariant(); } } bool KrVfsModel::setData(const QModelIndex & index, const QVariant & value, int role) { if (role == Qt::EditRole && index.isValid()) { if (index.row() < rowCount() && index.row() >= 0) { FileItem *fileitem = _fileItems.at(index.row()); if (fileitem == 0) return false; _view->op()->emitRenameItem(fileitem->getName(), value.toString()); } } if (role == Qt::UserRole && index.isValid()) { _justForSizeHint = value.toBool(); } return QAbstractListModel::setData(index, value, role); } void KrVfsModel::sort(int column, Qt::SortOrder order) { _view->sortModeUpdated(column, order); if(lastSortOrder() == KrViewProperties::NoColumn) return; emit layoutAboutToBeChanged(); QModelIndexList oldPersistentList = persistentIndexList(); KrSort::Sorter sorter(createSorter()); sorter.sort(); _fileItems.clear(); _fileItemNdx.clear(); _nameNdx.clear(); _urlNdx.clear(); bool sortOrderChanged = false; QHash changeMap; for (int i = 0; i < sorter.items().count(); ++i) { const KrSort::SortProps *props = sorter.items()[i]; _fileItems.append(props->fileitem()); changeMap[ props->originalIndex() ] = i; if (i != props->originalIndex()) sortOrderChanged = true; updateIndices(props->fileitem(), i); } QModelIndexList newPersistentList; foreach(const QModelIndex &mndx, oldPersistentList) newPersistentList << index(changeMap[ mndx.row()], mndx.column()); changePersistentIndexList(oldPersistentList, newPersistentList); emit layoutChanged(); if (sortOrderChanged) _view->makeItemVisible(_view->getCurrentKrViewItem()); } QModelIndex KrVfsModel::addItem(FileItem *fileitem) { emit layoutAboutToBeChanged(); if(lastSortOrder() == KrViewProperties::NoColumn) { int idx = _fileItems.count(); _fileItems.append(fileitem); updateIndices(fileitem, idx); emit layoutChanged(); return index(idx, 0); } QModelIndexList oldPersistentList = persistentIndexList(); KrSort::Sorter sorter(createSorter()); int insertIndex = sorter.insertIndex(fileitem, fileitem == _dummyFileItem, customSortData(fileitem)); if (insertIndex != _fileItems.count()) _fileItems.insert(insertIndex, fileitem); else _fileItems.append(fileitem); for (int i = insertIndex; i < _fileItems.count(); ++i) { updateIndices(_fileItems[i], i); } QModelIndexList newPersistentList; foreach(const QModelIndex &mndx, oldPersistentList) { int newRow = mndx.row(); if (newRow >= insertIndex) newRow++; newPersistentList << index(newRow, mndx.column()); } changePersistentIndexList(oldPersistentList, newPersistentList); emit layoutChanged(); _view->makeItemVisible(_view->getCurrentKrViewItem()); return index(insertIndex, 0); } QModelIndex KrVfsModel::removeItem(FileItem *fileitem) { QModelIndex currIndex = _view->getCurrentIndex(); int removeIdx = _fileItems.indexOf(fileitem); if(removeIdx < 0) return currIndex; emit layoutAboutToBeChanged(); QModelIndexList oldPersistentList = persistentIndexList(); QModelIndexList newPersistentList; _fileItems.removeAt(removeIdx); if (currIndex.row() == removeIdx) { if (_fileItems.count() == 0) currIndex = QModelIndex(); else if (removeIdx >= _fileItems.count()) currIndex = index(_fileItems.count() - 1, 0); else currIndex = index(removeIdx, 0); } else if (currIndex.row() > removeIdx) { currIndex = index(currIndex.row() - 1, 0); } _fileItemNdx.remove(fileitem); _nameNdx.remove(fileitem->getName()); _urlNdx.remove(fileitem->getUrl()); // update indices for fileItems following fileitem for (int i = removeIdx; i < _fileItems.count(); i++) { updateIndices(_fileItems[i], i); } foreach(const QModelIndex &mndx, oldPersistentList) { int newRow = mndx.row(); if (newRow > removeIdx) newRow--; if (newRow != removeIdx) newPersistentList << index(newRow, mndx.column()); else newPersistentList << QModelIndex(); } changePersistentIndexList(oldPersistentList, newPersistentList); emit layoutChanged(); _view->makeItemVisible(_view->getCurrentKrViewItem()); return currIndex; } void KrVfsModel::updateItem(FileItem *fileitem) { QModelIndex oldModelIndex = fileItemIndex(fileitem); if (!oldModelIndex.isValid()) { addItem(fileitem); return; } if(lastSortOrder() == KrViewProperties::NoColumn) { _view->redrawItem(fileitem); return; } int oldIndex = oldModelIndex.row(); emit layoutAboutToBeChanged(); _fileItems.removeAt(oldIndex); KrSort::Sorter sorter(createSorter()); QModelIndexList oldPersistentList = persistentIndexList(); int newIndex = sorter.insertIndex(fileitem, fileitem == _dummyFileItem, customSortData(fileitem)); if (newIndex != _fileItems.count()) { if (newIndex > oldIndex) newIndex--; _fileItems.insert(newIndex, fileitem); } else _fileItems.append(fileitem); int i = newIndex; if (oldIndex < i) i = oldIndex; for (; i < _fileItems.count(); ++i) { updateIndices(_fileItems[i], i); } QModelIndexList newPersistentList; foreach(const QModelIndex &mndx, oldPersistentList) { int newRow = mndx.row(); if (newRow == oldIndex) newRow = newIndex; else { if (newRow >= oldIndex) newRow--; if (mndx.row() > newIndex) newRow++; } newPersistentList << index(newRow, mndx.column()); } changePersistentIndexList(oldPersistentList, newPersistentList); emit layoutChanged(); if (newIndex != oldIndex) _view->makeItemVisible(_view->getCurrentKrViewItem()); } QVariant KrVfsModel::headerData(int section, Qt::Orientation orientation, int role) const { // ignore anything that's not display, and not horizontal if (role != Qt::DisplayRole || orientation != Qt::Horizontal) return QVariant(); switch (section) { case KrViewProperties::Name: return i18nc("File property", "Name"); case KrViewProperties::Ext: return i18nc("File property", "Ext"); case KrViewProperties::Size: return i18nc("File property", "Size"); case KrViewProperties::Type: return i18nc("File property", "Type"); case KrViewProperties::Modified: return i18nc("File property", "Modified"); case KrViewProperties::Permissions: return i18nc("File property", "Perms"); case KrViewProperties::KrPermissions: return i18nc("File property", "rwx"); case KrViewProperties::Owner: return i18nc("File property", "Owner"); case KrViewProperties::Group: return i18nc("File property", "Group"); } return QString(); } const KrViewProperties *KrVfsModel::properties() const { return _view->properties(); } FileItem *KrVfsModel::fileItemAt(const QModelIndex &index) { if (!index.isValid() || index.row() < 0 || index.row() >= _fileItems.count()) return 0; return _fileItems[ index.row()]; } const QModelIndex & KrVfsModel::fileItemIndex(const FileItem *fileitem) { return _fileItemNdx[ (FileItem *) fileitem ]; } const QModelIndex & KrVfsModel::nameIndex(const QString & st) { return _nameNdx[ st ]; } Qt::ItemFlags KrVfsModel::flags(const QModelIndex & index) const { Qt::ItemFlags flags = QAbstractListModel::flags(index); if (!index.isValid()) return flags; if (index.row() >= rowCount()) return flags; FileItem *fileitem = _fileItems.at(index.row()); if (fileitem == _dummyFileItem) { flags = (flags & (~Qt::ItemIsSelectable)) | Qt::ItemIsDropEnabled; } else flags = flags | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; return flags; } Qt::SortOrder KrVfsModel::lastSortDir() const { return (properties()->sortOptions & KrViewProperties::Descending) ? Qt::DescendingOrder : Qt::AscendingOrder; } int KrVfsModel::lastSortOrder() const { return properties()->sortColumn; } QString KrVfsModel::nameWithoutExtension(const FileItem *fileItem, bool checkEnabled) const { if ((checkEnabled && !_extensionEnabled) || fileItem->isDir()) return fileItem->getName(); // check if the file has an extension const QString& fileItemName = fileItem->getName(); int loc = fileItemName.lastIndexOf('.'); // avoid mishandling of .bashrc and friend // and virtfs / search result names like "/dir/.file" which whould become "/dir/" if (loc > 0 && fileItemName.lastIndexOf('/') < loc) { // check if it has one of the predefined 'atomic extensions' for (QStringList::const_iterator i = properties()->atomicExtensions.begin(); i != properties()->atomicExtensions.end(); ++i) { if (fileItemName.endsWith(*i) && fileItemName != *i) { loc = fileItemName.length() - (*i).length(); break; } } } else return fileItemName; return fileItemName.left(loc); } const QModelIndex &KrVfsModel::indexFromUrl(const QUrl &url) { return _urlNdx[url]; } KrSort::Sorter KrVfsModel::createSorter() { KrSort::Sorter sorter(_fileItems.count(), properties(), lessThanFunc(), greaterThanFunc()); for(int i = 0; i < _fileItems.count(); i++) sorter.addItem(_fileItems[i], _fileItems[i] == _dummyFileItem, i, customSortData(_fileItems[i])); return sorter; } void KrVfsModel::updateIndices(FileItem *file, int i) { _fileItemNdx[file] = index(i, 0); _nameNdx[file->getName()] = index(i, 0); _urlNdx[file->getUrl()] = index(i, 0); } + +QString KrVfsModel::toolTipText(FileItem *fileItem) const +{ + //"

"; // disable automatic word-wrap + QString text = "" + fileItem->getName() + "


"; + if (!fileItem->isDir() || fileItem->getSize() != 0) { + const QString size = KrView::sizeText(properties(), fileItem->getSize()); + text += i18n("Size:") + " " + size + "
"; + } + text += i18nc("File property", "Type:") + " " + KrView::mimeTypeText(fileItem); + text += "
" + i18nc("File property", "Modified:") + " " + dateText(fileItem->getTime_t()); + text += "
" + i18nc("File property", "Permissions:") + " " + + KrView::permissionsText(properties(), fileItem); + text += "
" + i18nc("File property", "Owner:") + " " + fileItem->getOwner(); + text += "
" + i18nc("File property", "Group:") + " " + fileItem->getGroup(); + if (fileItem->isSymLink()) { + text += "
" + i18nc("File property", "Link to:") + " " + fileItem->getSymDest(); + if (fileItem->isBrokenLink()) + text += " - " + i18nc("File property; broken symbolic link", "(broken)"); + } + return text; +} + +QString KrVfsModel::dateText(time_t time) +{ + struct tm* t = localtime((time_t *) & time); + + const QDateTime dateTime(QDate(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday), + QTime(t->tm_hour, t->tm_min)); + return QLocale().toString(dateTime, QLocale::ShortFormat); +} diff --git a/krusader/Panel/krvfsmodel.h b/krusader/Panel/krvfsmodel.h index 17c837a2..b15a17bb 100644 --- a/krusader/Panel/krvfsmodel.h +++ b/krusader/Panel/krvfsmodel.h @@ -1,119 +1,121 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 Rafi Yanai * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This package is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this package; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ #ifndef KRVFSMODEL_H #define KRVFSMODEL_H // QtCore #include // QtGui #include #include "krsort.h" class FileItem; class KrInterView; class KrViewProperties; /** * @brief The list model for all panel views. */ class KrVfsModel: public QAbstractListModel { Q_OBJECT public: explicit KrVfsModel(KrInterView *); virtual ~KrVfsModel(); inline bool ready() const { return _ready; } void populate(const QList &files, FileItem *dummy); QModelIndex addItem(FileItem *); QModelIndex removeItem(FileItem *); void updateItem(FileItem *fileitem); int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole) Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; void setExtensionEnabled(bool exten) { _extensionEnabled = exten; } const KrViewProperties * properties() const; void sort() { sort(lastSortOrder(), lastSortDir()); } void clear(bool emitLayoutChanged = true); QList fileItems() { return _fileItems; } FileItem * fileItemAt(const QModelIndex &index); FileItem *dummyFileItem() const { return _dummyFileItem; } const QModelIndex & fileItemIndex(const FileItem *); const QModelIndex & nameIndex(const QString &); const QModelIndex & indexFromUrl(const QUrl &url); virtual Qt::ItemFlags flags(const QModelIndex & index) const Q_DECL_OVERRIDE; void emitChanged() { emit layoutChanged(); } Qt::SortOrder lastSortDir() const; int lastSortOrder() const; void setAlternatingTable(bool altTable) { _alternatingTable = altTable; } public slots: virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) Q_DECL_OVERRIDE; protected: KrSort::LessThanFunc lessThanFunc() { return KrSort::itemLessThan; } KrSort::LessThanFunc greaterThanFunc() const { return KrSort::itemGreaterThan; } QVariant customSortData(FileItem *) const { return QVariant(); } KrSort::Sorter createSorter(); QString nameWithoutExtension(const FileItem * fileitem, bool checkEnabled = true) const; private: void updateIndices(FileItem *file, int index); + QString toolTipText(FileItem *fileItem) const; + static QString dateText(time_t time); QList _fileItems; QHash _fileItemNdx; QHash _nameNdx; QHash _urlNdx; bool _extensionEnabled; KrInterView * _view; FileItem * _dummyFileItem; bool _ready; QFont _defaultFont; bool _justForSizeHint; bool _alternatingTable; }; #endif // __krvfsmodel__ diff --git a/krusader/Panel/krview.cpp b/krusader/Panel/krview.cpp index 955ea8f6..a87483d4 100644 --- a/krusader/Panel/krview.cpp +++ b/krusader/Panel/krview.cpp @@ -1,1163 +1,1179 @@ /*************************************************************************** krview.cpp ------------------- copyright : (C) 2000-2002 by Shie Erlich & Rafi Yanai e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "krview.h" #include "viewactions.h" #include "krviewfactory.h" #include "krviewitem.h" #include "krselectionmode.h" #include "krcolorcache.h" #include "krpreviews.h" #include "../kicons.h" #include "../krglobal.h" #include "../defaults.h" #include "../FileSystem/dirlisterinterface.h" #include "../FileSystem/fileitem.h" #include "../FileSystem/krpermhandler.h" #include "../Filter/filterdialog.h" // QtCore #include // QtGui #include #include #include #include // QtWidgets #include #include +#include +#include #include #include #include #include #define FILEITEM getFileItem() KrView *KrViewOperator::_changedView = 0; KrViewProperties::PropertyType KrViewOperator::_changedProperties = KrViewProperties::NoProperty; // ----------------------------- operator KrViewOperator::KrViewOperator(KrView *view, QWidget *widget) : _view(view), _widget(widget), _massSelectionUpdate(false) { _saveDefaultSettingsTimer.setSingleShot(true); connect(&_saveDefaultSettingsTimer, SIGNAL(timeout()), SLOT(saveDefaultSettings())); } KrViewOperator::~KrViewOperator() { if(_changedView == _view) saveDefaultSettings(); } void KrViewOperator::startUpdate() { _view->refresh(); } void KrViewOperator::cleared() { _view->clear(); } void KrViewOperator::fileAdded(FileItem *fileitem) { _view->addItem(fileitem); } void KrViewOperator::fileUpdated(FileItem *fileitem) { _view->updateItem(fileitem); } void KrViewOperator::startDrag() { QStringList items; _view->getSelectedItems(&items); if (items.empty()) return ; // don't drag an empty thing QPixmap px; if (items.count() > 1 || _view->getCurrentKrViewItem() == 0) px = FL_LOADICON("queue"); // how much are we dragging else px = _view->getCurrentKrViewItem() ->icon(); emit letsDrag(items, px); } bool KrViewOperator::searchItem(const QString &text, bool caseSensitive, int direction) { KrViewItem * item = _view->getCurrentKrViewItem(); if (!item) { return false; } QRegExp rx(text, caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard); if (!direction) { if (rx.indexIn(item->name()) == 0) { return true; } direction = 1; } KrViewItem * startItem = item; while (true) { item = (direction > 0) ? _view->getNext(item) : _view->getPrev(item); if (!item) item = (direction > 0) ? _view->getFirst() : _view->getLast(); if (item == startItem) { return false; } if (rx.indexIn(item->name()) == 0) { _view->setCurrentKrViewItem(item); _view->makeItemVisible(item); return true; } } } bool KrViewOperator::filterSearch(const QString &text, bool caseSensitive) { _view->_quickFilterMask = QRegExp(text, caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard); _view->refresh(); return _view->_count || !_view->_files->numFileItems(); } void KrViewOperator::setMassSelectionUpdate(bool upd) { _massSelectionUpdate = upd; if (!upd) { emit selectionChanged(); _view->redraw(); } } void KrViewOperator::settingsChanged(KrViewProperties::PropertyType properties) { if(!_view->_updateDefaultSettings || _view->_ignoreSettingsChange) return; if(_changedView != _view) saveDefaultSettings(); _changedView = _view; _changedProperties = static_cast(_changedProperties | properties); _saveDefaultSettingsTimer.start(100); } void KrViewOperator::saveDefaultSettings() { _saveDefaultSettingsTimer.stop(); if(_changedView) _changedView->saveDefaultSettings(_changedProperties); _changedProperties = KrViewProperties::NoProperty; _changedView = 0; } // ----------------------------- krview const KrView::IconSizes KrView::iconSizes; KrView::KrView(KrViewInstance &instance, KConfig *cfg) : _config(cfg), _properties(0), _focused(false), _fileIconSize(0), _instance(instance), _files(0), _mainWindow(0), _widget(0), _nameToMakeCurrent(QString()), _previews(0), _updateDefaultSettings(false), _ignoreSettingsChange(false), _count(0), _numDirs(0), _dummyFileItem(0) { } KrView::~KrView() { _instance.m_objects.removeOne(this); delete _previews; _previews = 0; delete _dummyFileItem; _dummyFileItem = 0; if (_properties) qFatal("A class inheriting KrView didn't delete _properties!"); if (_operator) qFatal("A class inheriting KrView didn't delete _operator!"); } void KrView::init(bool enableUpdateDefaultSettings) { // sanity checks: if (!_widget) qFatal("_widget must be set during construction of KrView inheritors"); // ok, continue initProperties(); _operator = createOperator(); setup(); restoreDefaultSettings(); _updateDefaultSettings = enableUpdateDefaultSettings && KConfigGroup(_config, "Startup").readEntry("Update Default Panel Settings", _RememberPos); _instance.m_objects.append(this); } void KrView::initProperties() { _properties = createViewProperties(); KConfigGroup grpSvr(_config, "Look&Feel"); KConfigGroup grpInstance(_config, _instance.name()); _properties->displayIcons = grpInstance.readEntry("With Icons", _WithIcons); _properties->numericPermissions = grpSvr.readEntry("Numeric permissions", _NumericPermissions); int sortOptions = _properties->sortOptions; if (grpSvr.readEntry("Show Directories First", true)) sortOptions |= KrViewProperties::DirsFirst; if(grpSvr.readEntry("Always sort dirs by name", false)) sortOptions |= KrViewProperties::AlwaysSortDirsByName; if (!grpSvr.readEntry("Case Sensative Sort", _CaseSensativeSort)) sortOptions |= KrViewProperties::IgnoreCase; if (grpSvr.readEntry("Locale Aware Sort", true)) sortOptions |= KrViewProperties::LocaleAwareSort; _properties->sortOptions = static_cast(sortOptions); _properties->sortMethod = static_cast( grpSvr.readEntry("Sort method", (int) _DefaultSortMethod)); _properties->humanReadableSize = grpSvr.readEntry("Human Readable Size", _HumanReadableSize); _properties->localeAwareCompareIsCaseSensitive = QString("a").localeAwareCompare("B") > 0; // see KDE bug #40131 QStringList defaultAtomicExtensions; defaultAtomicExtensions += ".tar.gz"; defaultAtomicExtensions += ".tar.bz2"; defaultAtomicExtensions += ".tar.lzma"; defaultAtomicExtensions += ".tar.xz"; defaultAtomicExtensions += ".moc.cpp"; QStringList atomicExtensions = grpSvr.readEntry("Atomic Extensions", defaultAtomicExtensions); for (QStringList::iterator i = atomicExtensions.begin(); i != atomicExtensions.end();) { QString & ext = *i; ext = ext.trimmed(); if (!ext.length()) { i = atomicExtensions.erase(i); continue; } if (!ext.startsWith('.')) ext.insert(0, '.'); ++i; } _properties->atomicExtensions = atomicExtensions; } void KrView::showPreviews(bool show) { if(show) { if(!_previews) { _previews = new KrPreviews(this); _previews->update(); } } else { delete _previews; _previews = 0; } redraw(); // op()->settingsChanged(KrViewProperties::PropShowPreviews); op()->emitRefreshActions(); } void KrView::updatePreviews() { if(_previews) _previews->update(); } QPixmap KrView::processIcon(const QPixmap &icon, bool dim, const QColor & dimColor, int dimFactor, bool symlink) { QPixmap pixmap = icon; if (symlink) { const QStringList overlays = QStringList() << QString() << "emblem-symbolic-link"; KIconLoader::global()->drawOverlays(overlays, pixmap, KIconLoader::Desktop); } if(!dim) return pixmap; QImage dimmed = pixmap.toImage(); QPainter p(&dimmed); p.setCompositionMode(QPainter::CompositionMode_SourceIn); p.fillRect(0, 0, icon.width(), icon.height(), dimColor); p.setCompositionMode(QPainter::CompositionMode_SourceOver); p.setOpacity((qreal)dimFactor / (qreal)100); p.drawPixmap(0, 0, icon.width(), icon.height(), pixmap); return QPixmap::fromImage(dimmed, Qt::ColorOnly | Qt::ThresholdDither | Qt::ThresholdAlphaDither | Qt::NoOpaqueDetection ); } QPixmap KrView::getIcon(FileItem *fileitem, bool active, int size/*, KRListItem::cmpColor color*/) { // KConfigGroup ag( krConfig, "Advanced"); ////////////////////////////// QPixmap icon; QString icon_name = fileitem->getIcon(); QString cacheName; if(!size) size = _FilelistIconSize.toInt(); QColor dimColor; int dimFactor; bool dim = !active && KrColorCache::getColorCache().getDimSettings(dimColor, dimFactor); if (icon_name.isNull()) icon_name = ""; cacheName.append(QString::number(size)); if(fileitem->isSymLink()) cacheName.append("LINK_"); if(dim) cacheName.append("DIM_"); cacheName.append(icon_name); //QPixmapCache::setCacheLimit( ag.readEntry("Icon Cache Size",_IconCacheSize) ); // first try the cache if (!QPixmapCache::find(cacheName, icon)) { icon = processIcon(krLoader->loadIcon(icon_name, KIconLoader::Desktop, size), dim, dimColor, dimFactor, fileitem->isSymLink()); // insert it into the cache QPixmapCache::insert(cacheName, icon); } return icon; } QPixmap KrView::getIcon(FileItem *fileitem) { if(_previews) { QPixmap icon; if(_previews->getPreview(fileitem, icon, _focused)) return icon; } return getIcon(fileitem, _focused, _fileIconSize); } /** * this function ADDs a list of selected item names into 'names'. * it assumes the list is ready and doesn't initialize it, or clears it */ void KrView::getItemsByMask(QString mask, QStringList* names, bool dirs, bool files) { for (KrViewItem * it = getFirst(); it != 0; it = getNext(it)) { if ((it->name() == "..") || !QDir::match(mask, it->name())) continue; // if we got here, than the item fits the mask if (it->getFileItem()->isDir() && !dirs) continue; // do we need to skip folders? if (!it->getFileItem()->isDir() && !files) continue; // do we need to skip files names->append(it->name()); } } /** * this function ADDs a list of selected item names into 'names'. * it assumes the list is ready and doesn't initialize it, or clears it */ void KrView::getSelectedItems(QStringList *names, bool ignoreJustFocused) { for (KrViewItem * it = getFirst(); it != 0; it = getNext(it)) if (it->isSelected() && (it->name() != "..")) names->append(it->name()); // if all else fails, take the current item if (!ignoreJustFocused) { QString item = getCurrentItem(); if (names->empty() && !item.isEmpty() && item != "..") { names->append(item); } } } void KrView::getSelectedKrViewItems(KrViewItemList *items) { for (KrViewItem * it = getFirst(); it != 0; it = getNext(it)) if (it->isSelected() && (it->name() != "..")) items->append(it); // if all else fails, take the current item QString item = getCurrentItem(); if (items->empty() && !item.isEmpty() && item != ".." && getCurrentKrViewItem() != 0) { items->append(getCurrentKrViewItem()); } } QString KrView::statistics() { KIO::filesize_t size = calcSize(); KIO::filesize_t selectedSize = calcSelectedSize(); QString tmp; KConfigGroup grp(_config, "Look&Feel"); if(grp.readEntry("Show Size In Bytes", false)) { tmp = i18nc("%1=number of selected items,%2=total number of items, \ %3=filesize of selected items,%4=filesize in Bytes, \ %5=filesize of all items in folder,%6=filesize in Bytes", "%1 out of %2, %3 (%4) out of %5 (%6)", numSelected(), _count, KIO::convertSize(selectedSize), KRpermHandler::parseSize(selectedSize), KIO::convertSize(size), KRpermHandler::parseSize(size)); } else { tmp = i18nc("%1=number of selected items,%2=total number of items, \ %3=filesize of selected items,%4=filesize of all items in folder", "%1 out of %2, %3 out of %4", numSelected(), _count, KIO::convertSize(selectedSize), KIO::convertSize(size)); } // notify if we're running a filtered view if (filter() != KrViewProperties::All) tmp = ">> [ " + filterMask().nameFilter() + " ] " + tmp; return tmp; } bool KrView::changeSelection(const KRQuery& filter, bool select) { KConfigGroup grpSvr(_config, "Look&Feel"); return changeSelection(filter, select, grpSvr.readEntry("Mark Dirs", _MarkDirs), true); } bool KrView::changeSelection(const KRQuery& filter, bool select, bool includeDirs, bool makeVisible) { if (op()) op()->setMassSelectionUpdate(true); KrViewItem *temp = getCurrentKrViewItem(); KrViewItem *firstMatch = 0; for (KrViewItem * it = getFirst(); it != 0; it = getNext(it)) { if (it->name() == "..") continue; if (it->getFileItem()->isDir() && !includeDirs) continue; FileItem * file = it->getMutableFileItem(); // filter::match calls getMimetype which isn't const if (file == 0) continue; if (filter.match(file)) { it->setSelected(select); if (!firstMatch) firstMatch = it; } } if (op()) op()->setMassSelectionUpdate(false); updateView(); if (ensureVisibilityAfterSelect() && temp != 0) { makeItemVisible(temp); } else if (makeVisible && firstMatch != 0) { // if no selected item is visible... KrViewItemList selectedItems; getSelectedKrViewItems(&selectedItems); bool anyVisible = false; for (KrViewItem *item : selectedItems) { if (isItemVisible(item)) { anyVisible = true; break; } } if (!anyVisible) { // ...scroll to fist selected item makeItemVisible(firstMatch); } } redraw(); return firstMatch != 0; // return if any file was selected } void KrView::invertSelection() { if (op()) op()->setMassSelectionUpdate(true); KConfigGroup grpSvr(_config, "Look&Feel"); bool markDirs = grpSvr.readEntry("Mark Dirs", _MarkDirs); KrViewItem *temp = getCurrentKrViewItem(); for (KrViewItem * it = getFirst(); it != 0; it = getNext(it)) { if (it->name() == "..") continue; if (it->getFileItem()->isDir() && !markDirs && !it->isSelected()) continue; it->setSelected(!it->isSelected()); } if (op()) op()->setMassSelectionUpdate(false); updateView(); if (ensureVisibilityAfterSelect() && temp != 0) makeItemVisible(temp); } QString KrView::firstUnmarkedBelowCurrent() { if (getCurrentKrViewItem() == 0) return QString(); KrViewItem * iterator = getNext(getCurrentKrViewItem()); while (iterator && iterator->isSelected()) iterator = getNext(iterator); if (!iterator) { iterator = getPrev(getCurrentKrViewItem()); while (iterator && iterator->isSelected()) iterator = getPrev(iterator); } if (!iterator) return QString(); return iterator->name(); } void KrView::delItem(const QString &name) { KrViewItem *it = findItemByName(name); if(!it) return; if(_previews) _previews->deletePreview(it); preDelItem(it); if (it->FILEITEM->isDir()) { --_numDirs; } --_count; delete it; op()->emitSelectionChanged(); } void KrView::addItem(FileItem *fileitem) { if (isFiltered(fileitem)) return; KrViewItem *item = preAddItem(fileitem); if (!item) return; // don't add it after all if(_previews) _previews->updatePreview(item); if (fileitem->isDir()) ++_numDirs; ++_count; if (item->name() == nameToMakeCurrent()) { setCurrentKrViewItem(item); // dictionary based - quick makeItemVisible(item); } op()->emitSelectionChanged(); } void KrView::updateItem(FileItem *fileitem) { if (isFiltered(fileitem)) delItem(fileitem->getName()); else { preUpdateItem(fileitem); if(_previews) _previews->updatePreview(findItemByFileItem(fileitem)); } op()->emitSelectionChanged(); } void KrView::clear() { if(_previews) _previews->clear(); _count = _numDirs = 0; delete _dummyFileItem; _dummyFileItem = 0; redraw(); } bool KrView::handleKeyEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_Enter : case Qt::Key_Return : { if (e->modifiers() & Qt::ControlModifier) // let the panel handle it e->ignore(); else { KrViewItem * i = getCurrentKrViewItem(); if (i == 0) return true; QString tmp = i->name(); op()->emitExecuted(tmp); } return true; } case Qt::Key_QuoteLeft : // Terminal Emulator bugfix if (e->modifiers() == Qt::ControlModifier) { // let the panel handle it e->ignore(); } else { // a normal click - do a lynx-like moving thing op()->emitGoHome(); // ask krusader to move to the home directory } return true; case Qt::Key_Delete : // delete/trash the file op()->emitDefaultDeleteFiles(e->modifiers() == Qt::ShiftModifier || e->modifiers() == Qt::ControlModifier); return true; case Qt::Key_Insert: { KrViewItem * i = getCurrentKrViewItem(); if (!i) return true; i->setSelected(!i->isSelected()); if (KrSelectionMode::getSelectionHandler()->insertMovesDown()) { KrViewItem * next = getNext(i); if (next) { setCurrentKrViewItem(next); makeItemVisible(next); } } op()->emitSelectionChanged(); return true; } case Qt::Key_Space: { KrViewItem * viewItem = getCurrentKrViewItem(); if (viewItem != 0) { viewItem->setSelected(!viewItem->isSelected()); if (KrSelectionMode::getSelectionHandler()->spaceMovesDown()) { KrViewItem * next = getNext(viewItem); if (next) { setCurrentKrViewItem(next); makeItemVisible(next); } } op()->emitSelectionChanged(); } return true; } case Qt::Key_Backspace : // Terminal Emulator bugfix case Qt::Key_Left : if (e->modifiers() == Qt::ControlModifier || e->modifiers() == Qt::ShiftModifier || e->modifiers() == Qt::AltModifier) { // let the panel handle it e->ignore(); } else { // a normal click - do a lynx-like moving thing op()->emitDirUp(); // ask krusader to move up a directory } return true; // safety case Qt::Key_Right : if (e->modifiers() == Qt::ControlModifier || e->modifiers() == Qt::ShiftModifier || e->modifiers() == Qt::AltModifier) { // let the panel handle it e->ignore(); } else { // just a normal click - do a lynx-like moving thing KrViewItem *i = getCurrentKrViewItem(); if (i) op()->emitGoInside(i->name()); } return true; case Qt::Key_Up : if (e->modifiers() == Qt::ControlModifier) { // let the panel handle it - jump to the Location Bar e->ignore(); } else { KrViewItem *item = getCurrentKrViewItem(); if (item) { if (e->modifiers() == Qt::ShiftModifier) { item->setSelected(!item->isSelected()); op()->emitSelectionChanged(); } item = getPrev(item); if (item) { setCurrentKrViewItem(item); makeItemVisible(item); } } } return true; case Qt::Key_Down : if (e->modifiers() == Qt::ControlModifier || e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { // let the panel handle it - jump to command line e->ignore(); } else { KrViewItem *item = getCurrentKrViewItem(); if (item) { if (e->modifiers() == Qt::ShiftModifier) { item->setSelected(!item->isSelected()); op()->emitSelectionChanged(); } item = getNext(item); if (item) { setCurrentKrViewItem(item); makeItemVisible(item); } } } return true; case Qt::Key_Home: { if (e->modifiers() & Qt::ShiftModifier) { /* Shift+Home */ bool select = true; KrViewItem *pos = getCurrentKrViewItem(); if (pos == 0) pos = getLast(); KrViewItem *item = getFirst(); op()->setMassSelectionUpdate(true); while (item) { item->setSelected(select); if (item == pos) select = false; item = getNext(item); } op()->setMassSelectionUpdate(false); } KrViewItem * first = getFirst(); if (first) { setCurrentKrViewItem(first); makeItemVisible(first); } } return true; case Qt::Key_End: if (e->modifiers() & Qt::ShiftModifier) { bool select = false; KrViewItem *pos = getCurrentKrViewItem(); if (pos == 0) pos = getFirst(); op()->setMassSelectionUpdate(true); KrViewItem *item = getFirst(); while (item) { if (item == pos) select = true; item->setSelected(select); item = getNext(item); } op()->setMassSelectionUpdate(false); } else { KrViewItem *last = getLast(); if (last) { setCurrentKrViewItem(last); makeItemVisible(last); } } return true; case Qt::Key_PageDown: { KrViewItem * current = getCurrentKrViewItem(); int downStep = itemsPerPage(); while (downStep != 0 && current) { KrViewItem * newCurrent = getNext(current); if (newCurrent == 0) break; current = newCurrent; downStep--; } if (current) { setCurrentKrViewItem(current); makeItemVisible(current); } return true; } case Qt::Key_PageUp: { KrViewItem * current = getCurrentKrViewItem(); int upStep = itemsPerPage(); while (upStep != 0 && current) { KrViewItem * newCurrent = getPrev(current); if (newCurrent == 0) break; current = newCurrent; upStep--; } if (current) { setCurrentKrViewItem(current); makeItemVisible(current); } return true; } case Qt::Key_Escape: e->ignore(); return true; // otherwise the selection gets lost??!?? // also it is needed by the panel case Qt::Key_A : // mark all if (e->modifiers() == Qt::ControlModifier) { //FIXME: shouldn't there also be a shortcut for unselecting everything ? selectAllIncludingDirs(); return true; } // default continues here !!!!!!!!!!! default: return false; } return false; } void KrView::zoomIn() { int idx = iconSizes.indexOf(_fileIconSize); if(idx >= 0 && (idx+1) < iconSizes.count()) setFileIconSize(iconSizes[idx+1]); } void KrView::zoomOut() { int idx = iconSizes.indexOf(_fileIconSize); if(idx > 0) setFileIconSize(iconSizes[idx-1]); } void KrView::setFileIconSize(int size) { if(iconSizes.indexOf(size) < 0) return; _fileIconSize = size; if(_previews) { _previews->clear(); _previews->update(); } redraw(); op()->emitRefreshActions(); } int KrView::defaultFileIconSize() { KConfigGroup grpSvr(_config, _instance.name()); return grpSvr.readEntry("IconSize", _FilelistIconSize).toInt(); } void KrView::saveDefaultSettings(KrViewProperties::PropertyType properties) { saveSettings(KConfigGroup(_config, _instance.name()), properties); op()->emitRefreshActions(); } void KrView::restoreDefaultSettings() { restoreSettings(KConfigGroup(_config, _instance.name())); } void KrView::saveSettings(KConfigGroup group, KrViewProperties::PropertyType properties) { if(properties & KrViewProperties::PropIconSize) group.writeEntry("IconSize", fileIconSize()); if(properties & KrViewProperties::PropShowPreviews) group.writeEntry("ShowPreviews", previewsShown()); if(properties & KrViewProperties::PropSortMode) saveSortMode(group); if(properties & KrViewProperties::PropFilter) { group.writeEntry("Filter", static_cast(_properties->filter)); group.writeEntry("FilterApplysToDirs", _properties->filterApplysToDirs); if(_properties->filterSettings.isValid()) _properties->filterSettings.save(KConfigGroup(&group, "FilterSettings")); } } void KrView::restoreSettings(KConfigGroup group) { _ignoreSettingsChange = true; doRestoreSettings(group); _ignoreSettingsChange = false; refresh(); } void KrView::doRestoreSettings(KConfigGroup group) { restoreSortMode(group); setFileIconSize(group.readEntry("IconSize", defaultFileIconSize())); showPreviews(group.readEntry("ShowPreviews", false)); _properties->filter = static_cast(group.readEntry("Filter", static_cast(KrViewProperties::All))); _properties->filterApplysToDirs = group.readEntry("FilterApplysToDirs", false); _properties->filterSettings.load(KConfigGroup(&group, "FilterSettings")); _properties->filterMask = _properties->filterSettings.toQuery(); } void KrView::applySettingsToOthers() { for(int i = 0; i < _instance.m_objects.length(); i++) { KrView *view = _instance.m_objects[i]; if(this != view) { view->_ignoreSettingsChange = true; view->copySettingsFrom(this); view->_ignoreSettingsChange = false; } } } void KrView::sortModeUpdated(KrViewProperties::ColumnType sortColumn, bool descending) { if(sortColumn == _properties->sortColumn && descending == (bool) (_properties->sortOptions & KrViewProperties::Descending)) return; int options = _properties->sortOptions; if(descending) options |= KrViewProperties::Descending; else options &= ~KrViewProperties::Descending; _properties->sortColumn = sortColumn; _properties->sortOptions = static_cast(options); // op()->settingsChanged(KrViewProperties::PropSortMode); } void KrView::saveSortMode(KConfigGroup &group) { group.writeEntry("Sort Column", static_cast(_properties->sortColumn)); group.writeEntry("Descending Sort Order", _properties->sortOptions & KrViewProperties::Descending); } void KrView::restoreSortMode(KConfigGroup &group) { int column = group.readEntry("Sort Column", static_cast(KrViewProperties::Name)); bool isDescending = group.readEntry("Descending Sort Order", false); setSortMode(static_cast(column), isDescending); } -QString KrView::krPermissionString(const FileItem * fileitem) +QString KrView::krPermissionText(const FileItem * fileitem) { QString tmp; switch (fileitem->isReadable()) { case ALLOWED_PERM: tmp+='r'; break; case UNKNOWN_PERM: tmp+='?'; break; case NO_PERM: tmp+='-'; break; } switch (fileitem->isWriteable()) { case ALLOWED_PERM: tmp+='w'; break; case UNKNOWN_PERM: tmp+='?'; break; case NO_PERM: tmp+='-'; break; } switch (fileitem->isExecutable()) { case ALLOWED_PERM: tmp+='x'; break; case UNKNOWN_PERM: tmp+='?'; break; case NO_PERM: tmp+='-'; break; } return tmp; } -QString KrView::sizeToString(const KrViewProperties *properties, KIO::filesize_t size) +QString KrView::permissionsText(const KrViewProperties *properties, const FileItem *fileItem) +{ + return properties->numericPermissions ? + QString().asprintf("%.4o", fileItem->getMode() & (S_ISUID | S_ISGID | S_ISVTX | + S_IRWXU | S_IRWXG | S_IRWXO)) : + fileItem->getPerm(); +} + +QString KrView::sizeText(const KrViewProperties *properties, KIO::filesize_t size) { return properties->humanReadableSize ? KIO::convertSize(size) : KRpermHandler::parseSize(size); } +QString KrView::mimeTypeText(FileItem *fileItem) +{ + QMimeType mt = QMimeDatabase().mimeTypeForName(fileItem->getMime()); + return mt.isValid() ? mt.comment() : QString(); +} + bool KrView::isFiltered(FileItem *fileitem) { if (_quickFilterMask.isValid() && _quickFilterMask.indexIn(fileitem->getName()) == -1) return true; bool filteredOut = false; bool isDir = fileitem->isDir(); if (!isDir || (isDir && properties()->filterApplysToDirs)) { switch (properties()->filter) { case KrViewProperties::All : break; case KrViewProperties::Custom : if (!properties()->filterMask.match(fileitem)) filteredOut = true; break; case KrViewProperties::Dirs: if (!isDir) filteredOut = true; break; case KrViewProperties::Files: if (isDir) filteredOut = true; break; default: break; } } return filteredOut; } void KrView::setFiles(DirListerInterface *files) { if(files != _files) { clear(); if(_files) QObject::disconnect(_files, 0, op(), 0); _files = files; } if(!_files) return; QObject::disconnect(_files, 0, op(), 0); QObject::connect(_files, SIGNAL(refreshDone(bool)), op(), SLOT(startUpdate())); QObject::connect(_files, SIGNAL(cleared()), op(), SLOT(cleared())); QObject::connect(_files, SIGNAL(addedFileItem(FileItem*)), op(), SLOT(fileAdded(FileItem*))); QObject::connect(_files, SIGNAL(updatedFileItem(FileItem*)), op(), SLOT(fileUpdated(FileItem*))); } void KrView::setFilter(KrViewProperties::FilterSpec filter, FilterSettings customFilter, bool applyToDirs) { _properties->filter = filter; _properties->filterSettings = customFilter; _properties->filterMask = customFilter.toQuery(); _properties->filterApplysToDirs = applyToDirs; refresh(); } void KrView::setFilter(KrViewProperties::FilterSpec filter) { KConfigGroup cfg(_config, "Look&Feel"); bool rememberSettings = cfg.readEntry("FilterDialogRemembersSettings", _FilterDialogRemembersSettings); bool applyToDirs = rememberSettings ? _properties->filterApplysToDirs : false; switch (filter) { case KrViewProperties::All : break; case KrViewProperties::Custom : { FilterDialog dialog(_widget, i18n("Filter Files"), QStringList(i18n("Apply filter to folders")), false); dialog.checkExtraOption(i18n("Apply filter to folders"), applyToDirs); if(rememberSettings) dialog.applySettings(_properties->filterSettings); dialog.exec(); FilterSettings s(dialog.getSettings()); if(!s.isValid()) // if the user canceled - quit return; _properties->filterSettings = s; _properties->filterMask = s.toQuery(); applyToDirs = dialog.isExtraOptionChecked(i18n("Apply filter to folders")); } break; default: return; } _properties->filterApplysToDirs = applyToDirs; _properties->filter = filter; refresh(); } void KrView::customSelection(bool select) { KConfigGroup grpSvr(_config, "Look&Feel"); bool includeDirs = grpSvr.readEntry("Mark Dirs", _MarkDirs); FilterDialog dialog(0, i18n("Select Files"), QStringList(i18n("Apply selection to folders")), false); dialog.checkExtraOption(i18n("Apply selection to folders"), includeDirs); dialog.exec(); KRQuery query = dialog.getQuery(); // if the user canceled - quit if (query.isNull()) return ; includeDirs = dialog.isExtraOptionChecked(i18n("Apply selection to folders")); changeSelection(query, select, includeDirs); } void KrView::refresh() { QString currentItem = getCurrentItem(); QList selection = selectedUrls(); QModelIndex currentIndex = getCurrentIndex(); clear(); if(!_files) return; QList fileItems; // if we are not at the root add the ".." entry if(!_files->isRoot()) { _dummyFileItem = FileItem::createDummy(); fileItems << _dummyFileItem; } foreach(FileItem *fileitem, _files->fileItems()) { if(!fileitem || isFiltered(fileitem)) continue; if(fileitem->isDir()) _numDirs++; _count++; fileItems << fileitem; } populate(fileItems, _dummyFileItem); if(!selection.isEmpty()) setSelectionUrls(selection); if (!nameToMakeCurrent().isEmpty()) { setCurrentItem(nameToMakeCurrent()); setNameToMakeCurrent(""); } else if (!currentItem.isEmpty()) { if (currentItem == ".." && _count > 0 && !_quickFilterMask.isEmpty() && _quickFilterMask.isValid()) { // In a filtered view we should never select the dummy entry if // there are real matches. setCurrentKrViewItem(getNext(getFirst())); } else setCurrentItem(currentItem, currentIndex); } else { setCurrentKrViewItem(getFirst()); } updatePreviews(); redraw(); op()->emitSelectionChanged(); } void KrView::setSelected(const FileItem* fileitem, bool select) { if(fileitem == _dummyFileItem) return; if(select) clearSavedSelection(); intSetSelected(fileitem, select); } void KrView::saveSelection() { _savedSelection = selectedUrls(); op()->emitRefreshActions(); } void KrView::restoreSelection() { if(canRestoreSelection()) setSelectionUrls(_savedSelection); } void KrView::clearSavedSelection() { _savedSelection.clear(); op()->emitRefreshActions(); } void KrView::markSameBaseName() { KrViewItem* item = getCurrentKrViewItem(); if (!item) return; KRQuery query(QString("%1.*").arg(item->name(false))); changeSelection(query, true, false); } void KrView::markSameExtension() { KrViewItem* item = getCurrentKrViewItem(); if (!item) return; KRQuery query(QString("*.%1").arg(item->extension())); changeSelection(query, true, false); } diff --git a/krusader/Panel/krview.h b/krusader/Panel/krview.h index 5f76dfe5..abae2df7 100644 --- a/krusader/Panel/krview.h +++ b/krusader/Panel/krview.h @@ -1,445 +1,449 @@ /*************************************************************************** krview.h ------------------- copyright : (C) 2000-2002 by Shie Erlich & Rafi Yanai e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD H e a d e r F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KRVIEW_H #define KRVIEW_H // QtCore #include #include #include #include #include #include // QtGui #include #include #include "../Filter/filtersettings.h" #include "../FileSystem/krquery.h" #define MAX_BRIEF_COLS 5 class KrView; class KrViewItem; class KrPreviews; class KrViewInstance; class DirListerInterface; typedef QList KrViewItemList; // KrViewProperties // This class is an interface class between KrView and KrViewItem // In order for KrViewItem to be as independent as possible, KrView holds // an instance of this class, and fills it with the correct data. A reference // to this should be given to each KrViewItem, which then queries it for // information regarding how things should be displayed in the current view. // // Every property that the item needs to know about the view must be here! class KrViewProperties { public: KrViewProperties() : numericPermissions(false), displayIcons(false), sortColumn(Name), sortOptions(static_cast(0)), sortMethod(Alphabetical), filter(KrViewProperties::All), filterMask(KRQuery("*")), filterApplysToDirs(false), localeAwareCompareIsCaseSensitive(false), humanReadableSize(), numberOfColumns(1) { } enum PropertyType { NoProperty = 0x0, PropIconSize = 0x1, PropShowPreviews = 0x2, PropSortMode = 0x4, PropColumns = 0x8, PropFilter = 0x10, AllProperties = PropIconSize | PropShowPreviews | PropSortMode | PropColumns | PropFilter }; enum ColumnType { NoColumn = -1, Name = 0x0, Ext = 0x1, Size = 0x2, Type = 0x3, Modified = 0x4, Permissions = 0x5, KrPermissions = 0x6, Owner = 0x7, Group = 0x8, MAX_COLUMNS = 0x09 }; enum SortOptions { Descending = 0x200, DirsFirst = 0x400, IgnoreCase = 0x800, AlwaysSortDirsByName = 0x1000, LocaleAwareSort = 0x2000 }; enum SortMethod { Alphabetical = 0x1, AlphabeticalNumbers = 0x2, CharacterCode = 0x4, CharacterCodeNumbers = 0x8, Krusader = 0x10 }; enum FilterSpec { Dirs = 0x1, Files = 0x2, All = 0x3, Custom = 0x4 }; bool numericPermissions; // show full permission column as octal numbers bool displayIcons; // true if icons should be displayed in this view ColumnType sortColumn; SortOptions sortOptions; SortMethod sortMethod; // sort method for names and extensions FilterSpec filter; // what items to show (all, custom, exec) KRQuery filterMask; // what items to show (*.cpp, *.h etc) FilterSettings filterSettings; bool filterApplysToDirs; bool localeAwareCompareIsCaseSensitive; // mostly, it is not! depends on LC_COLLATE bool humanReadableSize; // display size as KB, MB or just as a long number QStringList atomicExtensions; // list of strings, which will be treated as one extension. Must // start with a dot. int numberOfColumns; // the number of columns in the brief view }; // operator can handle two ways of doing things: // 1. if the view is a widget (inherits krview and klistview for example) // 2. if the view HAS A widget (a krview-son has a member of klistview) // this is done by specifying the view and the widget in the constructor, // even if they are actually the same object (specify it twice in that case) class KrViewOperator : public QObject { Q_OBJECT public: KrViewOperator(KrView *view, QWidget *widget); ~KrViewOperator(); KrView *view() const { return _view; } QWidget *widget() const { return _widget; } void startDrag(); void emitGotDrop(QDropEvent *e) { emit gotDrop(e); } void emitLetsDrag(QStringList items, QPixmap icon) { emit letsDrag(items, icon); } void emitItemDescription(const QString &desc) { emit itemDescription(desc); } void emitContextMenu(const QPoint &point) { emit contextMenu(point); } void emitEmptyContextMenu(const QPoint &point) { emit emptyContextMenu(point); } void emitRenameItem(const QString &oldName, const QString &newName) { emit renameItem(oldName, newName); } void emitExecuted(const QString &name) { emit executed(name); } void emitGoInside(const QString &name) { emit goInside(name); } void emitNeedFocus() { emit needFocus(); } void emitMiddleButtonClicked(KrViewItem *item) { emit middleButtonClicked(item); } void emitCurrentChanged(KrViewItem *item) { emit currentChanged(item); } void emitPreviewJobStarted(KJob *job) { emit previewJobStarted(job); } void emitGoHome() { emit goHome(); } void emitDirUp() { emit dirUp(); } void emitDefaultDeleteFiles(bool invertMode) { emit defaultDeleteFiles(invertMode); } void emitRefreshActions() { emit refreshActions(); } void emitGoBack() { emit goBack(); } void emitGoForward() { emit goForward(); } bool searchItem(const QString &, bool, int = 0); // search for item and set cursor bool filterSearch(const QString &, bool); // filter view items void setMassSelectionUpdate(bool upd); bool isMassSelectionUpdate() { return _massSelectionUpdate; } void settingsChanged(KrViewProperties::PropertyType properties); public slots: void emitSelectionChanged() { if (!_massSelectionUpdate) emit selectionChanged(); } signals: void selectionChanged(); void gotDrop(QDropEvent *e); void letsDrag(QStringList items, QPixmap icon); void itemDescription(const QString &desc); void contextMenu(const QPoint &point); void emptyContextMenu(const QPoint &point); void renameItem(const QString &oldName, const QString &newName); void executed(const QString &name); void goInside(const QString &name); void needFocus(); void middleButtonClicked(KrViewItem *item); void currentChanged(KrViewItem *item); void previewJobStarted(KJob *job); void goHome(); void defaultDeleteFiles(bool invertMode); void dirUp(); void refreshActions(); void goBack(); void goForward(); protected slots: void saveDefaultSettings(); void startUpdate(); void cleared(); void fileAdded(FileItem *fileitem); void fileUpdated(FileItem *fileitem); protected: // never delete those KrView *_view; QWidget *_widget; private: bool _massSelectionUpdate; QTimer _saveDefaultSettingsTimer; static KrViewProperties::PropertyType _changedProperties; static KrView *_changedView; }; /**************************************************************************** * READ THIS FIRST: Using the view * * You always hold a pointer to KrView, thus you can only use functions declared * in this class. If you need something else, either this class is missing something * or you are ;-) * * The functions you'd usually want: * 1) getSelectedItems - returns all selected items, or (if none) the current item. * it never returns anything which includes the "..", and thus can return an empty list! * 2) getSelectedKrViewItems - the same as (1), but returns a QValueList with KrViewItems * 3) getCurrentItem, setCurrentItem - work with QString * 4) getFirst, getNext, getPrev, getCurrentKrViewItem - all work with KrViewItems, and * used to iterate through a list of items. note that getNext and getPrev accept a pointer * to the current item (used in detailedview for safe iterating), thus your loop should be: * for (KrViewItem *it = view->getFirst(); it!=0; it = view->getNext(it)) { blah; } * 5) nameToMakeCurrent(), setNameToMakeCurrent() - work with QString * * IMPORTANT NOTE: every one who subclasses this must call initProperties() in the constructor !!! */ class KrView { friend class KrViewItem; friend class KrViewOperator; public: class IconSizes : public QVector { public: IconSizes() : QVector() { *this << 12 << 16 << 22 << 32 << 48 << 64 << 128 << 256; } }; // instantiating a new view // 1. new KrView // 2. view->init() // notes: constructor does as little as possible, setup() does the rest. esp, note that // if you need something from operator or properties, move it into setup() void init(bool enableUpdateDefaultSettings = true); KrViewInstance *instance() { return &_instance; } static const IconSizes iconSizes; protected: void initProperties(); KrViewProperties *createViewProperties() { return new KrViewProperties(); } KrViewOperator *createOperator() { return new KrViewOperator(this, _widget); } virtual void setup() = 0; /////////////////////////////////////////////////////// // Every view must implement the following functions // /////////////////////////////////////////////////////// public: // interview related functions virtual QModelIndex getCurrentIndex() = 0; virtual bool isSelected(const QModelIndex &) = 0; virtual bool ensureVisibilityAfterSelect() = 0; virtual void selectRegion(KrViewItem *, KrViewItem *, bool) = 0; virtual uint numSelected() const = 0; virtual QList selectedUrls() = 0; virtual void setSelectionUrls(const QList urls) = 0; virtual KrViewItem *getFirst() = 0; virtual KrViewItem *getLast() = 0; virtual KrViewItem *getNext(KrViewItem *current) = 0; virtual KrViewItem *getPrev(KrViewItem *current) = 0; virtual KrViewItem *getCurrentKrViewItem() = 0; virtual KrViewItem *getKrViewItemAt(const QPoint &vp) = 0; virtual KrViewItem *findItemByName(const QString &name) = 0; virtual KrViewItem *findItemByFileItem(FileItem *vf) = 0; virtual KrViewItem *findItemByUrl(const QUrl &url) = 0; virtual QString getCurrentItem() const = 0; virtual void setCurrentItem(const QString &name, const QModelIndex &fallbackToIndex = QModelIndex()) = 0; virtual void setCurrentKrViewItem(KrViewItem *item) = 0; virtual void makeItemVisible(const KrViewItem *item) = 0; virtual bool isItemVisible(const KrViewItem *item) = 0; virtual void updateView() = 0; virtual void sort() = 0; virtual void refreshColors() = 0; virtual void redraw() = 0; virtual bool handleKeyEvent(QKeyEvent *e); virtual void prepareForActive() = 0; virtual void prepareForPassive() = 0; virtual void renameCurrentItem() = 0; // Rename current item. returns immediately virtual int itemsPerPage() = 0; virtual void showContextMenu(const QPoint &point = QPoint(0, 0)) = 0; protected: virtual KrViewItem *preAddItem(FileItem *fileitem) = 0; virtual void preDelItem(KrViewItem *item) = 0; virtual void preUpdateItem(FileItem *fileitem) = 0; virtual void copySettingsFrom(KrView *other) = 0; virtual void populate(const QList &fileItems, FileItem *dummy) = 0; virtual void intSetSelected(const FileItem *fileitem, bool select) = 0; virtual void clear(); void addItem(FileItem *fileitem); void updateItem(FileItem *fileitem); void delItem(const QString &name); public: ////////////////////////////////////////////////////// // the following functions are already implemented, // // and normally - should NOT be re-implemented. // ////////////////////////////////////////////////////// uint numFiles() const { return _count - _numDirs; } uint numDirs() const { return _numDirs; } uint count() const { return _count; } void getSelectedItems(QStringList *names, bool ignoreJustFocused = false); void getItemsByMask(QString mask, QStringList *names, bool dirs = true, bool files = true); void getSelectedKrViewItems(KrViewItemList *items); void selectAllIncludingDirs() { changeSelection(KRQuery("*"), true, true); } void select(const KRQuery &filter = KRQuery("*")) { changeSelection(filter, true); } void unselect(const KRQuery &filter = KRQuery("*")) { changeSelection(filter, false); } void unselectAll() { changeSelection(KRQuery("*"), false, true); } void invertSelection(); QString nameToMakeCurrent() const { return _nameToMakeCurrent; } void setNameToMakeCurrent(const QString name) { _nameToMakeCurrent = name; } QString firstUnmarkedBelowCurrent(); QString statistics(); const KrViewProperties *properties() const { return _properties; } KrViewOperator *op() const { return _operator; } void showPreviews(bool show); bool previewsShown() { return _previews != 0; } void applySettingsToOthers(); void setFiles(DirListerInterface *files); void refresh(); bool changeSelection(const KRQuery &filter, bool select); bool changeSelection(const KRQuery &filter, bool select, bool includeDirs, bool makeVisible = false); bool isFiltered(FileItem *fileitem); void setSelected(const FileItem *fileitem, bool select); ///////////////////////////////////////////////////////////// // the following functions have a default and minimalistic // // implementation, and may be re-implemented if needed // ///////////////////////////////////////////////////////////// virtual void setSortMode(KrViewProperties::ColumnType sortColumn, bool descending) { sortModeUpdated(sortColumn, descending); } const KRQuery &filterMask() const { return _properties->filterMask; } KrViewProperties::FilterSpec filter() const { return _properties->filter; } void setFilter(KrViewProperties::FilterSpec filter); void setFilter(KrViewProperties::FilterSpec filter, FilterSettings customFilter, bool applyToDirs); void customSelection(bool select); int defaultFileIconSize(); virtual void setFileIconSize(int size); void setDefaultFileIconSize() { setFileIconSize(defaultFileIconSize()); } void zoomIn(); void zoomOut(); // save this view's settings to be restored after restart virtual void saveSettings(KConfigGroup grp, KrViewProperties::PropertyType properties = KrViewProperties::AllProperties); inline QWidget *widget() { return _widget; } inline int fileIconSize() const { return _fileIconSize; } inline bool isFocused() const { return _focused; } QPixmap getIcon(FileItem *fileitem); void setMainWindow(QWidget *mainWindow) { _mainWindow = mainWindow; } // save this view's settings as default for new views of this type void saveDefaultSettings( KrViewProperties::PropertyType properties = KrViewProperties::AllProperties); // restore the default settings for this view type void restoreDefaultSettings(); // call this to restore this view's settings after restart void restoreSettings(KConfigGroup grp); void saveSelection(); void restoreSelection(); bool canRestoreSelection() { return !_savedSelection.isEmpty(); } void clearSavedSelection(); void markSameBaseName(); void markSameExtension(); // todo: what about selection modes ??? virtual ~KrView(); static QPixmap getIcon(FileItem *fileitem, bool active, int size = 0); static QPixmap processIcon(const QPixmap &icon, bool dim, const QColor &dimColor, int dimFactor, bool symlink); - static QString krPermissionString(const FileItem *fileitem); - static QString sizeToString(const KrViewProperties *properties, KIO::filesize_t size); + + // Get GUI strings for file item properties + static QString krPermissionText(const FileItem *fileitem); + static QString permissionsText(const KrViewProperties *properties, const FileItem *fileItem); + static QString sizeText(const KrViewProperties *properties, KIO::filesize_t size); + static QString mimeTypeText(FileItem *fileItem); protected: KrView(KrViewInstance &instance, KConfig *cfg); virtual void doRestoreSettings(KConfigGroup grp); virtual KIO::filesize_t calcSize() = 0; virtual KIO::filesize_t calcSelectedSize() = 0; void sortModeUpdated(KrViewProperties::ColumnType sortColumn, bool descending); inline void setWidget(QWidget *w) { _widget = w; } KConfig *_config; KrViewProperties *_properties; KrViewOperator *_operator; bool _focused; int _fileIconSize; private: void updatePreviews(); void saveSortMode(KConfigGroup &group); void restoreSortMode(KConfigGroup &group); KrViewInstance &_instance; DirListerInterface *_files; QWidget *_mainWindow; QWidget *_widget; QList _savedSelection; QString _nameToMakeCurrent; KrPreviews *_previews; bool _updateDefaultSettings; bool _ignoreSettingsChange; QRegExp _quickFilterMask; uint _count, _numDirs; FileItem *_dummyFileItem; }; #endif /* KRVIEW_H */ diff --git a/krusader/Panel/krviewitem.cpp b/krusader/Panel/krviewitem.cpp index 940b01b1..bd5cc7bd 100644 --- a/krusader/Panel/krviewitem.cpp +++ b/krusader/Panel/krviewitem.cpp @@ -1,148 +1,148 @@ /***************************************************************************** * Copyright (C) 2000-2002 Shie Erlich * * Copyright (C) 2000-2002 Rafi Yanai * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This package is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this package; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ #include "krviewitem.h" #include "krinterview.h" #include "krvfsmodel.h" #include "../FileSystem/fileitem.h" #include "../FileSystem/krpermhandler.h" // QtCore #include #include #include // QtGui #include #include KrViewItem::KrViewItem(FileItem *fileitem, KrInterView *parentView): _fileitem(fileitem), _view(parentView), _viewProperties(parentView->properties()), _hasExtension(false), _hidden(false), _extension("") { dummyFileItem = parentView->_model->dummyFileItem() == fileitem; if (fileitem) { // check if the file has an extension const QString& fileitemName = fileitem->getName(); int loc = fileitemName.lastIndexOf('.'); if (loc > 0) { // avoid mishandling of .bashrc and friend // check if it has one of the predefined 'atomic extensions' for (QStringList::const_iterator i = _viewProperties->atomicExtensions.begin(); i != _viewProperties->atomicExtensions.end(); ++i) { if (fileitemName.endsWith(*i)) { loc = fileitemName.length() - (*i).length(); break; } } _name = fileitemName.left(loc); _extension = fileitemName.mid(loc + 1); _hasExtension = true; } if (fileitemName.startsWith('.')) _hidden = true; } } const QString& KrViewItem::name(bool withExtension) const { if (!withExtension && _hasExtension) return _name; else return _fileitem->getName(); } QString KrViewItem::description() const { if (dummyFileItem) return i18n("Climb up the folder tree"); // else is implied QString mimeTypeComment; QMimeType mt = QMimeDatabase().mimeTypeForName(_fileitem->getMime()); if (mt.isValid()) mimeTypeComment = mt.comment(); - const QString size = KrView::sizeToString(_viewProperties, _fileitem->getSize()); + const QString size = KrView::sizeText(_viewProperties, _fileitem->getSize()); QString text = _fileitem->getName(); if (_fileitem->isSymLink()) { text += " -> " + _fileitem->getSymDest() + " "; if (_fileitem->isBrokenLink()) text += i18n("(Broken Link)"); else if (mimeTypeComment.isEmpty()) text += i18n("Symbolic Link") ; else text += i18n("%1 (Link)", mimeTypeComment); } else { if (_fileitem->isDir()) text += "/"; if (S_ISREG(_fileitem->getMode()) || (_fileitem->isDir() && _fileitem->getSize() != 0)) text += QString(" (%1)").arg(size); text += " " + mimeTypeComment; } return text; } QPixmap KrViewItem::icon() { #if 0 QPixmap *p; // This is bad - very bad. the function must return a valid reference, // This is an interface flow - shie please fix it with a function that return QPixmap* // this way we can return 0 - and do our error checking... // shie answers: why? what's the difference? if we return an empty pixmap, others can use it as it // is, without worrying or needing to do error checking. empty pixmap displays nothing #endif if (dummyFileItem || !_viewProperties->displayIcons) return QPixmap(); else return KrView::getIcon(_fileitem, true); } bool KrViewItem::isSelected() const { return _view->isSelected(_fileitem); } void KrViewItem::setSelected(bool s) { _view->setSelected(_fileitem, s); if(!_view->op()->isMassSelectionUpdate()) { redraw(); _view->op()->emitSelectionChanged(); } } QRect KrViewItem::itemRect() const { return _view->itemRect(_fileitem); } void KrViewItem::redraw() { _view->_itemView->viewport()->update(itemRect()); } void KrViewItem::setSize(KIO::filesize_t size) { _fileitem->setSize(size); }