|
|
|
/***************************************************************************
|
|
|
|
copyright : (C) 2001-2006 by Robby Stephenson
|
|
|
|
email : robby@periapsis.org
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of version 2 of the GNU General Public License as *
|
|
|
|
* published by the Free Software Foundation; *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "listview.h"
|
|
|
|
#include "../controller.h"
|
|
|
|
#include "../tellico_utils.h"
|
|
|
|
#include "../tellico_debug.h"
|
|
|
|
|
|
|
|
#include <kapplication.h>
|
|
|
|
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <tqpixmap.h>
|
|
|
|
#include <tqheader.h>
|
|
|
|
|
|
|
|
using Tellico::GUI::ListView;
|
|
|
|
using Tellico::GUI::ListViewItem;
|
|
|
|
|
|
|
|
ListView::ListView(TQWidget* parent_, const char* name_) : KListView(parent_, name_/*=0*/),
|
|
|
|
m_sortStyle(SortByText), m_isClear(true) {
|
|
|
|
setSelectionMode(TQListView::Extended);
|
|
|
|
connect(this, TQT_SIGNAL(selectionChanged()),
|
|
|
|
TQT_SLOT(slotSelectionChanged()));
|
|
|
|
connect(this, TQT_SIGNAL(doubleClicked(TQListViewItem*)),
|
|
|
|
TQT_SLOT(slotDoubleClicked(TQListViewItem*)));
|
|
|
|
#if !KDE_IS_VERSION(3,3,90)
|
|
|
|
m_shadeSortColumn = false;
|
|
|
|
// call it once to initialize
|
|
|
|
slotUpdateColors();
|
|
|
|
#endif
|
|
|
|
connect(kapp, TQT_SIGNAL(kdisplayPaletteChanged()), TQT_SLOT(slotUpdateColors()));
|
|
|
|
m_comparisons.setAutoDelete(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
ListView::~ListView() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListView::clearSelection() {
|
|
|
|
if(m_selectedItems.isEmpty()) {
|
|
|
|
// nothing to do;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
bool b = signalsBlocked();
|
|
|
|
blockSignals(true);
|
|
|
|
selectAll(false);
|
|
|
|
blockSignals(b);
|
|
|
|
emit selectionChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListView::updateSelected(ListViewItem* item_, bool selected_) {
|
|
|
|
if(selected_) {
|
|
|
|
m_selectedItems.append(item_);
|
|
|
|
} else {
|
|
|
|
m_selectedItems.removeRef(item_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ListView::isSelectable(ListViewItem* item_) const {
|
|
|
|
// don't allow hidden items to be selected
|
|
|
|
if(!item_->isVisible()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// selecting multiple items is ok
|
|
|
|
// only when parent is open. Be careful to check for existence of parent
|
|
|
|
if(item_->parent() && !item_->parent()->isOpen()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// just selecting a single item is always ok
|
|
|
|
if(m_selectedItems.isEmpty()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// not allowed is something other than an entry is selected and current is entry
|
|
|
|
if(m_selectedItems.getFirst()->isEntryItem() != item_->isEntryItem()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ListView::firstVisibleColumn() const {
|
|
|
|
int col = 0;
|
|
|
|
while(col < columns() && columnWidth(header()->mapToSection(col)) == 0) {
|
|
|
|
++col;
|
|
|
|
}
|
|
|
|
if(col == columns()) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return header()->mapToSection(col);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ListView::lastVisibleColumn() const {
|
|
|
|
int col = columns()-1;
|
|
|
|
while(col < columns() && columnWidth(header()->mapToSection(col)) == 0) {
|
|
|
|
--col;
|
|
|
|
}
|
|
|
|
if(col == columns()) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return header()->mapToSection(col);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListView::setColumnText(int column, const TQString& label) {
|
|
|
|
ListViewComparison* comp = m_comparisons.take(columnText(column));
|
|
|
|
KListView::setColumnText(column, label);
|
|
|
|
if(comp) {
|
|
|
|
m_comparisons.insert(columnText(column), comp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListView::setComparison(int column, ListViewComparison* comp) {
|
|
|
|
if(comp) {
|
|
|
|
m_comparisons.replace(columnText(column), comp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListView::removeComparison(int column) {
|
|
|
|
m_comparisons.remove(columnText(column));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListView::clearComparisons() {
|
|
|
|
m_comparisons.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
int ListView::compare(int col, const GUI::ListViewItem* item1, GUI::ListViewItem* item2, bool asc) {
|
|
|
|
if(col >= 0 && col < static_cast<int>(m_comparisons.count())) {
|
|
|
|
ListViewComparison* com = m_comparisons.find(columnText(col));
|
|
|
|
if(com) {
|
|
|
|
return com->compare(col, item1, item2, asc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !KDE_IS_VERSION(3,3,90)
|
|
|
|
void ListView::setShadeSortColumn(bool shade_) {
|
|
|
|
if(m_shadeSortColumn != shade_) {
|
|
|
|
m_shadeSortColumn = shade_;
|
|
|
|
repaint();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void ListView::slotUpdateColors() {
|
|
|
|
#if !KDE_IS_VERSION(3,3,90)
|
|
|
|
m_backColor2 = viewport()->colorGroup().base();
|
|
|
|
if(m_backColor2 == TQt::black) {
|
|
|
|
m_backColor2 = TQColor(50, 50, 50); // dark gray
|
|
|
|
} else {
|
|
|
|
int h,s,v;
|
|
|
|
m_backColor2.hsv(&h, &s, &v);
|
|
|
|
if(v > 175) {
|
|
|
|
m_backColor2 = m_backColor2.dark(105);
|
|
|
|
} else {
|
|
|
|
m_backColor2 = m_backColor2.light(120);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_altColor2 = alternateBackground();
|
|
|
|
if(m_altColor2 == TQt::black) {
|
|
|
|
m_altColor2 = TQColor(50, 50, 50); // dark gray
|
|
|
|
} else {
|
|
|
|
int h,s,v;
|
|
|
|
m_altColor2.hsv(&h, &s, &v);
|
|
|
|
if(v > 175) {
|
|
|
|
m_altColor2 = m_altColor2.dark(105);
|
|
|
|
} else {
|
|
|
|
m_altColor2 = m_altColor2.light(120);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
Tellico::updateContrastColor(viewport()->colorGroup());
|
|
|
|
repaint();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListView::slotSelectionChanged() {
|
|
|
|
if(m_selectedItems.isEmpty()) {
|
|
|
|
if(m_isClear) {
|
|
|
|
return; // nothing to do
|
|
|
|
}
|
|
|
|
m_isClear = true;
|
|
|
|
Controller::self()->slotClearSelection();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_isClear = false;
|
|
|
|
|
|
|
|
Data::EntryVec entries;
|
|
|
|
// now just find all the children or grandchildren that are entry items
|
|
|
|
for(GUI::ListViewItemListIt it(m_selectedItems); it.current(); ++it) {
|
|
|
|
Data::EntryVec more = it.current()->entries();
|
|
|
|
for(Data::EntryVecIt entry = more.begin(); entry != more.end(); ++entry) {
|
|
|
|
if(!entries.contains(entry)) {
|
|
|
|
entries.append(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Controller::self()->slotUpdateCurrent(entries); // just update current, don't change selection
|
|
|
|
Controller::self()->slotUpdateSelection(this, entries);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListView::slotDoubleClicked(TQListViewItem* item_) {
|
|
|
|
if(!item_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if it has children, just open it
|
|
|
|
// but some items delay children creation
|
|
|
|
if(static_cast<ListViewItem*>(item_)->realChildCount() > 0) {
|
|
|
|
item_->setOpen(!item_->isOpen());
|
|
|
|
}
|
|
|
|
|
|
|
|
GUI::ListViewItem* item = static_cast<GUI::ListViewItem*>(item_);
|
|
|
|
item->doubleClicked();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListView::drawContentsOffset(TQPainter* p, int ox, int oy, int cx, int cy, int cw, int ch) {
|
|
|
|
bool oldUpdatesEnabled = isUpdatesEnabled();
|
|
|
|
setUpdatesEnabled(false);
|
|
|
|
KListView::drawContentsOffset(p, ox, oy, cx, cy, cw, ch);
|
|
|
|
setUpdatesEnabled(oldUpdatesEnabled);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ****************** ListViewItem ********************* */
|
|
|
|
|
|
|
|
ListViewItem::~ListViewItem() {
|
|
|
|
// I think there's a bug in qt where the children of this item are deleted after the item itself
|
|
|
|
// as a result, there is no listView() pointer for the children, that obvious causes
|
|
|
|
// a problem with updating the selection. So we MUST call clear() here ourselves!
|
|
|
|
clear();
|
|
|
|
// be sure to remove from selected list when it's deleted
|
|
|
|
ListView* lv = listView();
|
|
|
|
if(lv) {
|
|
|
|
lv->updateSelected(this, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListViewItem::clear() {
|
|
|
|
TQListViewItem* item = firstChild();
|
|
|
|
while(item) {
|
|
|
|
delete item;
|
|
|
|
item = firstChild();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int ListViewItem::compare(TQListViewItem* item_, int col_, bool asc_) const {
|
|
|
|
int res = compareWeight(item_, col_, asc_);
|
|
|
|
if(res != 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
res = listView()->compare(col_, this, static_cast<GUI::ListViewItem*>(item_), asc_);
|
|
|
|
return res == 0 ? KListViewItem::compare(item_, col_, asc_) : res;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ListViewItem::compareWeight(TQListViewItem* item_, int col_, bool asc_) const {
|
|
|
|
Q_UNUSED(col_);
|
|
|
|
// I want the sorting to be independent of sort order
|
|
|
|
GUI::ListViewItem* i = static_cast<GUI::ListViewItem*>(item_);
|
|
|
|
int res = 0;
|
|
|
|
if(m_sortWeight < i->sortWeight()) {
|
|
|
|
res = -1;
|
|
|
|
} else if(m_sortWeight > i->sortWeight()) {
|
|
|
|
res = 1;
|
|
|
|
}
|
|
|
|
if(asc_) {
|
|
|
|
res *= -1; // reverse, heavier weights will come first always
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListViewItem::setSelected(bool s_) {
|
|
|
|
ListView* lv = listView();
|
|
|
|
if(!lv) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(s_ && !lv->isSelectable(this)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(s_ != isSelected()) {
|
|
|
|
lv->updateSelected(this, s_);
|
|
|
|
KListViewItem::setSelected(s_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQColor ListViewItem::backgroundColor(int column_) {
|
|
|
|
#if KDE_IS_VERSION(3,3,90)
|
|
|
|
return KListViewItem::backgroundColor(column_);
|
|
|
|
#else
|
|
|
|
ListView* view = listView();
|
|
|
|
if(view->columns() > 1 && view->shadeSortColumn() && column_ == view->sortColumn()) {
|
|
|
|
return isAlternate() ? view->alternateBackground2() : view->background2();
|
|
|
|
}
|
|
|
|
return isAlternate() ? view->alternateBackground() : view->viewport()->colorGroup().base();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListViewItem::paintCell(TQPainter* p_, const TQColorGroup& cg_,
|
|
|
|
int column_, int width_, int align_) {
|
|
|
|
// taken from klistview.cpp
|
|
|
|
// I can't call KListViewItem::paintCell since KListViewItem::backgroundCOlor(int) is
|
|
|
|
// not virtual. I need to be sure to call ListViewItem::backgroundColor(int);
|
|
|
|
TQColorGroup cg = cg_;
|
|
|
|
const TQPixmap* pm = listView()->viewport()->backgroundPixmap();
|
|
|
|
if(pm && !pm->isNull()) {
|
|
|
|
cg.setBrush(TQColorGroup::Base, TQBrush(backgroundColor(column_), *pm));
|
|
|
|
TQPoint o = p_->brushOrigin();
|
|
|
|
p_->setBrushOrigin(o.x()-listView()->contentsX(), o.y()-listView()->contentsY());
|
|
|
|
} else {
|
|
|
|
cg.setColor(listView()->viewport()->backgroundMode() == TQt::FixedColor ?
|
|
|
|
TQColorGroup::Background : TQColorGroup::Base,
|
|
|
|
backgroundColor(column_));
|
|
|
|
}
|
|
|
|
|
|
|
|
// don't call KListViewItem::paintCell() since that also does alternate painting, etc...
|
|
|
|
TQListViewItem::paintCell(p_, cg, column_, width_, align_);
|
|
|
|
|
|
|
|
// borrowed from amarok, draw line to left of cell
|
|
|
|
if(!isSelected()) {
|
|
|
|
p_->setPen(TQPen(listView()->alternateBackground(), 0, TQt::SolidLine));
|
|
|
|
p_->drawLine(width_-1, 0, width_-1, height()-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Tellico::Data::EntryVec ListViewItem::entries() const {
|
|
|
|
Data::EntryVec entries;
|
|
|
|
for(TQListViewItem* child = firstChild(); child; child = child->nextSibling()) {
|
|
|
|
Data::EntryVec more = static_cast<GUI::ListViewItem*>(child)->entries();
|
|
|
|
for(Data::EntryVecIt entry = more.begin(); entry != more.end(); ++entry) {
|
|
|
|
if(!entries.contains(entry)) {
|
|
|
|
entries.append(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return entries;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "listview.moc"
|