/*************************************************************************** kmymoneyselector.cpp ------------------- begin : Thu Jun 29 2006 copyright : (C) 2006 by Thomas Baumgart email : Thomas Baumgart ***************************************************************************/ /*************************************************************************** * * * 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 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes #include #include #include #include "../kmymoneyglobalsettings.h" KMyMoneySelector::KMyMoneySelector(TQWidget *parent, const char *name, TQWidget::WFlags flags) : TQWidget(parent, name, flags) { m_selMode = TQListView::Single; m_listView = new TDEListView(this); // don't show horizontal scroll bar m_listView->setHScrollBarMode(TQScrollView::AlwaysOff); m_listView->setSorting(-1); if(parent) { setFocusProxy(parent->focusProxy()); m_listView->setFocusProxy(parent->focusProxy()); } m_listView->setAllColumnsShowFocus(true); m_layout = new TQHBoxLayout( this, 0, 6); m_listView->addColumn( "Hidden" ); m_listView->header()->hide(); m_listView->header()->setStretchEnabled(true, -1); m_listView->header()->adjustHeaderSize(); m_layout->addWidget( m_listView ); // force init m_selMode = TQListView::Multi; setSelectionMode(TQListView::Single); connect(m_listView, TQT_SIGNAL(rightButtonPressed(TQListViewItem* , const TQPoint&, int)), this, TQT_SLOT(slotListRightMouse(TQListViewItem*, const TQPoint&, int))); } KMyMoneySelector::~KMyMoneySelector() { } void KMyMoneySelector::clear(void) { m_listView->clear(); m_visibleItem = 0; } void KMyMoneySelector::setSelectionMode(const TQListView::SelectionMode mode) { if(m_selMode != mode) { m_selMode = mode; clear(); // make sure, it's either Multi or Single if(mode != TQListView::Multi) { m_selMode = TQListView::Single; connect(m_listView, TQT_SIGNAL(selectionChanged(void)), this, TQT_SIGNAL(stateChanged(void))); connect(m_listView, TQT_SIGNAL(executed(TQListViewItem*)), this, TQT_SLOT(slotItemSelected(TQListViewItem*))); } else { disconnect(m_listView, TQT_SIGNAL(selectionChanged(void)), this, TQT_SIGNAL(stateChanged(void))); disconnect(m_listView, TQT_SIGNAL(executed(TQListViewItem*)), this, TQT_SLOT(slotItemSelected(TQListViewItem*))); } } TQWidget::update(); } void KMyMoneySelector::slotItemSelected(TQListViewItem *item) { if(m_selMode == TQListView::Single) { KMyMoneyListViewItem* l_item = dynamic_cast(item); if(l_item && l_item->isSelectable()) { emit itemSelected(l_item->id()); } } } TQListViewItem* KMyMoneySelector::newItem(const TQString& name, TQListViewItem* after, const TQString& key, const TQString& id, TQCheckListItem::Type type) { TQListViewItem* item; if(after) item = new KMyMoneyCheckListItem(m_listView, after, name, key, id, type); else item = new KMyMoneyCheckListItem(m_listView, name, key, id, type); item->setSelectable(!id.isEmpty()); item->setOpen(true); return item; } TQListViewItem* KMyMoneySelector::newItem(const TQString& name, const TQString& key, const TQString& id, TQCheckListItem::Type type) { return newItem(name, 0, key, id, type); } TQListViewItem* KMyMoneySelector::newTopItem(const TQString& name, const TQString& key, const TQString& id) { TQListViewItem* p; if(m_selMode == TQListView::Multi) { KMyMoneyCheckListItem* q = new KMyMoneyCheckListItem(m_listView, name, key, id); connect(q, TQT_SIGNAL(stateChanged(bool)), this, TQT_SIGNAL(stateChanged(void))); p = static_cast (q); } else { KMyMoneyListViewItem* q = new KMyMoneyListViewItem(m_listView, name, key, id); p = static_cast (q); } return p; } TQListViewItem* KMyMoneySelector::newItem(TQListViewItem* parent, const TQString& name, const TQString& key, const TQString& id) { TQListViewItem* p; if(m_selMode == TQListView::Multi) { KMyMoneyCheckListItem* q = new KMyMoneyCheckListItem(parent, name, key, id); connect(q, TQT_SIGNAL(stateChanged(bool)), this, TQT_SIGNAL(stateChanged(void))); p = static_cast (q); } else { KMyMoneyListViewItem* q = new KMyMoneyListViewItem(parent, name, key, id); p = static_cast (q); } return p; } void KMyMoneySelector::protectItem(const TQString& itemId, const bool protect) { TQListViewItemIterator it(m_listView, TQListViewItemIterator::Selectable); TQListViewItem* it_v; KMyMoneyListViewItem* it_l; KMyMoneyCheckListItem* it_c; // scan items while((it_v = it.current()) != 0) { it_l = dynamic_cast(it_v); if(it_l) { if(it_l->id() == itemId) { it_l->setSelectable(!protect); break; } } else { it_c = dynamic_cast(it_v); if(it_c) { if(it_c->id() == itemId) { it_c->setSelectable(!protect); break; } } } ++it; } } TQListViewItem* KMyMoneySelector::item(const TQString& id) const { TQListViewItemIterator it(m_listView, TQListViewItemIterator::Selectable); TQListViewItem* it_v; KMyMoneyListViewItem* it_l; KMyMoneyCheckListItem* it_c; while((it_v = it.current()) != 0) { it_l = dynamic_cast(it_v); if(it_l) { if(it_l->id() == id) break; } else { it_c = dynamic_cast(it_v); if(it_c->id() == id) break; } ++it; } return it_v; } int KMyMoneySelector::optimizedWidth(void) const { TQListViewItemIterator it(m_listView, TQListViewItemIterator::Selectable); TQListViewItem* it_v; KMyMoneyListViewItem* it_l; KMyMoneyCheckListItem* it_c; // scan items int w = 0; #ifndef KMM_DESIGNER TQFontMetrics fm( KMyMoneyGlobalSettings::listCellFont()); #else TQFontMetrics fm( font() ); #endif while((it_v = it.current()) != 0) { it_l = dynamic_cast(it_v); int nw = 0; if(it_l) { nw = it_l->width(fm, m_listView, 0); } else { it_c = dynamic_cast(it_v); if(it_c) { nw = it_c->width(fm, m_listView, 0); } } if(nw > w) w = nw; ++it; } return w; } void KMyMoneySelector::setOptimizedWidth(void) { int w = optimizedWidth(); m_listView->setMinimumWidth(w+30); m_listView->setMaximumWidth(w+30); m_listView->setColumnWidth(0, w+28); } bool KMyMoneySelector::allItemsSelected(void) const { TQListViewItem* it_v; if(m_selMode == TQListView::Single) return false; for(it_v = m_listView->firstChild(); it_v != 0; it_v = it_v->nextSibling()) { if(it_v->rtti() == 1) { TQCheckListItem* it_c = dynamic_cast(it_v); if(it_c->type() == TQCheckListItem::CheckBox) { if(!(it_c->isOn() && allItemsSelected(it_v))) return false; } else { if(!allItemsSelected(it_v)) return false; } } } return true; } bool KMyMoneySelector::allItemsSelected(const TQListViewItem *item) const { TQListViewItem* it_v; for(it_v = item->firstChild(); it_v != 0; it_v = it_v->nextSibling()) { if(it_v->rtti() == 1) { TQCheckListItem* it_c = static_cast(it_v); if(!(it_c->isOn() && allItemsSelected(it_v))) return false; } } return true; } void KMyMoneySelector::removeItem(const TQString& id) { TQListViewItem* it_v; TQListViewItemIterator it; it = TQListViewItemIterator(m_listView); while((it_v = it.current()) != 0) { if(it_v->rtti() == 1) { KMyMoneyCheckListItem* it_c = dynamic_cast(it_v); if(it_c->type() == TQCheckListItem::CheckBox) { if(id == it_c->id()) { if(it_c->firstChild()) { it_c->setSelectable(false); } else { delete it_c; } } } } else if(it_v->rtti() == 0) { KMyMoneyListViewItem* it_c = dynamic_cast(it_v); if(id == it_c->id()) { if(it_c->firstChild()) { it_c->setSelectable(false); } else { delete it_c; } } } it++; } // get rid of top items that just lost the last children (e.g. Favorites) it = TQListViewItemIterator(m_listView, TQListViewItemIterator::NotSelectable); while((it_v = it.current()) != 0) { if(it_v->rtti() == 1) { KMyMoneyCheckListItem* it_c = dynamic_cast(it_v); if(it_c->childCount() == 0) delete it_c; } it++; } return; } void KMyMoneySelector::selectAllItems(const bool state) { TQListViewItem* it_v; for(it_v = m_listView->firstChild(); it_v != 0; it_v = it_v->nextSibling()) { if(it_v->rtti() == 1) { TQCheckListItem* it_c = dynamic_cast(it_v); if(it_c->type() == TQCheckListItem::CheckBox) { it_c->setOn(state); } selectAllSubItems(it_v, state); } } emit stateChanged(); } void KMyMoneySelector::selectItems(const TQStringList& itemList, const bool state) { TQListViewItem* it_v; for(it_v = m_listView->firstChild(); it_v != 0; it_v = it_v->nextSibling()) { if(it_v->rtti() == 1) { KMyMoneyCheckListItem* it_c = dynamic_cast(it_v); if(it_c->type() == TQCheckListItem::CheckBox && itemList.contains(it_c->id())) { it_c->setOn(state); } selectSubItems(it_v, itemList, state); } } emit stateChanged(); } void KMyMoneySelector::selectSubItems(TQListViewItem* item, const TQStringList& itemList, const bool state) { TQListViewItem* it_v; for(it_v = item->firstChild(); it_v != 0; it_v = it_v->nextSibling()) { if(it_v->rtti() == 1) { KMyMoneyCheckListItem* it_c = dynamic_cast(it_v); if(it_c->type() == TQCheckListItem::CheckBox && itemList.contains(it_c->id())) { it_c->setOn(state); } selectSubItems(it_v, itemList, state); } } } void KMyMoneySelector::selectAllSubItems(TQListViewItem* item, const bool state) { TQListViewItem* it_v; for(it_v = item->firstChild(); it_v != 0; it_v = it_v->nextSibling()) { if(it_v->rtti() == 1) { TQCheckListItem* it_c = dynamic_cast(it_v); if(it_c->type() == TQCheckListItem::CheckBox) { it_c->setOn(state); } selectAllSubItems(it_v, state); } } } void KMyMoneySelector::selectedItems(TQStringList& list) const { TQListViewItem* it_v; list.clear(); if(m_selMode == TQListView::Single) { KMyMoneyListViewItem* it_c = dynamic_cast(m_listView->selectedItem()); if(it_c != 0) list << it_c->id(); } else { for(it_v = m_listView->firstChild(); it_v != 0; it_v = it_v->nextSibling()) { if(it_v->rtti() == 1) { KMyMoneyCheckListItem* it_c = dynamic_cast(it_v); if(it_c->type() == TQCheckListItem::CheckBox) { if(it_c->isOn()) list << (*it_c).id(); } selectedItems(list, it_v); } } } } void KMyMoneySelector::selectedItems(TQStringList& list, TQListViewItem* item) const { TQListViewItem* it_v; for(it_v = item->firstChild(); it_v != 0; it_v = it_v->nextSibling()) { if(it_v->rtti() == 1) { KMyMoneyCheckListItem* it_c = dynamic_cast(it_v); if(it_c->type() == TQCheckListItem::CheckBox) { if(it_c->isOn()) list << (*it_c).id(); selectedItems(list, it_v); } } } } void KMyMoneySelector::itemList(TQStringList& list) const { TQListViewItemIterator it; TQListViewItem* it_v; it = TQListViewItemIterator(m_listView, TQListViewItemIterator::Selectable); while((it_v = it.current()) != 0) { { if(it_v->rtti() == 1) { KMyMoneyCheckListItem* it_c = dynamic_cast(it_v); if(it_c->type() == TQCheckListItem::CheckBox) { list << it_c->id(); } } else if(it_v->rtti() == 0) { KMyMoneyListViewItem* it_c = dynamic_cast(it_v); list << it_c->id(); } } it++; } } void KMyMoneySelector::setSelected(const TQString& id, const bool state) { TQListViewItemIterator it; TQListViewItem* it_v; TQListViewItem* it_visible = 0; it = TQListViewItemIterator(m_listView, TQListViewItemIterator::Selectable); while((it_v = it.current()) != 0) { if(it_v->rtti() == 1) { KMyMoneyCheckListItem* it_c = dynamic_cast(it_v); TQ_CHECK_PTR(it_c); if(it_c->type() == TQCheckListItem::CheckBox) { if(it_c->id() == id) { it_c->setOn(state); m_listView->setSelected(it_v, true); if(!it_visible) it_visible = it_v; } } } else if(it_v->rtti() == 0) { KMyMoneyListViewItem* it_c = dynamic_cast(it_v); TQ_CHECK_PTR(it_c); if(it_c->id() == id) { m_listView->setSelected(it_v, true); if(!it_visible) it_visible = it_v; ensureItemVisible(it_v); return; } } it++; } // make sure the first one found is visible if(it_visible) ensureItemVisible(it_visible); } void KMyMoneySelector::ensureItemVisible(const TQListViewItem *it_v) { // for some reason, I could only use the ensureItemVisible() method // of TQListView successfully, after the widget was drawn on the screen. // If called before it had no effect (if the item was not visible). // // The solution was to store the item we wanted to see in a local var // and call TQListView::ensureItemVisible() about 10ms later in // the slot slotShowSelected. (ipwizard, 12/29/2003) m_visibleItem = it_v; TQTimer::singleShot(100, this, TQT_SLOT(slotShowSelected())); } void KMyMoneySelector::slotShowSelected(void) { if(m_listView && m_visibleItem) m_listView->ensureItemVisible(m_visibleItem); } int KMyMoneySelector::slotMakeCompletion(const TQString& _txt) { TQString txt(TQRegExp::escape(_txt)); if(KMyMoneyGlobalSettings::stringMatchFromStart() && this->isA("KMyMoneySelector") ) txt.prepend('^'); return slotMakeCompletion(TQRegExp(txt, false)); } bool KMyMoneySelector::match(const TQRegExp& exp, TQListViewItem* item) const { return exp.search(item->text(0)) != -1; } int KMyMoneySelector::slotMakeCompletion(const TQRegExp& exp) { TQListViewItemIterator it(m_listView, TQListViewItemIterator::Selectable); TQListViewItem* it_v; // The logic used here seems to be awkward. The problem is, that // TQListViewItem::setVisible works recursively on all it's children // and grand-children. // // The way out of this is as follows: Make all items visible. // Then go through the list again and perform the checks. // If an item does not have any children (last leaf in the tree view) // perform the check. Then check recursively on the parent of this // leaf that it has no visible children. If that is the case, make the // parent invisible and continue this check with it's parent. while((it_v = it.current()) != 0) { it_v->setVisible(true); ++it; } TQListViewItem* firstMatch = 0; if(!exp.pattern().isEmpty()) { it = TQListViewItemIterator(m_listView, TQListViewItemIterator::Selectable); while((it_v = it.current()) != 0) { if(it_v->firstChild() == 0) { if(!match(exp, it_v)) { // this is a node which does not contain the // text and does not have children. So we can // safely hide it. Then we check, if the parent // has more children which are still visible. If // none are found, the parent node is hidden also. We // continue until the top of the tree or until we // find a node that still has visible children. bool hide = true; while(hide) { it_v->setVisible(false); it_v = it_v->parent(); if(it_v && it_v->isSelectable()) { hide = !match(exp, it_v); TQListViewItem* child = it_v->firstChild(); for(; child && hide; child = child->nextSibling()) { if(child->isVisible()) hide = false; } } else hide = false; } } else if(!firstMatch) { firstMatch = it_v; } ++it; } else if(match(exp, it_v)) { if(!firstMatch) { firstMatch = it_v; } // a node with children contains the text. We want // to display all child nodes in this case, so we need // to advance the iterator to the next sibling of the // current node. This could well be the sibling of a // parent or grandparent node. TQListViewItem* curr = it_v; TQListViewItem* item; while((item = curr->nextSibling()) == 0) { curr = curr->parent(); if(curr == 0) break; if(match(exp, curr)) firstMatch = curr; } do { ++it; } while(it.current() && it.current() != item); } else { // It's a node with children that does not match. We don't // change it's status here. ++it; } } } // make the first match the one that is selected // if we have no match, make sure none is selected if(m_selMode == TQListView::Single) { if(firstMatch) { m_listView->setSelected(firstMatch, true); ensureItemVisible(firstMatch); } else m_listView->selectAll(false); } // Get the number of visible nodes for the return code int cnt = 0; it = TQListViewItemIterator(m_listView, TQListViewItemIterator::Selectable | TQListViewItemIterator::Visible); while((it_v = it.current()) != 0) { cnt++; it++; } return cnt; } bool KMyMoneySelector::contains(const TQString& txt) const { TQListViewItemIterator it(m_listView, TQListViewItemIterator::Selectable); TQListViewItem* it_v; while((it_v = it.current()) != 0) { if(it_v->rtti() == 1) { KMyMoneyCheckListItem* it_c = dynamic_cast(it_v); if(it_c->text() == txt) { return true; } } else if(it_v->rtti() == 0) { KMyMoneyListViewItem* it_c = dynamic_cast(it_v); if(it_c->text(0) == txt) { return true; } } it++; } return false; } void KMyMoneySelector::slotListRightMouse(TQListViewItem* it_v, const TQPoint& pos, int /* col */) { if(it_v && (it_v->rtti() == 1)) { KMyMoneyCheckListItem* it_c = static_cast(it_v); if(it_c->type() == TQCheckListItem::CheckBox) { // the following is copied from TQCheckListItem::activate() et al int boxsize = m_listView->style().pixelMetric(TQStyle::PM_CheckListButtonSize, m_listView); int align = m_listView->columnAlignment( 0 ); int marg = m_listView->itemMargin(); int y = 0; if ( align & AlignVCenter ) y = ( ( height() - boxsize ) / 2 ) + marg; else y = (m_listView->fontMetrics().height() + 2 + marg - boxsize) / 2; TQRect r( 0, y, boxsize-3, boxsize-3 ); // columns might have been swapped r.moveBy( m_listView->header()->sectionPos( 0 ), 0 ); TQPoint topLeft = m_listView->itemRect(it_v).topLeft(); //### inefficient? TQPoint p = m_listView->mapFromGlobal( pos ) - topLeft; int xdepth = m_listView->treeStepSize() * (it_v->depth() + (m_listView->rootIsDecorated() ? 1 : 0)) + m_listView->itemMargin(); xdepth += m_listView->header()->sectionPos( m_listView->header()->mapToSection( 0 ) ); p.rx() -= xdepth; // copy ends around here if ( r.contains( p ) ) { // we get down here, if we have a right click onto the checkbox selectAllSubItems(it_c, it_c->isOn()); } } } } TQStringList KMyMoneySelector::selectedItems(void) const { TQStringList list; selectedItems(list); return list; } TQStringList KMyMoneySelector::itemList(void) const { TQStringList list; itemList(list); return list; } #include "kmymoneyselector.moc"