/*************************************************************************** * Copyright (C) 2006 by Peter Penz * * peter.penz@gmx.at * * * * 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 program 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 program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "dolphiniconsview.h" #include #include #include #include #include #include #include #include #include #include #include #include "dolphinview.h" #include "viewproperties.h" #include "dolphin.h" #include "dolphinstatusbar.h" #include "dolphinsettings.h" #include "dolphiniconsviewsettings.h" DolphinIconsView::DolphinIconsView(DolphinView* parent, LayoutMode layoutMode) : KFileIconView(parent, 0), m_previewIconSize(-1), m_layoutMode(layoutMode), m_dolphinView(parent) { setAcceptDrops(true); setMode(TDEIconView::Execute); setSelectionMode(KFile::Extended); Dolphin& dolphin = Dolphin::mainWin(); connect(this, TQT_SIGNAL(onItem(TQIconViewItem*)), this, TQT_SLOT(slotOnItem(TQIconViewItem*))); connect(this, TQT_SIGNAL(onViewport()), this, TQT_SLOT(slotOnViewport())); connect(this, TQT_SIGNAL(contextMenuRequested(TQIconViewItem*, const TQPoint&)), this, TQT_SLOT(slotContextMenuRequested(TQIconViewItem*, const TQPoint&))); connect(this, TQT_SIGNAL(selectionChanged()), &dolphin, TQT_SLOT(slotSelectionChanged())); connect(&dolphin, TQT_SIGNAL(activeViewChanged()), this, TQT_SLOT(slotActivationUpdate())); connect(this, TQT_SIGNAL(itemRenamed(TQIconViewItem*, const TQString&)), this, TQT_SLOT(slotItemRenamed(TQIconViewItem*, const TQString&))); connect(this, TQT_SIGNAL(dropped(TQDropEvent*, const KURL::List&, const KURL&)), parent, TQT_SLOT(slotURLListDropped(TQDropEvent*, const KURL::List&, const KURL&))); TQClipboard* clipboard = TQApplication::clipboard(); connect(clipboard, TQT_SIGNAL(dataChanged()), this, TQT_SLOT(slotUpdateDisabledItems())); // KFileIconView creates two actions for zooming, which are directly connected to the // slots KFileIconView::zoomIn() and KFileIconView::zoomOut(). As this behavior is not // wanted and the slots are not virtual, the actions are disabled here. TDEAction* zoomInAction = actionCollection()->action("zoomIn"); assert(zoomInAction != 0); zoomInAction->setEnabled(false); TDEAction* zoomOutAction = actionCollection()->action("zoomOut"); assert(zoomOutAction != 0); zoomOutAction->setEnabled(false); setItemsMovable(true); setWordWrapIconText(true); if (m_layoutMode == Previews) { showPreviews(); } refreshSettings(); } DolphinIconsView::~DolphinIconsView() { } void DolphinIconsView::setLayoutMode(LayoutMode mode) { if (m_layoutMode != mode) { m_layoutMode = mode; refreshSettings(); } } void DolphinIconsView::beginItemUpdates() { } void DolphinIconsView::endItemUpdates() { arrangeItemsInGrid(); // TODO: KFileIconView does not emit any signal when the preview // has been finished. Using a delay of 300 ms is a temporary workaround // until the DolphinIconsView will implement the previews by it's own in // future releases. TQTimer::singleShot(300, this, TQT_SLOT(slotUpdateDisabledItems())); const KFileIconViewItem* item = static_cast(firstItem()); if (item != 0) { setCurrentItem(item->fileInfo()); } int index = 0; const TQValueList history = m_dolphinView->urlHistory(index); if (!history.isEmpty()) { KFileView* fileView = static_cast(this); fileView->setCurrentItem(history[index].currentFileName()); setContentsPos(history[index].contentsX(), history[index].contentsY()); } } void DolphinIconsView::refreshSettings() { const DolphinIconsViewSettings* settings = DolphinSettings::instance().iconsView(m_layoutMode); assert(settings != 0); setIconSize(settings->iconSize()); const TQIconView::Arrangement arrangement = settings->arrangement(); const TQIconView::ItemTextPos textPos = (arrangement == TQIconView::LeftToRight) ? TQIconView::Bottom : TQIconView::Right; setArrangement(arrangement); setItemTextPos(textPos); setGridX(settings->gridWidth()); setGridY(settings->gridHeight()); setSpacing(settings->gridSpacing()); TQFont adjustedFont(font()); adjustedFont.setFamily(settings->fontFamily()); adjustedFont.setPointSize(settings->fontSize()); setFont(adjustedFont); setIconTextHeight(settings->textlinesCount()); if (m_layoutMode == Previews) { // There is no getter method for the current size in KFileIconView. To // prevent a flickering the current size is stored in m_previewIconSize and // setPreviewSize is only invoked if the size really has changed. showPreviews(); const int size = settings->previewSize(); if (size != m_previewIconSize) { m_previewIconSize = size; setPreviewSize(size); } } } void DolphinIconsView::zoomIn() { if (isZoomInPossible()) { DolphinIconsViewSettings* settings = DolphinSettings::instance().iconsView(m_layoutMode); const int textWidthHint = settings->textWidthHint(); const int iconSize = increasedIconSize(settings->iconSize()); settings->setIconSize(iconSize); if (m_layoutMode == Previews) { const int previewSize = increasedIconSize(settings->previewSize()); settings->setPreviewSize(previewSize); } settings->calculateGridSize(textWidthHint); ItemEffectsManager::zoomIn(); } } void DolphinIconsView::zoomOut() { if (isZoomOutPossible()) { DolphinIconsViewSettings* settings = DolphinSettings::instance().iconsView(m_layoutMode); const int textWidthHint = settings->textWidthHint(); const int iconSize = decreasedIconSize(settings->iconSize()); settings->setIconSize(iconSize); if (m_layoutMode == Previews) { const int previewSize = decreasedIconSize(settings->previewSize()); settings->setPreviewSize(previewSize); } settings->calculateGridSize(textWidthHint); ItemEffectsManager::zoomOut(); } } bool DolphinIconsView::isZoomInPossible() const { DolphinIconsViewSettings* settings = DolphinSettings::instance().iconsView(m_layoutMode); const int size = (m_layoutMode == Icons) ? settings->iconSize() : settings->previewSize(); return size < TDEIcon::SizeEnormous; } bool DolphinIconsView::isZoomOutPossible() const { DolphinIconsViewSettings* settings = DolphinSettings::instance().iconsView(m_layoutMode); return settings->iconSize() > TDEIcon::SizeSmall; } void DolphinIconsView::arrangeItemsInGrid( bool updated ) { KFileIconView::arrangeItemsInGrid(updated); if (m_layoutMode == Previews) { // The class KFileIconView has a bug when the size of the previews differs from the size // of the icons: For specific MIME types the y-position and the height is calculated in // a wrong manner. The following code bypasses this issue. No bugreport has been submitted // as this functionality is not used by any KDE3 application and the core developers are // busy enough for KDE4 now :-) KFileIconViewItem* item = static_cast(TQIconView::firstItem()); TQString mimetype; while (item != 0) { mimetype = item->fileInfo()->mimetype(); const bool fixSize = mimetype.contains("text") || mimetype.contains("application/x-"); if (fixSize) { item->setPixmapSize(TQSize(m_previewIconSize, m_previewIconSize)); } item = static_cast(item->nextItem()); } } } void DolphinIconsView::setContextPixmap(void* context, const TQPixmap& pixmap) { reinterpret_cast(context)->setPixmap(pixmap); } const TQPixmap* DolphinIconsView::contextPixmap(void* context) { return reinterpret_cast(context)->pixmap(); } void* DolphinIconsView::firstContext() { return reinterpret_cast(firstItem()); } void* DolphinIconsView::nextContext(void* context) { KFileIconViewItem* iconViewItem = reinterpret_cast(context); return reinterpret_cast(iconViewItem->nextItem()); } KFileItem* DolphinIconsView::contextFileInfo(void* context) { return reinterpret_cast(context)->fileInfo(); } void DolphinIconsView::contentsMousePressEvent(TQMouseEvent* event) { KFileIconView::contentsMousePressEvent(event); resetActivatedItem(); emit signalRequestActivation(); m_dolphinView->statusBar()->clear(); } void DolphinIconsView::contentsMouseReleaseEvent(TQMouseEvent* event) { KFileIconView::contentsMouseReleaseEvent(event); // The KFileIconView does not send any selectionChanged signal if // a selection is done by using the "select-during-button-pressed" feature. // Hence inform Dolphin about the selection change manually: Dolphin::mainWin().slotSelectionChanged(); } void DolphinIconsView::drawBackground(TQPainter* painter, const TQRect& rect) { if (m_dolphinView->isActive()) { KFileIconView::drawBackground(painter, rect); } else { const TQBrush brush(colorGroup().background()); painter->fillRect(0, 0, width(), height(), brush); } } TQDragObject* DolphinIconsView::dragObject() { KURL::List urls; KFileItemListIterator it(*KFileView::selectedItems()); while (it.current() != 0) { urls.append((*it)->url()); ++it; } TQPixmap pixmap; if(urls.count() > 1) { pixmap = DesktopIcon("application-vnd.tde.tdemultiple", iconSize()); } else { KFileIconViewItem* item = static_cast(currentItem()); if ((item != 0) && (item->pixmap() != 0)) { pixmap = *(item->pixmap()); } } if (pixmap.isNull()) { pixmap = currentFileItem()->pixmap(iconSize()); } TQDragObject* dragObj = new KURLDrag(urls, widget()); dragObj->setPixmap(pixmap); return dragObj; } void DolphinIconsView::contentsDragEnterEvent(TQDragEnterEvent* event) { // TODO: The method KFileIconView::contentsDragEnterEvent() does // not allow drag and drop inside itself, which prevents the possability // to move a file into a directory. As the method KFileIconView::acceptDrag() // is not virtual, we must overwrite the method // KFileIconView::contentsDragEnterEvent() and do some cut/copy/paste for this // usecase. Corresponding to the documentation the method KFileIconView::acceptDrag() // will get virtual in KDE 4, which will simplify the code. if (event->source() != this) { KFileIconView::contentsDragEnterEvent(event); return; } const bool accept = KURLDrag::canDecode(event) && (event->action() == TQDropEvent::Copy || event->action() == TQDropEvent::Move || event->action() == TQDropEvent::Link ); if (accept) { event->acceptAction(); } else { event->ignore(); } } void DolphinIconsView::contentsDragMoveEvent(TQDragMoveEvent* event) { KFileIconView::contentsDragMoveEvent(event); // If a dragging is done above a directory, show the icon as 'active' for // a visual feedback KFileIconViewItem* item = static_cast(findItem(contentsToViewport(event->pos()))); bool showActive = false; if (item != 0) { const KFileItem* fileInfo = item->fileInfo(); showActive = (fileInfo != 0) && fileInfo->isDir(); } if (showActive) { slotOnItem(item); } else { slotOnViewport(); } } void DolphinIconsView::contentsDropEvent(TQDropEvent* event) { // TODO: Most of the following code is a copy of // KFileIconView::contentsDropEvent. See comment in // DolphinIconsView::contentsDragEnterEvent for details. if (event->source() != this) { KFileIconView::contentsDropEvent(event); return; } KFileIconViewItem* item = static_cast(findItem(contentsToViewport(event->pos()))); const bool accept = KURLDrag::canDecode(event) && (event->action() == TQDropEvent::Copy || event->action() == TQDropEvent::Move || event->action() == TQDropEvent::Link ) && (item != 0); if (!accept) { return; } KFileItem* fileItem = item->fileInfo(); if (!fileItem->isDir()) { // the file is not a directory, hence don't accept any drop return; } emit dropped(event, fileItem); KURL::List urls; if (KURLDrag::decode(event, urls) && !urls.isEmpty()) { emit dropped(event, urls, fileItem != 0 ? fileItem->url() : KURL()); sig->dropURLs(fileItem, event, urls); } } void DolphinIconsView::slotOnItem(TQIconViewItem* item) { assert(item != 0); activateItem(reinterpret_cast(item)); KFileItem* fileItem = static_cast(item)->fileInfo(); m_dolphinView->requestItemInfo(fileItem->url()); } void DolphinIconsView::slotOnViewport() { resetActivatedItem(); m_dolphinView->requestItemInfo(KURL()); } void DolphinIconsView::slotContextMenuRequested(TQIconViewItem* item, const TQPoint& pos) { KFileItem* fileInfo = 0; if (item != 0) { fileInfo = static_cast(item)->fileInfo(); } m_dolphinView->openContextMenu(fileInfo, pos); } void DolphinIconsView::slotItemRenamed(TQIconViewItem* item, const TQString& name) { KFileItem* fileInfo = static_cast(item)->fileInfo(); m_dolphinView->rename(KURL(fileInfo->url()), name); } void DolphinIconsView::slotActivationUpdate() { update(); // TODO: there must be a simpler way to say // "update all children" const TQObjectList list = childrenListObject(); if (list.isEmpty()) { return; } TQObjectListIterator it(list); TQObject* object = 0; while ((object = it.current()) != 0) { if (object->inherits(TQWIDGET_OBJECT_NAME_STRING)) { TQWidget* widget = TQT_TQWIDGET(object); widget->update(); } ++it; } } void DolphinIconsView::slotUpdateDisabledItems() { updateDisabledItems(); } int DolphinIconsView::increasedIconSize(int size) const { int incSize = 0; switch (size) { case TDEIcon::SizeSmall: incSize = TDEIcon::SizeSmallMedium; break; case TDEIcon::SizeSmallMedium: incSize = TDEIcon::SizeMedium; break; case TDEIcon::SizeMedium: incSize = TDEIcon::SizeLarge; break; case TDEIcon::SizeLarge: incSize = TDEIcon::SizeHuge; break; case TDEIcon::SizeHuge: incSize = TDEIcon::SizeEnormous; break; default: assert(false); break; } return incSize; } int DolphinIconsView::decreasedIconSize(int size) const { int decSize = 0; switch (size) { case TDEIcon::SizeSmallMedium: decSize = TDEIcon::SizeSmall; break; case TDEIcon::SizeMedium: decSize = TDEIcon::SizeSmallMedium; break; case TDEIcon::SizeLarge: decSize = TDEIcon::SizeMedium; break; case TDEIcon::SizeHuge: decSize = TDEIcon::SizeLarge; break; case TDEIcon::SizeEnormous: decSize = TDEIcon::SizeHuge; break; default: assert(false); break; } return decSize; } #include "dolphiniconsview.moc"