/*************************************************************************** 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 <tdeapplication.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_) : TDEListView(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(tdedisplayPaletteChanged()), 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)); TDEListView::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); TDEListView::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 ? TDEListViewItem::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_); TDEListViewItem::setSelected(s_); } } TQColor ListViewItem::backgroundColor(int column_) { #if KDE_IS_VERSION(3,3,90) return TDEListViewItem::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 tdelistview.cpp // I can't call TDEListViewItem::paintCell since TDEListViewItem::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 TDEListViewItem::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"