You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digikam/digikam/digikam/folderview.cpp

511 lines
13 KiB

/* ============================================================
*
* This file is a part of digiKam project
* http://www.digikam.org
*
* Date : 2005-05-06
* Description : implementation of folder view.
*
* Copyright (C) 2005-2006 by Joern Ahrens <joern.ahrens@kdemail.net>
* Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot com>
* Copyright (C) 2009 by Andi Clemens <andi dot clemens at gmx dot net>
*
* 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, 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.
*
* ============================================================ */
// TQt includes.
#include <tqpixmap.h>
#include <tqstyle.h>
#include <tqvaluelist.h>
// KDE includes.
#include <kapplication.h>
#include <tdeconfig.h>
#include <kcursor.h>
#include <kglobalsettings.h>
// Local includes.
#include "albummanager.h"
#include "albumsettings.h"
#include "albumthumbnailloader.h"
#include "ddebug.h"
#include "dragobjects.h"
#include "folderitem.h"
#include "themeengine.h"
#include "folderview.h"
#include "folderview.moc"
namespace Digikam
{
class FolderViewPriv
{
public:
FolderViewPriv()
{
active = false;
dragItem = 0;
oldHighlightItem = 0;
}
bool active;
int itemHeight;
TQPixmap itemRegPix;
TQPixmap itemSelPix;
TQPoint dragStartPos;
TQListViewItem *dragItem;
TQListViewItem *oldHighlightItem;
};
//-----------------------------------------------------------------------------
FolderView::FolderView(TQWidget *parent, const char *name)
: TQListView(parent, name)
{
d = new FolderViewPriv;
connect(ThemeEngine::instance(), TQT_SIGNAL(signalThemeChanged()),
this, TQT_SLOT(slotThemeChanged()));
connect(AlbumManager::instance(), TQT_SIGNAL(signalAllAlbumsLoaded()),
this, TQT_SLOT(slotAllAlbumsLoaded()));
connect(AlbumThumbnailLoader::instance(), TQT_SIGNAL(signalReloadThumbnails()),
this, TQT_SLOT(slotIconSizeChanged()));
setColumnAlignment(0, TQt::AlignLeft|TQt::AlignVCenter);
setShowSortIndicator(true);
fontChange(font());
}
FolderView::~FolderView()
{
delete d;
}
void FolderView::setActive(bool val)
{
d->active = val;
if (d->active)
slotSelectionChanged();
}
bool FolderView::active() const
{
return d->active;
}
int FolderView::itemHeight() const
{
return d->itemHeight;
}
TQRect FolderView::itemRect(TQListViewItem *item) const
{
if(!item)
return TQRect();
TQRect r = TQListView::itemRect(item);
r.setLeft(r.left()+(item->depth()+(rootIsDecorated() ? 1 : 0))*treeStepSize());
return r;
}
TQPixmap FolderView::itemBasePixmapRegular() const
{
return d->itemRegPix;
}
TQPixmap FolderView::itemBasePixmapSelected() const
{
return d->itemSelPix;
}
void FolderView::resizeEvent(TQResizeEvent* e)
{
TQListView::resizeEvent(e);
int w = frameRect().width();
int h = itemHeight();
if (d->itemRegPix.width() != w ||
d->itemRegPix.height() != h)
{
slotThemeChanged();
}
}
void FolderView::fontChange(const TQFont& oldFont)
{
// this is bad, since the settings value might not always be the _real_ height of the thumbnail.
// (e.g. when it is blended, as for the tags)
d->itemHeight = TQMAX(AlbumThumbnailLoader::instance()->thumbnailSize() + 2*itemMargin(), fontMetrics().height());
TQListView::fontChange(oldFont);
slotThemeChanged();
}
void FolderView::slotIconSizeChanged()
{
d->itemHeight = TQMAX(AlbumThumbnailLoader::instance()->thumbnailSize() + 2*itemMargin(), fontMetrics().height());
slotThemeChanged();
}
void FolderView::contentsMouseMoveEvent(TQMouseEvent *e)
{
TQListView::contentsMouseMoveEvent(e);
if(e->state() == NoButton)
{
if(TDEGlobalSettings::changeCursorOverIcon())
{
TQPoint vp = contentsToViewport(e->pos());
TQListViewItem *item = itemAt(vp);
if (mouseInItemRect(item, vp.x()))
setCursor(KCursor::handCursor());
else
unsetCursor();
}
return;
}
if(d->dragItem &&
(d->dragStartPos - e->pos()).manhattanLength() > TQApplication::startDragDistance())
{
TQPoint vp = contentsToViewport(e->pos());
TQListViewItem *item = itemAt(vp);
if(!item)
{
d->dragItem = 0;
return;
}
}
}
void FolderView::contentsMousePressEvent(TQMouseEvent *e)
{
TQPoint vp = contentsToViewport(e->pos());
TQListViewItem *item = itemAt(vp);
// With Check Box item, we will toggle on/off item using middle mouse button.
// See B.K.O #130906
FolderCheckListItem *citem = dynamic_cast<FolderCheckListItem*>(item);
if(citem && e->button() == MidButton && mouseInItemRect(item, e->pos().x()))
{
TQListView::contentsMousePressEvent(e);
citem->setOn(!citem->isOn());
return;
}
TQListView::contentsMousePressEvent(e);
if(item && e->button() == LeftButton)
{
// Prepare D&D if necessary
d->dragStartPos = e->pos();
d->dragItem = item;
return;
}
}
void FolderView::contentsMouseReleaseEvent(TQMouseEvent *e)
{
TQPoint vp = contentsToViewport(e->pos());
TQListViewItem *item = itemAt(vp);
TQListView::contentsMouseReleaseEvent(e);
if(item && e->button() == LeftButton)
{
// See B.K.O #126871: collapse/expand treeview using left mouse button single click.
if (mouseInItemRect(item, e->pos().x()))
item->setOpen(!item->isOpen());
}
d->dragItem = 0;
}
void FolderView::startDrag()
{
TQDragObject *o = dragObject();
if(o)
o->drag();
}
TQListViewItem* FolderView::dragItem() const
{
return d->dragItem;
}
void FolderView::contentsDragEnterEvent(TQDragEnterEvent *e)
{
TQListView::contentsDragEnterEvent(e);
e->accept(acceptDrop(e));
}
void FolderView::contentsDragLeaveEvent(TQDragLeaveEvent * e)
{
TQListView::contentsDragLeaveEvent(e);
if(d->oldHighlightItem)
{
FolderItem *fitem = dynamic_cast<FolderItem*>(d->oldHighlightItem);
if (fitem)
fitem->setFocus(false);
else
{
FolderCheckListItem *citem = dynamic_cast<FolderCheckListItem*>(d->oldHighlightItem);
if (citem)
citem->setFocus(false);
}
d->oldHighlightItem->repaint();
d->oldHighlightItem = 0;
}
}
void FolderView::contentsDragMoveEvent(TQDragMoveEvent *e)
{
TQListView::contentsDragMoveEvent(e);
TQPoint vp = contentsToViewport(e->pos());
TQListViewItem *item = itemAt(vp);
if(item)
{
if(d->oldHighlightItem)
{
FolderItem *fitem = dynamic_cast<FolderItem*>(d->oldHighlightItem);
if (fitem)
fitem->setFocus(false);
else
{
FolderCheckListItem *citem = dynamic_cast<FolderCheckListItem*>(d->oldHighlightItem);
if (citem)
citem->setFocus(false);
}
d->oldHighlightItem->repaint();
}
FolderItem *fitem = dynamic_cast<FolderItem*>(item);
if (fitem)
fitem->setFocus(true);
else
{
FolderCheckListItem *citem = dynamic_cast<FolderCheckListItem*>(item);
if (citem)
citem->setFocus(true);
}
d->oldHighlightItem = item;
item->repaint();
}
e->accept(acceptDrop(e));
}
void FolderView::contentsDropEvent(TQDropEvent *e)
{
TQListView::contentsDropEvent(e);
if(d->oldHighlightItem)
{
FolderItem *fitem = dynamic_cast<FolderItem*>(d->oldHighlightItem);
if (fitem)
fitem->setFocus(false);
else
{
FolderCheckListItem *citem = dynamic_cast<FolderCheckListItem*>(d->oldHighlightItem);
if (citem)
citem->setFocus(false);
}
d->oldHighlightItem->repaint();
d->oldHighlightItem = 0;
}
}
bool FolderView::acceptDrop(const TQDropEvent *) const
{
return false;
}
bool FolderView::mouseInItemRect(TQListViewItem* item, int x) const
{
if (!item)
return false;
x += contentsX();
int offset = treeStepSize()*(item->depth() + (rootIsDecorated() ? 1 : 0));
offset += itemMargin();
int width = item->width(fontMetrics(), this, 0);
int boxsize = 0;
FolderCheckListItem* citem = dynamic_cast<FolderCheckListItem*>(item);
if (citem &&
((citem->type() == TQCheckListItem::CheckBox) || (citem->type() == TQCheckListItem::CheckBoxController)))
boxsize = style().pixelMetric(TQStyle::PM_CheckListButtonSize, this);
return (x > (offset + boxsize) && x < (offset + boxsize + width));
}
void FolderView::slotThemeChanged()
{
int w = frameRect().width();
int h = itemHeight();
d->itemRegPix = ThemeEngine::instance()->listRegPixmap(w, h);
d->itemSelPix = ThemeEngine::instance()->listSelPixmap(w, h);
viewport()->update();
}
void FolderView::slotAllAlbumsLoaded()
{
disconnect(AlbumManager::instance(), TQT_SIGNAL(signalAllAlbumsLoaded()),
this, TQT_SLOT(slotAllAlbumsLoaded()));
loadViewState();
}
void FolderView::loadViewState()
{
TDEConfig *config = kapp->config();
config->setGroup(name());
int selectedItem = config->readNumEntry("LastSelectedItem", 0);
TQValueList<int> openFolders;
if(config->hasKey("OpenFolders"))
{
openFolders = config->readIntListEntry("OpenFolders");
}
FolderItem *item = 0;
FolderItem *foundItem = 0;
TQListViewItemIterator it(this->lastItem());
for( ; it.current(); --it)
{
item = dynamic_cast<FolderItem*>(it.current());
if(!item)
continue;
// Start the album root always open
if(openFolders.contains(item->id()) || item->id() == 0)
setOpen(item, true);
else
setOpen(item, false);
if(item->id() == selectedItem)
{
// Save the found selected item so that it can be made visible.
foundItem = item;
}
}
// Important note: this cannot be done inside the previous loop
// because opening folders prevents the visibility.
// Fixes bug #144815.
// (Looks a bit like a bug in TQt to me ...)
if (foundItem)
{
setSelected(foundItem, true);
ensureItemVisible(foundItem);
}
}
void FolderView::saveViewState()
{
TDEConfig *config = kapp->config();
config->setGroup(name());
FolderItem *item = dynamic_cast<FolderItem*>(selectedItem());
if(item)
config->writeEntry("LastSelectedItem", item->id());
else
config->writeEntry("LastSelectedItem", 0);
TQValueList<int> openFolders;
TQListViewItemIterator it(this);
for( ; it.current(); ++it)
{
item = dynamic_cast<FolderItem*>(it.current());
if(item && isOpen(item))
openFolders.push_back(item->id());
}
config->writeEntry("OpenFolders", openFolders);
}
void FolderView::slotSelectionChanged()
{
TQListView::selectionChanged();
}
void FolderView::selectItem(int)
{
}
void FolderView::collapseView(CollapseMode mode)
{
// collapse the whole list first
TQListViewItemIterator iter(this);
while (iter.current())
{
iter.current()->setOpen(false);
iter.current()->setVisible(true);
iter++;
}
// handle special cases
switch (mode)
{
case OmitRoot:
{
firstChild()->setOpen(true);
break;
}
case RestoreCurrentAlbum:
{
TQListViewItemIterator iter(this);
FolderItem* restoredItem = 0;
while (iter.current())
{
FolderItem* curItem = dynamic_cast<FolderItem*>(iter.current());
if (curItem)
{
if (curItem->id() == AlbumManager::instance()->currentAlbum()->id())
{
curItem->setOpen(true);
restoredItem = curItem;
break;
}
}
iter++;
}
if (restoredItem)
ensureItemVisible(restoredItem);
break;
}
default:
break;
}
}
} // namespace Digikam