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.
511 lines
13 KiB
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 <kconfig.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() == Qt::NoButton)
|
|
{
|
|
if(KGlobalSettings::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() == Qt::MidButton && mouseInItemRect(item, e->pos().x()))
|
|
{
|
|
TQListView::contentsMousePressEvent(e);
|
|
citem->setOn(!citem->isOn());
|
|
return;
|
|
}
|
|
|
|
TQListView::contentsMousePressEvent(e);
|
|
|
|
if(item && e->button() == Qt::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() == Qt::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()
|
|
{
|
|
KConfig *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()
|
|
{
|
|
KConfig *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
|