]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphindetailsview.cpp
commited initial version of Dolphin
[dolphin.git] / src / dolphindetailsview.cpp
1 /***************************************************************************
2 * Copyright (C) 2006 by Peter Penz *
3 * peter.penz@gmx.at *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21 #include "dolphindetailsview.h"
22
23 #include <kurldrag.h>
24 #include <qpainter.h>
25 #include <qobject.h>
26 #include <q3header.h>
27 #include <qclipboard.h>
28 #include <qpainter.h>
29 //Added by qt3to4:
30 #include <Q3ValueList>
31 #include <QPixmap>
32 #include <QDragMoveEvent>
33 #include <QDropEvent>
34 #include <QResizeEvent>
35 #include <QMouseEvent>
36 #include <QEvent>
37 #include <QPaintEvent>
38 #include <klocale.h>
39 #include <kglobalsettings.h>
40 #include <qscrollbar.h>
41 #include <qcursor.h>
42 #include <qstyle.h>
43 #include <assert.h>
44
45 #include "dolphinview.h"
46 #include "viewproperties.h"
47 #include "dolphin.h"
48 #include "kiconeffect.h"
49 #include "dolphinsettings.h"
50 #include "dolphinstatusbar.h"
51 #include "detailsmodesettings.h"
52
53 DolphinDetailsView::DolphinDetailsView(DolphinView* parent) :
54 KFileDetailView(parent, 0),
55 m_dolphinView(parent),
56 m_resizeTimer(0),
57 m_scrollTimer(0),
58 m_rubber(0)
59 {
60 m_resizeTimer = new QTimer(this);
61 connect(m_resizeTimer, SIGNAL(timeout()),
62 this, SLOT(updateColumnsWidth()));
63
64 setAcceptDrops(true);
65 setSelectionMode(KFile::Extended);
66 setHScrollBarMode(Q3ScrollView::AlwaysOff);
67
68 setColumnAlignment(SizeColumn, Qt::AlignRight);
69 for (int i = DateColumn; i <= GroupColumn; ++i) {
70 setColumnAlignment(i, Qt::AlignHCenter);
71 }
72
73 Dolphin& dolphin = Dolphin::mainWin();
74
75 connect(this, SIGNAL(onItem(Q3ListViewItem*)),
76 this, SLOT(slotOnItem(Q3ListViewItem*)));
77 connect(this, SIGNAL(onViewport()),
78 this, SLOT(slotOnViewport()));
79 connect(this, SIGNAL(contextMenuRequested(Q3ListViewItem*, const QPoint&, int)),
80 this, SLOT(slotContextMenuRequested(Q3ListViewItem*, const QPoint&, int)));
81 connect(this, SIGNAL(selectionChanged()),
82 &dolphin, SLOT(slotSelectionChanged()));
83 connect(&dolphin, SIGNAL(activeViewChanged()),
84 this, SLOT(slotActivationUpdate()));
85 connect(this, SIGNAL(itemRenamed(Q3ListViewItem*, const QString&, int)),
86 this, SLOT(slotItemRenamed(Q3ListViewItem*, const QString&, int)));
87 connect(this, SIGNAL(dropped(QDropEvent*, const KURL::List&, const KURL&)),
88 parent, SLOT(slotURLListDropped(QDropEvent*, const KURL::List&, const KURL&)));
89
90 QClipboard* clipboard = QApplication::clipboard();
91 connect(clipboard, SIGNAL(dataChanged()),
92 this, SLOT(slotUpdateDisabledItems()));
93
94 Q3Header* viewHeader = header();
95 viewHeader->setResizeEnabled(false);
96 viewHeader->setMovingEnabled(false);
97 connect(viewHeader, SIGNAL(clicked(int)),
98 this, SLOT(slotHeaderClicked(int)));
99
100 setMouseTracking(true);
101 setDefaultRenameAction(Q3ListView::Accept);
102
103 refreshSettings();
104 }
105
106 DolphinDetailsView::~DolphinDetailsView()
107 {
108 delete m_rubber;
109 m_rubber = 0;
110 }
111
112 void DolphinDetailsView::beginItemUpdates()
113 {
114 }
115
116 void DolphinDetailsView::endItemUpdates()
117 {
118 updateDisabledItems();
119
120 // Restore the current item. Use the information stored in the history if
121 // available. Otherwise use the first item as current item.
122
123 const KFileListViewItem* item = static_cast<const KFileListViewItem*>(firstChild());
124 if (item != 0) {
125 setCurrentItem(item->fileInfo());
126 }
127
128 int index = 0;
129 const Q3ValueList<URLNavigator::HistoryElem> history = m_dolphinView->urlHistory(index);
130 if (!history.isEmpty()) {
131 KFileView* fileView = static_cast<KFileView*>(this);
132 fileView->setCurrentItem(history[index].currentFileName());
133 setContentsPos(history[index].contentsX(), history[index].contentsY());
134 }
135
136 updateColumnsWidth();
137 }
138
139 void DolphinDetailsView::insertItem(KFileItem* fileItem)
140 {
141 KFileView::insertItem(fileItem);
142
143 DolphinListViewItem* item = new DolphinListViewItem(static_cast<Q3ListView*>(this), fileItem);
144
145 QDir::SortSpec spec = KFileView::sorting();
146 if (spec & QDir::Time) {
147 item->setKey(sortingKey(fileItem->time(KIO::UDS_MODIFICATION_TIME),
148 fileItem->isDir(),
149 spec));
150 }
151 else if (spec & QDir::Size) {
152 item->setKey(sortingKey(fileItem->size(), fileItem->isDir(), spec));
153 }
154 else {
155 item->setKey(sortingKey(fileItem->text(), fileItem->isDir(), spec));
156 }
157
158 fileItem->setExtraData(this, item);
159 }
160
161 bool DolphinDetailsView::isOnFilename(const Q3ListViewItem* item, const QPoint& pos) const
162 {
163 const QPoint absPos(mapToGlobal(QPoint(0, 0)));
164 return (pos.x() - absPos.x()) <= filenameWidth(item);
165 }
166
167 void DolphinDetailsView::refreshSettings()
168 {
169 const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
170 assert(settings != 0);
171
172 if (!settings->showGroup()) {
173 removeColumn(GroupColumn);
174 }
175 if (!settings->showOwner()) {
176 removeColumn(OwnerColumn);
177 }
178 if (!settings->showPermissions()) {
179 removeColumn(PermissionsColumn);
180 }
181 if (!settings->showDate()) {
182 removeColumn(DateColumn);
183 }
184
185 QFont adjustedFont(font());
186 adjustedFont.setFamily(settings->fontFamily());
187 adjustedFont.setPointSize(settings->fontSize());
188 setFont(adjustedFont);
189
190 updateView(true);
191 }
192
193 void DolphinDetailsView::zoomIn()
194 {
195 if (isZoomInPossible()) {
196 DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
197 switch (settings->iconSize()) {
198 case KIcon::SizeSmall: settings->setIconSize(KIcon::SizeMedium); break;
199 case KIcon::SizeMedium: settings->setIconSize(KIcon::SizeLarge); break;
200 default: assert(false); break;
201 }
202 ItemEffectsManager::zoomIn();
203 }
204 }
205
206 void DolphinDetailsView::zoomOut()
207 {
208 if (isZoomOutPossible()) {
209 DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
210 switch (settings->iconSize()) {
211 case KIcon::SizeLarge: settings->setIconSize(KIcon::SizeMedium); break;
212 case KIcon::SizeMedium: settings->setIconSize(KIcon::SizeSmall); break;
213 default: assert(false); break;
214 }
215 ItemEffectsManager::zoomOut();
216 }
217 }
218
219 bool DolphinDetailsView::isZoomInPossible() const
220 {
221 DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
222 return settings->iconSize() < KIcon::SizeLarge;
223 }
224
225 bool DolphinDetailsView::isZoomOutPossible() const
226 {
227 DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
228 return settings->iconSize() > KIcon::SizeSmall;
229 }
230
231 void DolphinDetailsView::resizeContents(int width, int height)
232 {
233 KFileDetailView::resizeContents(width, height);
234
235 // When loading several 1000 items a punch of resize events
236 // drops in. As updating the column width is a quite expensive
237 // operation, this operation will be postponed until there is
238 // no resize event for at least 50 milliseconds.
239 m_resizeTimer->stop();
240 m_resizeTimer->start(50, true);
241 }
242
243 void DolphinDetailsView::slotOnItem(Q3ListViewItem* item)
244 {
245 if (isOnFilename(item, QCursor::pos())) {
246 activateItem(item);
247 KFileItem* fileItem = static_cast<KFileListViewItem*>(item)->fileInfo();
248 m_dolphinView->requestItemInfo(fileItem->url());
249 }
250 else {
251 resetActivatedItem();
252 }
253 }
254
255 void DolphinDetailsView::slotOnViewport()
256 {
257 resetActivatedItem();
258 m_dolphinView->requestItemInfo(KURL());
259 }
260
261 void DolphinDetailsView::setContextPixmap(void* context,
262 const QPixmap& pixmap)
263 {
264 reinterpret_cast<KFileListViewItem*>(context)->setPixmap(0, pixmap);
265 }
266
267 const QPixmap* DolphinDetailsView::contextPixmap(void* context)
268 {
269 return reinterpret_cast<KFileListViewItem*>(context)->pixmap(0);
270 }
271
272 void* DolphinDetailsView::firstContext()
273 {
274 return reinterpret_cast<void*>(firstChild());
275 }
276
277 void* DolphinDetailsView::nextContext(void* context)
278 {
279 KFileListViewItem* listViewItem = reinterpret_cast<KFileListViewItem*>(context);
280 return reinterpret_cast<void*>(listViewItem->nextSibling());
281 }
282
283 KFileItem* DolphinDetailsView::contextFileInfo(void* context)
284 {
285 return reinterpret_cast<KFileListViewItem*>(context)->fileInfo();
286 }
287
288
289 void DolphinDetailsView::contentsDragMoveEvent(QDragMoveEvent* event)
290 {
291 KFileDetailView::contentsDragMoveEvent(event);
292
293 // If a dragging is done above a directory, show the icon as 'active' for
294 // a visual feedback
295 KFileListViewItem* item = static_cast<KFileListViewItem*>(itemAt(event->pos()));
296
297 bool showActive = false;
298 if (item != 0) {
299 const KFileItem* fileInfo = item->fileInfo();
300 showActive = (fileInfo != 0) && fileInfo->isDir();
301 }
302
303 if (showActive) {
304 slotOnItem(item);
305 }
306 else {
307 slotOnViewport();
308 }
309 }
310
311 void DolphinDetailsView::resizeEvent(QResizeEvent* event)
312 {
313 KFileDetailView::resizeEvent(event);
314
315 // When loading several 1000 items a punch of resize events
316 // drops in. As updating the column width is a quite expensive
317 // operation, this operation will be postponed until there is
318 // no resize event for at least 50 milliseconds.
319 m_resizeTimer->stop();
320 m_resizeTimer->start(50, true);
321 }
322
323 bool DolphinDetailsView::acceptDrag(QDropEvent* event) const
324 {
325 bool accept = KURLDrag::canDecode(event) &&
326 (event->action() == QDropEvent::Copy ||
327 event->action() == QDropEvent::Move ||
328 event->action() == QDropEvent::Link);
329 if (accept) {
330 if (static_cast<const QWidget*>(event->source()) == this) {
331 KFileListViewItem* item = static_cast<KFileListViewItem*>(itemAt(event->pos()));
332 accept = (item != 0);
333 if (accept) {
334 KFileItem* fileItem = item->fileInfo();
335 accept = fileItem->isDir();
336 }
337 }
338 }
339
340 return accept;
341 }
342
343 void DolphinDetailsView::contentsDropEvent(QDropEvent* event)
344 {
345 // KFileDetailView::contentsDropEvent does not care whether the mouse
346 // cursor is above a filename or not, the destination URL is always
347 // the URL of the item. This is fixed here in a way that the destination
348 // URL is only the URL of the item if the cursor is above the filename.
349 const QPoint pos(QCursor::pos());
350 const QPoint viewportPos(viewport()->mapToGlobal(QPoint(0, 0)));
351 Q3ListViewItem* item = itemAt(QPoint(pos.x() - viewportPos.x(), pos.y() - viewportPos.y()));
352 if ((item == 0) || ((item != 0) && isOnFilename(item, pos))) {
353 // dropping is done on the viewport or directly above a filename
354 KFileDetailView::contentsDropEvent(event);
355 return;
356 }
357
358 // Dropping is done above an item, but the mouse cursor is not above the file name.
359 // In this case the signals of the base implementation will be blocked and send
360 // in a corrected manner afterwards.
361 assert(item != 0);
362 const bool block = signalsBlocked();
363 blockSignals(true);
364 KFileDetailView::contentsDropEvent(event);
365 blockSignals(block);
366
367 if (!acceptDrag(event)) {
368 return;
369 }
370
371 emit dropped(event, 0);
372 KURL::List urls;
373 if (KURLDrag::decode(event, urls) && !urls.isEmpty()) {
374 emit dropped(event, urls, KURL());
375 sig->dropURLs(0, event, urls);
376 }
377 }
378
379 void DolphinDetailsView::contentsMousePressEvent(QMouseEvent* event)
380 {
381 if (m_rubber != 0) {
382 drawRubber();
383 delete m_rubber;
384 m_rubber = 0;
385 }
386
387 // Swallow the base implementation of the mouse press event
388 // if the mouse cursor is not above the filename. This prevents
389 // that the item gets selected and simulates an equal usability
390 // like in the icon view.
391 const QPoint pos(QCursor::pos());
392 const QPoint viewportPos(viewport()->mapToGlobal(QPoint(0, 0)));
393 Q3ListViewItem* item = itemAt(QPoint(pos.x() - viewportPos.x(), pos.y() - viewportPos.y()));
394 if ((item != 0) && isOnFilename(item, pos)) {
395 KFileDetailView::contentsMousePressEvent(event);
396 }
397 else if (event->button() == Qt::LeftButton) {
398 const ButtonState keyboardState = KApplication::keyboardMouseState();
399 const bool isSelectionActive = (keyboardState & ShiftButton) ||
400 (keyboardState & ControlButton);
401 if (!isSelectionActive) {
402 clearSelection();
403 }
404
405 assert(m_rubber == 0);
406 m_rubber = new QRect(event->x(), event->y(), 0, 0);
407 }
408
409 resetActivatedItem();
410 emit signalRequestActivation();
411
412 m_dolphinView->statusBar()->clear();
413 }
414
415 void DolphinDetailsView::contentsMouseMoveEvent(QMouseEvent* event)
416 {
417 if (m_rubber != 0) {
418 slotAutoScroll();
419 return;
420 }
421
422 KFileDetailView::contentsMouseMoveEvent(event);
423
424 const QPoint& pos = event->globalPos();
425 const QPoint viewportPos = viewport()->mapToGlobal(QPoint(0, 0));
426 Q3ListViewItem* item = itemAt(QPoint(pos.x() - viewportPos.x(), pos.y() - viewportPos.y()));
427 if ((item != 0) && isOnFilename(item, pos)) {
428 activateItem(item);
429 }
430 else {
431 resetActivatedItem();
432 }
433 }
434
435 void DolphinDetailsView::contentsMouseReleaseEvent(QMouseEvent* event)
436 {
437 if (m_rubber != 0) {
438 drawRubber();
439 delete m_rubber;
440 m_rubber = 0;
441 }
442
443 if (m_scrollTimer != 0) {
444 disconnect(m_scrollTimer, SIGNAL(timeout()),
445 this, SLOT(slotAutoScroll()));
446 m_scrollTimer->stop();
447 delete m_scrollTimer;
448 m_scrollTimer = 0;
449 }
450
451 KFileDetailView::contentsMouseReleaseEvent(event);
452 }
453
454 void DolphinDetailsView::paintEmptyArea(QPainter* painter, const QRect& rect)
455 {
456 if (m_dolphinView->isActive()) {
457 KFileDetailView::paintEmptyArea(painter, rect);
458 }
459 else {
460 const QBrush brush(colorGroup().background());
461 painter->fillRect(rect, brush);
462 }
463 }
464
465 void DolphinDetailsView::drawRubber()
466 {
467 // Parts of the following code have been taken
468 // from the class KonqBaseListViewWidget located in
469 // konqueror/listview/konq_listviewwidget.h of Konqueror.
470 // (Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
471 // 2001, 2002, 2004 Michael Brade <brade@kde.org>)
472 if (m_rubber == 0) {
473 return;
474 }
475
476 QPainter p;
477 p.begin(viewport());
478 p.setRasterOp(NotROP);
479 p.setPen(QPen(color0, 1));
480 p.setBrush(NoBrush);
481
482 QPoint point(m_rubber->x(), m_rubber->y());
483 point = contentsToViewport(point);
484 style().drawPrimitive(QStyle::PE_FocusRect, &p,
485 QRect(point.x(), point.y(), m_rubber->width(), m_rubber->height()),
486 colorGroup(), QStyle::Style_Default, colorGroup().base());
487 p.end();
488 }
489
490 void DolphinDetailsView::viewportPaintEvent(QPaintEvent* paintEvent)
491 {
492 drawRubber();
493 KFileDetailView::viewportPaintEvent(paintEvent);
494 drawRubber();
495 }
496
497 void DolphinDetailsView::leaveEvent(QEvent* event)
498 {
499 KFileDetailView::leaveEvent(event);
500 slotOnViewport();
501 }
502
503 void DolphinDetailsView::slotActivationUpdate()
504 {
505 update();
506
507 // TODO: there must be a simpler way to say
508 // "update all children"
509 const QObjectList* list = children();
510 if (list == 0) {
511 return;
512 }
513
514 QObjectListIterator it(*list);
515 QObject* object = 0;
516 while ((object = it.current()) != 0) {
517 if (object->inherits("QWidget")) {
518 QWidget* widget = static_cast<QWidget*>(object);
519 widget->update();
520 }
521 ++it;
522 }
523 }
524
525 void DolphinDetailsView::slotContextMenuRequested(Q3ListViewItem* item,
526 const QPoint& pos,
527 int /* col */)
528 {
529 KFileItem* fileInfo = 0;
530 if ((item != 0) && isOnFilename(item, pos)) {
531 fileInfo = static_cast<KFileListViewItem*>(item)->fileInfo();
532 }
533 m_dolphinView->openContextMenu(fileInfo, pos);
534
535 }
536
537 void DolphinDetailsView::slotUpdateDisabledItems()
538 {
539 updateDisabledItems();
540 }
541
542 void DolphinDetailsView::slotAutoScroll()
543 {
544 // Parts of the following code have been taken
545 // from the class KonqBaseListViewWidget located in
546 // konqueror/listview/konq_listviewwidget.h of Konqueror.
547 // (Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
548 // 2001, 2002, 2004 Michael Brade <brade@kde.org>)
549
550 const QPoint pos(viewport()->mapFromGlobal(QCursor::pos()));
551 const QPoint vc(viewportToContents(pos));
552
553 if (vc == m_rubber->bottomRight()) {
554 return;
555 }
556
557 drawRubber();
558
559 m_rubber->setBottomRight(vc);
560
561 Q3ListViewItem* item = itemAt(QPoint(0,0));
562
563 const bool block = signalsBlocked();
564 blockSignals(true);
565
566 const QRect rubber(m_rubber->normalize());
567 const int bottom = contentsY() + visibleHeight() - 1;
568
569 // select all items which intersect with the rubber, deselect all others
570 bool bottomReached = false;
571 while ((item != 0) && !bottomReached) {
572 QRect rect(itemRect(item));
573 rect.setWidth(filenameWidth(item));
574 rect = QRect(viewportToContents(rect.topLeft()),
575 viewportToContents(rect.bottomRight()));
576 if (rect.isValid() && (rect.top() <= bottom)) {
577 const KFileItem* fileItem = static_cast<KFileListViewItem*>(item)->fileInfo();
578 setSelected(fileItem, rect.intersects(rubber));
579 item = item->itemBelow();
580 }
581 else {
582 bottomReached = true;
583 }
584 }
585
586 blockSignals(block);
587 emit selectionChanged();
588
589 drawRubber();
590
591 // scroll the viewport if the top or bottom margin is reached
592 const int scrollMargin = 40;
593 ensureVisible(vc.x(), vc.y(), scrollMargin, scrollMargin);
594 const bool scroll = !QRect(scrollMargin,
595 scrollMargin,
596 viewport()->width() - 2 * scrollMargin,
597 viewport()->height() - 2 * scrollMargin).contains(pos);
598 if (scroll) {
599 if (m_scrollTimer == 0) {
600 m_scrollTimer = new QTimer( this );
601 connect(m_scrollTimer, SIGNAL(timeout()),
602 this, SLOT(slotAutoScroll()));
603 m_scrollTimer->start(100, false);
604 }
605 }
606 else if (m_scrollTimer != 0) {
607 disconnect(m_scrollTimer, SIGNAL(timeout()),
608 this, SLOT(slotAutoScroll()));
609 m_scrollTimer->stop();
610 delete m_scrollTimer;
611 m_scrollTimer = 0;
612 }
613 }
614
615 void DolphinDetailsView::updateColumnsWidth()
616 {
617 const int columnCount = columns();
618 int requiredWidth = 0;
619 for (int i = 1; i < columnCount; ++i) {
620 // When a directory contains no items, a minimum width for
621 // the column must be available, so that the header is readable.
622 // TODO: use header data instead of the hardcoded 64 value...
623 int columnWidth = 64;
624 QFontMetrics fontMetrics(font());
625 for (Q3ListViewItem* item = firstChild(); item != 0; item = item->nextSibling()) {
626 const int width = item->width(fontMetrics, this, i);
627 if (width > columnWidth) {
628 columnWidth = width;
629 }
630 }
631 columnWidth += 16; // add custom margin
632 setColumnWidth(i, columnWidth);
633 requiredWidth += columnWidth;
634 }
635
636 // resize the first column in a way that the
637 // whole available width is used
638 int firstColumnWidth = visibleWidth() - requiredWidth;
639 if (firstColumnWidth < 128) {
640 firstColumnWidth = 128;
641 }
642 setColumnWidth(0, firstColumnWidth);
643 }
644
645 void DolphinDetailsView::slotItemRenamed(Q3ListViewItem* item,
646 const QString& name,
647 int /* column */)
648 {
649 KFileItem* fileInfo = static_cast<KFileListViewItem*>(item)->fileInfo();
650 m_dolphinView->rename(KURL(fileInfo->url()), name);
651 }
652
653 void DolphinDetailsView::slotHeaderClicked(int /* section */)
654 {
655 // The sorting has already been changed in QListView if this slot is
656 // invoked, but Dolphin was not informed about this (no signal is available
657 // which indicates a change of the sorting). This is bypassed by changing
658 // the sorting and sort order to a temporary other value and readjust it again.
659 const int column = sortColumn();
660 if (column <= DateColumn) {
661 DolphinView::Sorting sorting = DolphinView::SortByName;
662 switch (column) {
663 case SizeColumn: sorting = DolphinView::SortBySize; break;
664 case DateColumn: sorting = DolphinView::SortByDate; break;
665 case NameColumn:
666 default: break;
667 }
668
669 const Qt::SortOrder currSortOrder = sortOrder();
670
671 // temporary adjust the sorting and sort order to different values...
672 const DolphinView::Sorting tempSorting = (sorting == DolphinView::SortByName) ?
673 DolphinView::SortBySize :
674 DolphinView::SortByName;
675 m_dolphinView->setSorting(tempSorting);
676 const Qt::SortOrder tempSortOrder = (currSortOrder == Qt::Ascending) ?
677 Qt::Descending : Qt::Ascending;
678 m_dolphinView->setSortOrder(tempSortOrder);
679
680 // ... so that setting them again results in storing the new setting.
681 m_dolphinView->setSorting(sorting);
682 m_dolphinView->setSortOrder(currSortOrder);
683 }
684 }
685
686 DolphinDetailsView::DolphinListViewItem::DolphinListViewItem(Q3ListView* parent,
687 KFileItem* fileItem) :
688 KFileListViewItem(parent, fileItem)
689 {
690 const int iconSize = DolphinSettings::instance().detailsModeSettings()->iconSize();
691 KFileItem* info = fileInfo();
692 setPixmap(DolphinDetailsView::NameColumn, info->pixmap(iconSize));
693
694 // The base class KFileListViewItem represents the column 'Size' only as byte values.
695 // Adjust those values in a way that a mapping to GBytes, MBytes, KBytes and Bytes
696 // is done. As the file size for directories is useless (only the size of the directory i-node
697 // is given), it is removed completely.
698 if (fileItem->isDir()) {
699 setText(SizeColumn, " - ");
700 }
701 else {
702 QString sizeText(KIO::convertSize(fileItem->size()));
703 sizeText.append(" ");
704 setText(SizeColumn, sizeText);
705 }
706
707 // Dolphin allows to remove specific columns, but the base class KFileListViewItem
708 // is not aware about this (or at least the class KFileDetailView does not react on
709 // QListView::remove()). Therefore the columns are rearranged here.
710 const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
711 assert(settings != 0);
712
713 int column_idx = DateColumn; // the columns for 'name' and 'size' cannot get removed
714 for (int i = DolphinDetailsView::DateColumn; i <= DolphinDetailsView::GroupColumn; ++i) {
715 if (column_idx < i) {
716 setText(column_idx, text(i));
717 }
718
719 bool inc = false;
720 switch (i) {
721 case DateColumn: inc = settings->showDate(); break;
722 case PermissionsColumn: inc = settings->showPermissions(); break;
723 case OwnerColumn: inc = settings->showOwner(); break;
724 case GroupColumn: inc = settings->showGroup(); break;
725 default: break;
726 }
727
728 if (inc) {
729 ++column_idx;
730 }
731 }
732 }
733
734 DolphinDetailsView::DolphinListViewItem::~DolphinListViewItem()
735 {
736 }
737
738 void DolphinDetailsView::DolphinListViewItem::paintCell(QPainter* painter,
739 const QColorGroup& colorGroup,
740 int column,
741 int cellWidth,
742 int alignment)
743 {
744 const Q3ListView* view = listView();
745 const bool isActive = view->parent() == Dolphin::mainWin().activeView();
746 if (isSelected()) {
747 // Per default the selection is drawn above the whole width of the item. As a consistent
748 // behavior with the icon view is wanted, only the the column containing the file name
749 // should be shown as selected.
750 QColorGroup defaultColorGroup(colorGroup);
751 const QColor highlightColor(isActive ? backgroundColor(column) : view->colorGroup().background());
752 defaultColorGroup.setColor(QColorGroup::Highlight , highlightColor);
753 defaultColorGroup.setColor(QColorGroup::HighlightedText, colorGroup.color(QColorGroup::Text));
754 KFileListViewItem::paintCell(painter, defaultColorGroup, column, cellWidth, alignment);
755
756 if (column == 0) {
757 // draw the selection only on the first column
758 Q3ListView* parent = listView();
759 const int itemWidth = width(parent->fontMetrics(), parent, 0);
760 if (isActive) {
761 KFileListViewItem::paintCell(painter, colorGroup, column, itemWidth, alignment);
762 }
763 else {
764 Q3ListViewItem::paintCell(painter, colorGroup, column, itemWidth, alignment);
765 }
766 }
767 }
768 else {
769 if (isActive) {
770 KFileListViewItem::paintCell(painter, colorGroup, column, cellWidth, alignment);
771 }
772 else {
773 Q3ListViewItem::paintCell(painter, colorGroup, column, cellWidth, alignment);
774 }
775 }
776
777 if (column < listView()->columns() - 1) {
778 // draw a separator between columns
779 painter->setPen(KGlobalSettings::buttonBackground());
780 painter->drawLine(cellWidth - 1, 0, cellWidth - 1, height() - 1);
781 }
782 }
783
784 void DolphinDetailsView::DolphinListViewItem::paintFocus(QPainter* painter,
785 const QColorGroup& colorGroup,
786 const QRect& rect)
787 {
788 // draw the focus consistently with the selection (see implementation notes
789 // in DolphinListViewItem::paintCell)
790 Q3ListView* parent = listView();
791 int visibleWidth = width(parent->fontMetrics(), parent, 0);
792 const int colWidth = parent->columnWidth(0);
793 if (visibleWidth > colWidth) {
794 visibleWidth = colWidth;
795 }
796
797 QRect focusRect(rect);
798 focusRect.setWidth(visibleWidth);
799
800 KFileListViewItem::paintFocus(painter, colorGroup, focusRect);
801 }
802
803 int DolphinDetailsView::filenameWidth(const Q3ListViewItem* item) const
804 {
805 assert(item != 0);
806
807 int visibleWidth = item->width(fontMetrics(), this, 0);
808 const int colWidth = columnWidth(0);
809 if (visibleWidth > colWidth) {
810 visibleWidth = colWidth;
811 }
812
813 return visibleWidth;
814 }
815 #include "dolphindetailsview.moc"