|
|
/* ============================================================
|
|
|
* Copyright 2004 by Tudor Calin <tudor@1xtech.com>
|
|
|
|
|
|
* 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
|
|
|
#include <tqpainter.h>
|
|
|
#include <tqrect.h>
|
|
|
#include <tqpoint.h>
|
|
|
#include <tqsize.h>
|
|
|
#include <tqevent.h>
|
|
|
#include <tqstring.h>
|
|
|
#include <tqstyle.h>
|
|
|
#include <tqpixmap.h>
|
|
|
#include <tqptrlist.h>
|
|
|
#include <tqcursor.h>
|
|
|
#include <tqtimer.h>
|
|
|
#include <tqdragobject.h>
|
|
|
#include <tqstrlist.h>
|
|
|
#include <tqapplication.h>
|
|
|
// KDE
|
|
|
#include <kiconloader.h>
|
|
|
// Standard
|
|
|
#include <stdlib.h>
|
|
|
#include <iostream>
|
|
|
|
|
|
// To get INT_MAX
|
|
|
extern "C" {
|
|
|
#include <limits.h>
|
|
|
}
|
|
|
// Local
|
|
|
#include "thumbitem.h"
|
|
|
#include "thumbview.h"
|
|
|
|
|
|
|
|
|
#define RECT_EXTENSION 300
|
|
|
|
|
|
namespace KIPIKameraKlientPlugin
|
|
|
{
|
|
|
|
|
|
class ThumbViewPrivate {
|
|
|
|
|
|
public:
|
|
|
ThumbItem *firstItem;
|
|
|
ThumbItem *lastItem;
|
|
|
int spacing;
|
|
|
int count;
|
|
|
bool clearing;
|
|
|
bool pressedMoved;
|
|
|
TQRect *rubber;
|
|
|
TQPoint dragStartPos;
|
|
|
TQPtrList<ThumbItem> selectedItems;
|
|
|
TQTimer* updateTimer;
|
|
|
struct ItemContainer {
|
|
|
ItemContainer(ItemContainer *p, ItemContainer *n, const TQRect &r) : prev(p), next(n), rect(r) {
|
|
|
items.setAutoDelete(false);
|
|
|
if (prev) {
|
|
|
prev->next = this;
|
|
|
}
|
|
|
if (next) {
|
|
|
next->prev = this;
|
|
|
}
|
|
|
}
|
|
|
ItemContainer *prev, *next;
|
|
|
TQRect rect;
|
|
|
TQPtrList<ThumbItem> items;
|
|
|
} *firstContainer, *lastContainer;
|
|
|
ThumbItem *startDragItem;
|
|
|
struct SortableItem {
|
|
|
ThumbItem *item;
|
|
|
};
|
|
|
};
|
|
|
|
|
|
|
|
|
static int cmpItems( const void *n1, const void *n2 ) {
|
|
|
if (!n1 || !n2) {
|
|
|
return 0;
|
|
|
}
|
|
|
ThumbViewPrivate::SortableItem *i1 = (ThumbViewPrivate::SortableItem *)n1;
|
|
|
ThumbViewPrivate::SortableItem *i2 = (ThumbViewPrivate::SortableItem *)n2;
|
|
|
return i1->item->compare( i2->item );
|
|
|
}
|
|
|
|
|
|
|
|
|
ThumbView::ThumbView(TQWidget* tqparent, const char* name, WFlags fl) : TQScrollView(tqparent, name, TQt::WStaticContents | fl) {
|
|
|
setBackgroundMode(TQt::NoBackground);
|
|
|
viewport()->setBackgroundMode(TQt::NoBackground);
|
|
|
viewport()->setFocusProxy(this);
|
|
|
viewport()->setFocusPolicy(TQ_TabFocus);
|
|
|
renamingItem = 0;
|
|
|
d = new ThumbViewPrivate;
|
|
|
d->firstItem = 0;
|
|
|
d->lastItem = 0;
|
|
|
d->spacing = 5;
|
|
|
d->count = 0;
|
|
|
d->clearing = false;
|
|
|
d->pressedMoved = false;
|
|
|
d->rubber = 0;
|
|
|
d->firstContainer = 0;
|
|
|
d->lastContainer = 0;
|
|
|
d->selectedItems.setAutoDelete(false);
|
|
|
d->updateTimer = new TQTimer(this);
|
|
|
d->startDragItem = 0;
|
|
|
connect(d->updateTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotUpdate()));
|
|
|
}
|
|
|
|
|
|
ThumbView::~ThumbView() {
|
|
|
clear(false);
|
|
|
if (d->rubber) {
|
|
|
delete d->rubber;
|
|
|
}
|
|
|
delete d->updateTimer;
|
|
|
delete d;
|
|
|
}
|
|
|
|
|
|
void ThumbView::clear(bool update) {
|
|
|
d->clearing = true;
|
|
|
renamingItem = 0;
|
|
|
deleteContainers();
|
|
|
d->selectedItems.clear();
|
|
|
emit signalSelectionChanged();
|
|
|
ThumbItem *item = d->firstItem;
|
|
|
while (item) {
|
|
|
ThumbItem *tmp = item->next;
|
|
|
delete item;
|
|
|
item = tmp;
|
|
|
}
|
|
|
d->firstItem = 0;
|
|
|
d->lastItem = 0;
|
|
|
viewport()->setUpdatesEnabled(false);
|
|
|
resizeContents(0, 0);
|
|
|
viewport()->setUpdatesEnabled(true);
|
|
|
if (update) {
|
|
|
updateContents();
|
|
|
}
|
|
|
d->clearing = false;
|
|
|
}
|
|
|
|
|
|
int ThumbView::count() {
|
|
|
return d->count;
|
|
|
}
|
|
|
|
|
|
int ThumbView::index(ThumbItem* item) {
|
|
|
if (!item) {
|
|
|
return -1;
|
|
|
}
|
|
|
if (item == d->firstItem) {
|
|
|
return 0;
|
|
|
} else if ( item == d->lastItem ) {
|
|
|
return d->count - 1;
|
|
|
} else {
|
|
|
ThumbItem *i = d->firstItem;
|
|
|
int j = 0;
|
|
|
while ( i && i != item ) {
|
|
|
i = i->next;
|
|
|
++j;
|
|
|
}
|
|
|
return i ? j : -1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
ThumbItem* ThumbView::firstItem() {
|
|
|
return d->firstItem;
|
|
|
}
|
|
|
|
|
|
ThumbItem* ThumbView::lastItem() {
|
|
|
return d->lastItem;
|
|
|
}
|
|
|
|
|
|
void ThumbView::insertItem(ThumbItem *item) {
|
|
|
if (!item) {
|
|
|
return;
|
|
|
}
|
|
|
if (!d->firstItem) {
|
|
|
d->firstItem = item;
|
|
|
d->lastItem = item;
|
|
|
item->prev = 0;
|
|
|
item->next = 0;
|
|
|
} else {
|
|
|
d->lastItem->next = item;
|
|
|
item->prev = d->lastItem;
|
|
|
item->next = 0;
|
|
|
d->lastItem = item;
|
|
|
}
|
|
|
d->count++;
|
|
|
// this way one can insert items in a loop without too many paintevents
|
|
|
d->updateTimer->start(0, true);
|
|
|
}
|
|
|
|
|
|
void ThumbView::takeItem(ThumbItem *item) {
|
|
|
if (!item) {
|
|
|
return;
|
|
|
}
|
|
|
d->count--;
|
|
|
// First remove item from any containers holding it
|
|
|
ThumbViewPrivate::ItemContainer *tmp = d->firstContainer;
|
|
|
while (tmp) {
|
|
|
tmp->items.remove(item);
|
|
|
tmp = tmp->next;
|
|
|
}
|
|
|
// Remove from selected item list
|
|
|
d->selectedItems.remove(item);
|
|
|
if (item == d->firstItem) {
|
|
|
d->firstItem = d->firstItem->next;
|
|
|
if (d->firstItem) {
|
|
|
d->firstItem->prev = 0;
|
|
|
} else {
|
|
|
d->firstItem = d->lastItem = 0;
|
|
|
}
|
|
|
} else if (item == d->lastItem) {
|
|
|
d->lastItem = d->lastItem->prev;
|
|
|
if ( d->lastItem ) {
|
|
|
d->lastItem->next = 0;
|
|
|
} else {
|
|
|
d->firstItem = d->lastItem = 0;
|
|
|
}
|
|
|
} else {
|
|
|
ThumbItem *i = item;
|
|
|
if (i) {
|
|
|
if (i->prev) {
|
|
|
i->prev->next = i->next;
|
|
|
}
|
|
|
if (i->next) {
|
|
|
i->next->prev = i->prev;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if (!d->clearing) {
|
|
|
TQRect r(contentsRectToViewport(item->rect()));
|
|
|
viewport()->tqrepaint(r);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void ThumbView::slotUpdate() {
|
|
|
d->updateTimer->stop();
|
|
|
sort();
|
|
|
rearrangeItems();
|
|
|
}
|
|
|
|
|
|
void ThumbView::sort() {
|
|
|
ThumbViewPrivate::SortableItem *items = new ThumbViewPrivate::SortableItem[ count() ];
|
|
|
ThumbItem *item = d->firstItem;
|
|
|
int i = 0;
|
|
|
for ( ; item; item = item->next) {
|
|
|
items[ i++ ].item = item;
|
|
|
}
|
|
|
qsort( items, count(), sizeof( ThumbViewPrivate::SortableItem ), cmpItems );
|
|
|
ThumbItem *prev = 0;
|
|
|
item = 0;
|
|
|
for (i = 0; i < (int)count(); ++i) {
|
|
|
item = items[ i ].item;
|
|
|
if ( item ) {
|
|
|
item->prev = prev;
|
|
|
if (item->prev) {
|
|
|
item->prev->next = item;
|
|
|
}
|
|
|
item->next = 0;
|
|
|
}
|
|
|
if (i == 0) {
|
|
|
d->firstItem = item;
|
|
|
}
|
|
|
if (i == (int)count() - 1) {
|
|
|
d->lastItem = item;
|
|
|
}
|
|
|
prev = item;
|
|
|
}
|
|
|
delete [] items;
|
|
|
}
|
|
|
|
|
|
void ThumbView::viewportPaintEvent(TQPaintEvent *pe) {
|
|
|
TQRect r(pe->rect());
|
|
|
TQRegion paintRegion(pe->region());
|
|
|
TQPainter painter(viewport());
|
|
|
painter.setClipRegion(paintRegion);
|
|
|
ThumbViewPrivate::ItemContainer *c = d->firstContainer;
|
|
|
for ( ; c; c = c->next) {
|
|
|
TQRect cr(contentsRectToViewport(c->rect));
|
|
|
if (r.intersects(cr)) {
|
|
|
ThumbItem *item = c->items.first();
|
|
|
for ( ; item; item = c->items.next()) {
|
|
|
TQRect ir(contentsRectToViewport(item->rect()));
|
|
|
if (r.intersects(ir)) {
|
|
|
item->paintItem(&painter, tqcolorGroup());
|
|
|
paintRegion -= TQRegion(ir);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
painter.setClipRegion(paintRegion);
|
|
|
painter.fillRect(r, tqcolorGroup().base());
|
|
|
painter.end();
|
|
|
}
|
|
|
|
|
|
void ThumbView::resizeEvent(TQResizeEvent* e) {
|
|
|
TQScrollView::resizeEvent(e);
|
|
|
//d->updateTimer->start(0, true);
|
|
|
rearrangeItems();
|
|
|
}
|
|
|
|
|
|
void ThumbView::rearrangeItems(bool update) {
|
|
|
if (!d->firstItem || !d->lastItem) {
|
|
|
return;
|
|
|
}
|
|
|
int w = 0, h = 0, y = d->spacing;
|
|
|
ThumbItem *item = d->firstItem;
|
|
|
bool changedLayout = false;
|
|
|
while (item) {
|
|
|
bool changed;
|
|
|
ThumbItem *next = makeRow(item, y, changed);
|
|
|
changedLayout = changed || changedLayout;
|
|
|
item = next;
|
|
|
w = TQMAX(w, item->x() + item->width());
|
|
|
h = TQMAX(h, item->y() + item->height());
|
|
|
h = TQMAX(h, y);
|
|
|
if (!item || !item->next) {
|
|
|
break;
|
|
|
}
|
|
|
item = item->next;
|
|
|
}
|
|
|
w = TQMAX(w, d->lastItem->x() + d->lastItem->width());
|
|
|
h = TQMAX(h, d->lastItem->y() + d->lastItem->height());
|
|
|
int vw = visibleWidth();
|
|
|
viewport()->setUpdatesEnabled(false);
|
|
|
resizeContents( w, h );
|
|
|
bool doAgain = visibleWidth() != vw;
|
|
|
if (doAgain) {
|
|
|
rearrangeItems(false);
|
|
|
}
|
|
|
viewport()->setUpdatesEnabled(true);
|
|
|
rebuildContainers();
|
|
|
if (changedLayout && update) {
|
|
|
viewport()->update();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
ThumbItem* ThumbView::makeRow(ThumbItem *begin, int &y, bool &changed) {
|
|
|
ThumbItem *end = 0;
|
|
|
changed = false;
|
|
|
// first calculate the row height
|
|
|
int h = 0;
|
|
|
int x = 0;
|
|
|
ThumbItem *item = begin;
|
|
|
for (;;) {
|
|
|
x += d->spacing + item->width();
|
|
|
//int maxW = visibleWidth();
|
|
|
int maxW = frameRect().width() - 20;
|
|
|
if (x > maxW && item != begin) {
|
|
|
item = item->prev;
|
|
|
break;
|
|
|
}
|
|
|
h = TQMAX(h, item->height());
|
|
|
ThumbItem *old = item;
|
|
|
item = item->next;
|
|
|
if (!item) {
|
|
|
item = old;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
end = item;
|
|
|
// now move the items
|
|
|
item = begin;
|
|
|
for (;;) {
|
|
|
int x;
|
|
|
if (item == begin) {
|
|
|
x = d->spacing;
|
|
|
} else {
|
|
|
x = item->prev->x() + item->prev->width() + d->spacing;
|
|
|
}
|
|
|
changed = item->move(x, y) || changed;
|
|
|
if (item == end) {
|
|
|
break;
|
|
|
}
|
|
|
item = item->next;
|
|
|
}
|
|
|
y += h + d->spacing;
|
|
|
return end;
|
|
|
}
|
|
|
|
|
|
void ThumbView::drawRubber(TQPainter *p) {
|
|
|
if (!p || !d->rubber) {
|
|
|
return;
|
|
|
}
|
|
|
TQRect r(d->rubber->normalize());
|
|
|
r = contentsRectToViewport(r);
|
|
|
TQPoint pnt(r.x(), r.y());
|
|
|
tqstyle().tqdrawPrimitive(TQStyle::PE_FocusRect, p, TQRect( pnt.x(), pnt.y(), r.width(), r.height()), tqcolorGroup(), TQStyle::Style_Default, TQStyleOption(tqcolorGroup().base()));
|
|
|
}
|
|
|
|
|
|
void ThumbView::contentsMousePressEvent(TQMouseEvent *e) {
|
|
|
// If renaming any item, cancel it --------------------------
|
|
|
if (renamingItem) {
|
|
|
renamingItem->cancelRenameItem();
|
|
|
}
|
|
|
// Delete any existing rubber -------------------------------
|
|
|
if ( d->rubber ) {
|
|
|
TQPainter p;
|
|
|
p.begin(viewport());
|
|
|
p.setRasterOp(NotROP);
|
|
|
p.setPen(TQPen(color0, 1));
|
|
|
p.setBrush(NoBrush);
|
|
|
drawRubber(&p);
|
|
|
p.end();
|
|
|
delete d->rubber;
|
|
|
d->rubber = 0;
|
|
|
}
|
|
|
d->dragStartPos = e->pos();
|
|
|
ThumbItem *item = findItem(e->pos());
|
|
|
if (item) {
|
|
|
if (e->state() & TQt::ControlButton) {
|
|
|
item->setSelected(!item->isSelected(), false);
|
|
|
} else if (e->state() & TQt::ShiftButton) {
|
|
|
// different selection mode than the Trolls
|
|
|
ThumbItem *lastSelectedItem = 0;
|
|
|
bool bwdSelection = false;
|
|
|
// first go backwards
|
|
|
for (ThumbItem *it = item->prev; it; it = it->prev) {
|
|
|
if (it->isSelected()) {
|
|
|
lastSelectedItem = it;
|
|
|
bwdSelection = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
bool fwdSelection = false;
|
|
|
if (!lastSelectedItem) {
|
|
|
// Now go forward
|
|
|
for (ThumbItem *it = item->next; it; it = it->next) {
|
|
|
if (it->isSelected()) {
|
|
|
lastSelectedItem = it;
|
|
|
fwdSelection = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
blockSignals(true);
|
|
|
if (bwdSelection) {
|
|
|
for (ThumbItem *it = lastSelectedItem;
|
|
|
it && it != item->next; it = it->next) {
|
|
|
if (!it->isSelected()) {
|
|
|
it->setSelected(true, false);
|
|
|
}
|
|
|
}
|
|
|
} else if (fwdSelection) {
|
|
|
for (ThumbItem *it = item;
|
|
|
it && it != lastSelectedItem->next; it = it->next) {
|
|
|
if (!it->isSelected()) {
|
|
|
it->setSelected(true, false);
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
item->setSelected(!item->isSelected(), false);
|
|
|
}
|
|
|
blockSignals(false);
|
|
|
emit signalSelectionChanged();
|
|
|
} else {
|
|
|
if (!item->isSelected()) {
|
|
|
item->setSelected(true, true);
|
|
|
}
|
|
|
}
|
|
|
d->startDragItem = item;
|
|
|
return;
|
|
|
}
|
|
|
// Press outside any item. unselect all
|
|
|
clearSelection();
|
|
|
// If not item then initiate rubber
|
|
|
if ( d->rubber ) {
|
|
|
delete d->rubber;
|
|
|
d->rubber = 0;
|
|
|
}
|
|
|
d->rubber = new TQRect( e->x(), e->y(), 0, 0 );
|
|
|
TQPainter p;
|
|
|
p.begin( viewport() );
|
|
|
p.setRasterOp( NotROP );
|
|
|
p.setPen( TQPen( color0, 1 ) );
|
|
|
p.setBrush( NoBrush );
|
|
|
drawRubber( &p );
|
|
|
p.end();
|
|
|
d->pressedMoved = false;
|
|
|
}
|
|
|
|
|
|
void ThumbView::contentsMouseMoveEvent(TQMouseEvent *e) {
|
|
|
if (!e) {
|
|
|
return;
|
|
|
}
|
|
|
if (e->state() == Qt::NoButton) {
|
|
|
return;
|
|
|
}
|
|
|
// Dragging ?
|
|
|
if (d->startDragItem) {
|
|
|
if ((d->dragStartPos - e->pos() ).manhattanLength() > TQApplication::startDragDistance()) {
|
|
|
startDrag();
|
|
|
}
|
|
|
return;
|
|
|
}
|
|
|
if (!d->rubber) {
|
|
|
return;
|
|
|
}
|
|
|
TQRect oldRubber = TQRect(*d->rubber);
|
|
|
d->rubber->setRight( e->pos().x() );
|
|
|
d->rubber->setBottom( e->pos().y() );
|
|
|
TQRegion paintRegion;
|
|
|
viewport()->setUpdatesEnabled(false);
|
|
|
TQRect nr(d->rubber->normalize());
|
|
|
TQRect rubberUnion = nr.unite(oldRubber.normalize());
|
|
|
bool changed = false;
|
|
|
ThumbViewPrivate::ItemContainer *c = d->lastContainer;
|
|
|
for (; c; c = c->prev) {
|
|
|
if ( rubberUnion.intersects(c->rect) ) {
|
|
|
ThumbItem *item = c->items.last();
|
|
|
for ( ; item; item = c->items.prev() ) {
|
|
|
if (nr.intersects(item->rect())) {
|
|
|
if (!item->isSelected()) {
|
|
|
item->setSelected(true, false);
|
|
|
changed = true;
|
|
|
paintRegion += TQRect(item->rect());
|
|
|
}
|
|
|
} else {
|
|
|
if (item->isSelected()) {
|
|
|
item->setSelected(false, false);
|
|
|
changed = true;
|
|
|
paintRegion += TQRect(item->rect());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
viewport()->setUpdatesEnabled(true);
|
|
|
TQRect r = *d->rubber;
|
|
|
*d->rubber = oldRubber;
|
|
|
TQPainter p;
|
|
|
p.begin( viewport() );
|
|
|
p.setRasterOp( NotROP );
|
|
|
p.setPen( TQPen( color0, 1 ) );
|
|
|
p.setBrush( NoBrush );
|
|
|
drawRubber( &p );
|
|
|
p.end();
|
|
|
if (changed) {
|
|
|
emit signalSelectionChanged();
|
|
|
paintRegion.translate(-contentsX(), -contentsY());
|
|
|
viewport()->tqrepaint(paintRegion);
|
|
|
}
|
|
|
ensureVisible(e->pos().x(), e->pos().y());
|
|
|
*d->rubber = r;
|
|
|
p.begin(viewport());
|
|
|
p.setRasterOp(NotROP);
|
|
|
p.setPen(TQPen(color0, 1));
|
|
|
p.setBrush(NoBrush);
|
|
|
drawRubber(&p);
|
|
|
p.end();
|
|
|
d->pressedMoved = true;
|
|
|
}
|
|
|
|
|
|
void ThumbView::contentsMouseReleaseEvent(TQMouseEvent *e) {
|
|
|
if (!e) {
|
|
|
return;
|
|
|
}
|
|
|
d->startDragItem = 0;
|
|
|
if (d->rubber) {
|
|
|
TQPainter p;
|
|
|
p.begin( viewport() );
|
|
|
p.setRasterOp( NotROP );
|
|
|
p.setPen( TQPen( color0, 1 ) );
|
|
|
p.setBrush( NoBrush );
|
|
|
drawRubber( &p );
|
|
|
p.end();
|
|
|
delete d->rubber;
|
|
|
d->rubber = 0;
|
|
|
}
|
|
|
if (e->button() == Qt::RightButton) {
|
|
|
ThumbItem *item = findItem(e->pos());
|
|
|
if (item) {
|
|
|
emit signalRightButtonClicked(item, e->globalPos());
|
|
|
} else {
|
|
|
emit signalRightButtonClicked(e->globalPos());
|
|
|
}
|
|
|
} else if ((e->button() == Qt::LeftButton) && !(e->state() & TQt::ShiftButton) && !(e->state() & TQt::ControlButton)) {
|
|
|
if (d->pressedMoved) {
|
|
|
d->pressedMoved = false;
|
|
|
return;
|
|
|
}
|
|
|
ThumbItem *item = findItem(e->pos());
|
|
|
if (item) {
|
|
|
item->setSelected(true, true);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void ThumbView::contentsMouseDoubleClickEvent(TQMouseEvent *e) {
|
|
|
ThumbItem *item = findItem(e->pos());
|
|
|
if (item) {
|
|
|
blockSignals(true);
|
|
|
clearSelection();
|
|
|
if (renamingItem) {
|
|
|
renamingItem->cancelRenameItem();
|
|
|
}
|
|
|
blockSignals(false);
|
|
|
item->setSelected(true);
|
|
|
emit signalDoubleClicked(item);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void ThumbView::rebuildContainers() {
|
|
|
deleteContainers();
|
|
|
ThumbItem *item = d->firstItem;
|
|
|
appendContainer();
|
|
|
ThumbViewPrivate::ItemContainer* c = d->lastContainer;
|
|
|
while (item) {
|
|
|
if (c->rect.contains(item->rect())) {
|
|
|
c->items.append(item);
|
|
|
item = item->next;
|
|
|
} else if (c->rect.intersects(item->rect())) {
|
|
|
c->items.append( item );
|
|
|
c = c->next;
|
|
|
if (!c) {
|
|
|
appendContainer();
|
|
|
c = d->lastContainer;
|
|
|
}
|
|
|
c->items.append(item);
|
|
|
item = item->next;
|
|
|
c = c->prev;
|
|
|
} else {
|
|
|
if (item->y() < c->rect.y() && c->prev) {
|
|
|
c = c->prev;
|
|
|
continue;
|
|
|
}
|
|
|
c = c->next;
|
|
|
if (!c) {
|
|
|
appendContainer();
|
|
|
c = d->lastContainer;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void ThumbView::appendContainer() {
|
|
|
TQSize s;
|
|
|
s = TQSize(INT_MAX - 1, RECT_EXTENSION );
|
|
|
if (!d->firstContainer) {
|
|
|
d->firstContainer = new ThumbViewPrivate::ItemContainer(0, 0, TQRect(TQPoint(0, 0), s));
|
|
|
d->lastContainer = d->firstContainer;
|
|
|
} else {
|
|
|
d->lastContainer = new ThumbViewPrivate::ItemContainer(d->lastContainer, 0, TQRect(d->lastContainer->rect.bottomLeft(), s));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void ThumbView::deleteContainers() {
|
|
|
ThumbViewPrivate::ItemContainer *c = d->firstContainer, *tmpc;
|
|
|
while (c) {
|
|
|
tmpc = c->next;
|
|
|
delete c;
|
|
|
c = tmpc;
|
|
|
}
|
|
|
d->firstContainer = d->lastContainer = 0;
|
|
|
}
|
|
|
|
|
|
void ThumbView::updateItemContainer(ThumbItem *item) {
|
|
|
if (!item) return;
|
|
|
// First remove item from any containers holding it
|
|
|
ThumbViewPrivate::ItemContainer *tmp = d->firstContainer;
|
|
|
while (tmp) {
|
|
|
tmp->items.remove(item);
|
|
|
tmp = tmp->next;
|
|
|
}
|
|
|
ThumbViewPrivate::ItemContainer *c = d->firstContainer;
|
|
|
if (!c) {
|
|
|
appendContainer();
|
|
|
c = d->firstContainer;
|
|
|
}
|
|
|
const TQRect ir = item->rect();
|
|
|
bool contains = false;
|
|
|
for (;;) {
|
|
|
if (c->rect.intersects(ir)) {
|
|
|
contains = c->rect.contains(ir);
|
|
|
break;
|
|
|
}
|
|
|
c = c->next;
|
|
|
if (!c) {
|
|
|
appendContainer();
|
|
|
c = d->lastContainer;
|
|
|
}
|
|
|
}
|
|
|
if ( !c ) {
|
|
|
return;
|
|
|
}
|
|
|
c->items.append(item);
|
|
|
if (!contains) {
|
|
|
c = c->next;
|
|
|
if (!c) {
|
|
|
appendContainer();
|
|
|
c = d->lastContainer;
|
|
|
}
|
|
|
c->items.append( item );
|
|
|
}
|
|
|
if (contentsWidth() < ir.right() || contentsHeight() < ir.bottom()) {
|
|
|
resizeContents(TQMAX(contentsWidth(), ir.right()), TQMAX(contentsHeight(), ir.bottom()));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
ThumbItem* ThumbView::findItem(const TQPoint& pos) {
|
|
|
if (!d->firstItem) {
|
|
|
return 0;
|
|
|
}
|
|
|
ThumbViewPrivate::ItemContainer *c = d->lastContainer;
|
|
|
for (; c; c = c->prev) {
|
|
|
if ( c->rect.contains(pos) ) {
|
|
|
ThumbItem *item = c->items.last();
|
|
|
for ( ; item; item = c->items.prev()) {
|
|
|
if (item->rect().contains( pos )) {
|
|
|
return item;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
ThumbItem* ThumbView::findItem(const TQString& text) {
|
|
|
if (!d->firstItem) {
|
|
|
return 0;
|
|
|
}
|
|
|
bool found = false;
|
|
|
ThumbItem *item = 0;
|
|
|
for (item = d->firstItem; item; item = item->next) {
|
|
|
if (item->text() == text) {
|
|
|
found = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
if (found) {
|
|
|
return item;
|
|
|
} else {
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
TQRect ThumbView::contentsRectToViewport(const TQRect& r) {
|
|
|
TQRect vr = TQRect(contentsToViewport(TQPoint(r.x(), r.y())), r.size());
|
|
|
return vr;
|
|
|
}
|
|
|
|
|
|
void ThumbView::clearSelection() {
|
|
|
blockSignals(true);
|
|
|
for (ThumbItem* item = d->firstItem; item; item = item->next) {
|
|
|
if (item->isSelected()) {
|
|
|
item->setSelected(false, false);
|
|
|
d->selectedItems.remove(item);
|
|
|
}
|
|
|
}
|
|
|
blockSignals(false);
|
|
|
emit signalSelectionChanged();
|
|
|
}
|
|
|
|
|
|
void ThumbView::selectAll() {
|
|
|
blockSignals(true);
|
|
|
for (ThumbItem* item = d->firstItem; item; item = item->next) {
|
|
|
if (!item->isSelected()) {
|
|
|
item->setSelected(true, false);
|
|
|
d->selectedItems.append(item);
|
|
|
}
|
|
|
}
|
|
|
blockSignals(false);
|
|
|
emit signalSelectionChanged();
|
|
|
}
|
|
|
|
|
|
void ThumbView::invertSelection() {
|
|
|
blockSignals(true);
|
|
|
for (ThumbItem* item = d->firstItem; item; item = item->next) {
|
|
|
if (!item->isSelected()) {
|
|
|
item->setSelected(true, false);
|
|
|
d->selectedItems.append(item);
|
|
|
} else {
|
|
|
item->setSelected(false, false);
|
|
|
d->selectedItems.remove(item);
|
|
|
}
|
|
|
}
|
|
|
blockSignals(false);
|
|
|
emit signalSelectionChanged();
|
|
|
}
|
|
|
|
|
|
void ThumbView::selectItem(ThumbItem* item, bool select) {
|
|
|
if (!item) {
|
|
|
return;
|
|
|
}
|
|
|
if (select) {
|
|
|
d->selectedItems.append(item);
|
|
|
} else {
|
|
|
d->selectedItems.remove(item);
|
|
|
}
|
|
|
emit signalSelectionChanged();
|
|
|
}
|
|
|
|
|
|
void ThumbView::emitRenamed(ThumbItem *item) {
|
|
|
if (!item) {
|
|
|
return;
|
|
|
}
|
|
|
emit signalItemRenamed(item);
|
|
|
}
|
|
|
|
|
|
void ThumbView::startDrag() {
|
|
|
if (!d->startDragItem) {
|
|
|
return;
|
|
|
}
|
|
|
TQStrList uris;
|
|
|
for (ThumbItem *it = firstItem(); it; it=it->nextItem()) {
|
|
|
if (it->isSelected()) {
|
|
|
// PENDING(Aur<75>lien) Check if .ascii() is ok here
|
|
|
uris.append(it->text().ascii());
|
|
|
}
|
|
|
}
|
|
|
TQUriDrag* drag = new TQUriDrag(uris, this);
|
|
|
if (!drag) {
|
|
|
return;
|
|
|
}
|
|
|
drag->setPixmap(*d->startDragItem->pixmap());
|
|
|
d->startDragItem = 0;
|
|
|
drag->dragCopy();
|
|
|
}
|
|
|
|
|
|
void ThumbView::contentsDropEvent(TQDropEvent *e) {
|
|
|
if (!e) {
|
|
|
return;
|
|
|
}
|
|
|
if (e->source() == this) {
|
|
|
e->accept();
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void ThumbView::keyPressEvent(TQKeyEvent *e) {
|
|
|
bool handled = false;
|
|
|
if (!d->firstItem) {
|
|
|
return;
|
|
|
}
|
|
|
ThumbItem *currItem = d->selectedItems.first();
|
|
|
if (!currItem) {
|
|
|
d->firstItem->setSelected(true, true);
|
|
|
return;
|
|
|
}
|
|
|
switch ( e->key() ) {
|
|
|
case Key_Home: {
|
|
|
d->firstItem->setSelected(true, true);
|
|
|
ensureItemVisible(d->firstItem);
|
|
|
handled = true;
|
|
|
break;
|
|
|
}
|
|
|
case Key_End: {
|
|
|
d->lastItem->setSelected(true, true);
|
|
|
ensureItemVisible(d->lastItem);
|
|
|
handled = true;
|
|
|
break;
|
|
|
}
|
|
|
case Key_Enter:
|
|
|
case Key_Return: {
|
|
|
emit signalReturnPressed(currItem);
|
|
|
break;
|
|
|
}
|
|
|
case Key_Right: {
|
|
|
ThumbItem *item = currItem->next;
|
|
|
if (item) {
|
|
|
item->setSelected(true,true);
|
|
|
ensureItemVisible(item);
|
|
|
handled = true;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
case Key_Left: {
|
|
|
ThumbItem *item = currItem->prev;
|
|
|
if (item) {
|
|
|
item->setSelected(true,true);
|
|
|
ensureItemVisible(item);
|
|
|
handled = true;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
case Key_Up: {
|
|
|
int x = currItem->x() + currItem->width()/2;
|
|
|
int y = currItem->y() - d->spacing*2;
|
|
|
ThumbItem *item = 0;
|
|
|
while (!item && y > 0) {
|
|
|
item = findItem(TQPoint(x,y));
|
|
|
y -= d->spacing * 2;
|
|
|
}
|
|
|
if (item) {
|
|
|
item->setSelected(true,true);
|
|
|
ensureItemVisible(item);
|
|
|
handled = true;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
case Key_Down: {
|
|
|
int x = currItem->x() + currItem->width()/2;
|
|
|
int y = currItem->y() + currItem->height() + d->spacing * 2;
|
|
|
ThumbItem *item = 0;
|
|
|
while (!item && y < contentsHeight()) {
|
|
|
item = findItem(TQPoint(x,y));
|
|
|
y += d->spacing * 2;
|
|
|
}
|
|
|
if (item) {
|
|
|
item->setSelected(true,true);
|
|
|
ensureItemVisible(item);
|
|
|
handled = true;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
case Key_Next: {
|
|
|
TQRect r( 0, currItem->y() + visibleHeight(),
|
|
|
contentsWidth(), visibleHeight() );
|
|
|
ThumbItem *ni = findFirstVisibleItem(r);
|
|
|
if (!ni) {
|
|
|
r = TQRect( 0, currItem->y() + currItem->height(), contentsWidth(), contentsHeight() );
|
|
|
ni = findLastVisibleItem( r );
|
|
|
}
|
|
|
if (ni) {
|
|
|
ni->setSelected(true, true);
|
|
|
ensureItemVisible(ni);
|
|
|
handled = true;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
case Key_Prior: {
|
|
|
TQRect r(0, currItem->y() - visibleHeight(), contentsWidth(), visibleHeight() );
|
|
|
ThumbItem *ni = findFirstVisibleItem(r);
|
|
|
if ( !ni ) {
|
|
|
r = TQRect( 0, 0, contentsWidth(), currItem->y() );
|
|
|
ni = findFirstVisibleItem( r );
|
|
|
}
|
|
|
if ( ni ) {
|
|
|
ni->setSelected(true, true);
|
|
|
ensureItemVisible(ni);
|
|
|
handled = true;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
default:
|
|
|
e->ignore();
|
|
|
return;
|
|
|
}
|
|
|
if (handled) {
|
|
|
viewport()->tqrepaint();
|
|
|
emit signalSelectionChanged();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void ThumbView::ensureItemVisible(ThumbItem *item) {
|
|
|
if (!item) {
|
|
|
return;
|
|
|
}
|
|
|
int w = item->width();
|
|
|
int h = item->height();
|
|
|
ensureVisible( item->x() + w / 2, item->y() + h / 2, w / 2 + 1, h / 2 + 1 );
|
|
|
}
|
|
|
|
|
|
ThumbItem* ThumbView::findFirstVisibleItem(const TQRect &r ) const {
|
|
|
ThumbViewPrivate::ItemContainer *c = d->firstContainer;
|
|
|
ThumbItem *i = 0;
|
|
|
bool alreadyIntersected = false;
|
|
|
for ( ; c; c = c->next ) {
|
|
|
if ( c->rect.intersects( r ) ) {
|
|
|
alreadyIntersected = true;
|
|
|
ThumbItem *item = c->items.first();
|
|
|
for ( ; item; item = c->items.next() ) {
|
|
|
if ( r.intersects( item->rect() ) ) {
|
|
|
if ( !i ) {
|
|
|
i = item;
|
|
|
} else {
|
|
|
TQRect r2 = item->rect();
|
|
|
TQRect r3 = i->rect();
|
|
|
if (r2.y() < r3.y()) {
|
|
|
i = item;
|
|
|
} else if (r2.y() == r3.y() && r2.x() < r3.x()) {
|
|
|
i = item;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
if (alreadyIntersected) {
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return i;
|
|
|
}
|
|
|
|
|
|
ThumbItem* ThumbView::findLastVisibleItem(const TQRect &r ) const {
|
|
|
ThumbViewPrivate::ItemContainer *c = d->firstContainer;
|
|
|
ThumbItem *i = 0;
|
|
|
bool alreadyIntersected = false;
|
|
|
for ( ; c; c = c->next ) {
|
|
|
if ( c->rect.intersects( r ) ) {
|
|
|
alreadyIntersected = true;
|
|
|
ThumbItem *item = c->items.first();
|
|
|
for ( ; item; item = c->items.next() ) {
|
|
|
if ( r.intersects( item->rect() ) ) {
|
|
|
if ( !i ) {
|
|
|
i = item;
|
|
|
} else {
|
|
|
TQRect r2 = item->rect();
|
|
|
TQRect r3 = i->rect();
|
|
|
if (r2.y() > r3.y()) {
|
|
|
i = item;
|
|
|
} else if (r2.y() == r3.y() && r2.x() > r3.x()) {
|
|
|
i = item;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
if (alreadyIntersected) {
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return i;
|
|
|
}
|
|
|
|
|
|
} // NameSpace KIPIKameraKlientPlugin
|
|
|
|
|
|
#include "thumbview.moc"
|