summaryrefslogtreecommitdiffstats
path: root/src/detailedlistview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/detailedlistview.cpp')
-rw-r--r--src/detailedlistview.cpp894
1 files changed, 894 insertions, 0 deletions
diff --git a/src/detailedlistview.cpp b/src/detailedlistview.cpp
new file mode 100644
index 0000000..5c4e2d2
--- /dev/null
+++ b/src/detailedlistview.cpp
@@ -0,0 +1,894 @@
+/***************************************************************************
+ copyright : (C) 2001-2006 by Robby Stephenson
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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 "detailedlistview.h"
+#include "detailedentryitem.h"
+#include "collection.h"
+#include "imagefactory.h"
+#include "controller.h"
+#include "field.h"
+#include "entry.h"
+#include "gui/ratingwidget.h"
+#include "tellico_debug.h"
+#include "tellico_kernel.h"
+#include "core/tellico_config.h"
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kapplication.h>
+#include <kaction.h>
+#include <kiconloader.h>
+#include <kpopupmenu.h>
+
+#include <qptrlist.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+#include <qheader.h>
+
+namespace {
+ static const int MIN_COL_WIDTH = 50;
+}
+
+using Tellico::DetailedListView;
+
+DetailedListView::DetailedListView(QWidget* parent_, const char* name_/*=0*/)
+ : GUI::ListView(parent_, name_), m_filter(0),
+ m_prevSortColumn(-1), m_prev2SortColumn(-1), m_firstSection(-1),
+ m_pixWidth(50), m_pixHeight(50) {
+// myDebug() << "DetailedListView()" << endl;
+ setAllColumnsShowFocus(true);
+ setShowSortIndicator(true);
+ setShadeSortColumn(true);
+
+// connect(this, SIGNAL(selectionChanged()), SLOT(slotSelectionChanged()));
+ connect(this, SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int)),
+ SLOT(contextMenuRequested(QListViewItem*, const QPoint&, int)));
+ connect(header(), SIGNAL(indexChange(int, int, int)),
+ SLOT(slotUpdatePixmap()));
+
+ // header menu
+ header()->setClickEnabled(true);
+ header()->installEventFilter(this);
+ connect(header(), SIGNAL(sizeChange(int, int, int)),
+ this, SLOT(slotCacheColumnWidth(int, int, int)));
+
+ m_headerMenu = new KPopupMenu(this);
+ m_headerMenu->setCheckable(true);
+ m_headerMenu->insertTitle(i18n("View Columns"));
+ connect(m_headerMenu, SIGNAL(activated(int)),
+ this, SLOT(slotHeaderMenuActivated(int)));
+
+ m_checkPix = UserIcon(QString::fromLatin1("checkmark"));
+}
+
+DetailedListView::~DetailedListView() {
+}
+
+void DetailedListView::addCollection(Data::CollPtr coll_) {
+ if(!coll_) {
+ return;
+ }
+
+ m_imageColumns.clear();
+// myDebug() << "DetailedListView::addCollection()" << endl;
+
+ KConfigGroup config(kapp->config(), QString::fromLatin1("Options - %1").arg(coll_->typeName()));
+
+ QString configN;
+ if(coll_->type() == Data::Collection::Base) {
+ KURL url = Kernel::self()->URL();
+ for(uint i = 0; i < Config::maxCustomURLSettings(); ++i) {
+ KURL u = config.readEntry(QString::fromLatin1("URL_%1").arg(i));
+ if(u == url) {
+ configN = QString::fromLatin1("_%1").arg(i);
+ break;
+ }
+ }
+ }
+
+ QStringList colNames = config.readListEntry("ColumnNames" + configN);
+ if(colNames.isEmpty()) {
+ colNames = QString::fromLatin1("title");
+ }
+
+ // this block compensates for the chance that the user added a field and it wasn't
+ // written to the widths. Also compensates for 0.5.x to 0.6.x column layout changes
+ QValueList<int> colWidths = config.readIntListEntry("ColumnWidths" + configN);
+ if(colWidths.empty()) {
+ colWidths.insert(colWidths.begin(), colNames.count(), -1); // automatic width
+ }
+
+ QValueList<int> colOrder = config.readIntListEntry("ColumnOrder" + configN);
+
+ // need to remove values for fields which don't exist in the current collection
+ QStringList newCols;
+ QValueList<int> newWidths, removeCols;
+ for(uint i = 0; i < colNames.count(); ++i) {
+ if(!colNames[i].isEmpty() && coll_->hasField(colNames[i])) {
+ newCols += colNames[i];
+ newWidths += colWidths[i];
+ } else {
+ removeCols += i;
+ }
+ }
+ colNames = newCols;
+ colWidths = newWidths;
+
+ qHeapSort(removeCols);
+ // now need to shift values in the order if any columns were removed
+ // only need to shift by number of "holes"
+ QValueList<int> newOrder;
+ for(QValueList<int>::ConstIterator it = colOrder.begin(); it != colOrder.end(); ++it) {
+ if(removeCols.findIndex(*it) == -1) {
+ int i = *it;
+ for(uint j = 0; j < removeCols.count() && removeCols[j] < i; ++j) {
+ --i;
+ }
+ newOrder += i;
+ }
+ }
+ colOrder = newOrder;
+
+ bool none = true;
+ Data::FieldVec fields = coll_->fields();
+ for(Data::FieldVec::Iterator fIt = fields.begin(); fIt != fields.end(); ++fIt) {
+ if(colNames.findIndex(fIt->name()) > -1 && colWidths.count() > 0) {
+ addField(fIt, colWidths.front());
+ if(none && colWidths.front() != 0) {
+ none = false;
+ }
+ colWidths.pop_front();
+ } else {
+ addField(fIt, 0);
+ }
+ }
+ if(none && columns() > 0 && !colNames.isEmpty()) {
+ showColumn(coll_->fieldNames().findIndex(colNames[0]));
+ }
+
+ QValueList<int>::ConstIterator it = colOrder.begin();
+ for(int i = 0; it != colOrder.end(); ++it) {
+ header()->moveSection(i++, *it);
+ }
+ slotUpdatePixmap();
+
+ int sortCol = config.readNumEntry("SortColumn" + configN, 0);
+ bool sortAsc = config.readBoolEntry("SortAscending" + configN, true);
+ setSorting(sortCol, sortAsc);
+ int prevSortCol = config.readNumEntry("PrevSortColumn" + configN, -1);
+ int prev2SortCol = config.readNumEntry("Prev2SortColumn" + configN, -1);
+ setPrevSortedColumn(prevSortCol, prev2SortCol);
+
+ triggerUpdate();
+ kapp->processEvents();
+ setUpdatesEnabled(false);
+
+ m_loadingCollection = true;
+ Data::EntryVec entries = coll_->entries();
+ for(Data::EntryVecIt entry = entries.begin(); entry != entries.end(); ++entry) {
+ addEntryInternal(entry);
+ }
+ m_loadingCollection = false;
+
+ setUpdatesEnabled(true);
+ triggerUpdate();
+}
+
+void DetailedListView::slotReset() {
+// myDebug() << "DetailedListView::slotReset()" << endl;
+ //clear() does not remove columns
+ clear();
+// while(columns() > 0) {
+// removeColumn(0);
+// }
+ m_filter = 0;
+}
+
+void DetailedListView::addEntries(Data::EntryVec entries_) {
+ if(entries_.isEmpty()) {
+ return;
+ }
+
+// myDebug() << "DetailedListView::addEntry() - " << entry_->title() << endl;
+
+ DetailedEntryItem* item = 0;
+ for(Data::EntryVecIt entry = entries_.begin(); entry != entries_.end(); ++entry) {
+ item = addEntryInternal(entry);
+ item->setState(DetailedEntryItem::New);
+ item->setVisible(!m_filter || m_filter->matches(entry.data()));
+ }
+
+ if(isUpdatesEnabled() && item && item->isVisible()) {
+ sort();
+ ensureItemVisible(item);
+ setCurrentItem(item);
+ if(!selectedItems().isEmpty()) {
+ blockSignals(true);
+ clearSelection();
+ setSelected(item, true);
+ blockSignals(false);
+ }
+ } else {
+ triggerUpdate();
+ }
+}
+
+Tellico::DetailedEntryItem* DetailedListView::addEntryInternal(Data::EntryPtr entry_) {
+ if(m_entryPix.isNull()) {
+ m_entryPix = UserIcon(entry_->collection()->typeName());
+ if(m_entryPix.isNull()) {
+ kdWarning() << "DetailedListView::addEntryInternal() - can't find entry pix" << endl;
+ }
+ }
+
+ DetailedEntryItem* item = new DetailedEntryItem(this, entry_);
+ populateItem(item);
+ return item;
+}
+
+void DetailedListView::modifyEntries(Data::EntryVec entries_) {
+ if(entries_.isEmpty()) {
+ return;
+ }
+
+ DetailedEntryItem* item = 0;
+ for(Data::EntryVecIt entry = entries_.begin(); entry != entries_.end(); ++entry) {
+ item = locateItem(entry.data());
+ if(!item) {
+ kdWarning() << "DetailedListView::modifyEntries() - no item found for " << entry->title() << endl;
+ continue;
+ }
+
+ populateItem(item);
+ item->setState(DetailedEntryItem::Modified);
+ item->setVisible(!m_filter || m_filter->matches(entry.data()));
+ }
+
+ if(isUpdatesEnabled() && item && item->isVisible()) {
+ sort();
+ }
+
+ if(item && !item->isSelected() && !selectedItems().isEmpty()) {
+ blockSignals(true);
+ clearSelection();
+ setSelected(item, true);
+ blockSignals(false);
+ }
+}
+
+void DetailedListView::removeEntries(Data::EntryVec entries_) {
+ if(entries_.isEmpty()) {
+ return;
+ }
+
+// myDebug() << "DetailedListView::removeEntries() - " << entry_->title() << endl;
+
+ for(Data::EntryVecIt entry = entries_.begin(); entry != entries_.end(); ++entry) {
+ delete locateItem(entry);
+ }
+ // update is required
+ triggerUpdate();
+}
+
+void DetailedListView::removeCollection(Data::CollPtr coll_) {
+ if(!coll_) {
+ kdWarning() << "DetailedListView::removeCollection() - null coll pointer!" << endl;
+ return;
+ }
+
+// myDebug() << "DetailedListView::removeCollection() - " << coll_->title() << endl;
+
+ clear();
+ while(columns() > 0) {
+ removeColumn(0);
+ }
+
+ m_headerMenu->clear();
+ m_headerMenu->insertTitle(i18n("View Columns"));
+
+ m_columnWidths.clear();
+ clearComparisons();
+ m_entryPix = QPixmap();
+
+ // clear the filter, too
+ m_filter = 0;
+}
+
+void DetailedListView::populateColumn(int col_) {
+ if(childCount() == 0) {
+ return;
+ }
+// myDebug() << "DetailedListView::populateColumn() - " << columnText(col_) << endl;
+ DetailedEntryItem* item = static_cast<DetailedEntryItem*>(firstChild());
+ Data::FieldPtr field = item->entry()->collection()->fieldByTitle(columnText(col_));
+ for( ; item; item = static_cast<DetailedEntryItem*>(item->nextSibling())) {
+ setPixmapAndText(item, col_, field);
+ }
+ m_isDirty[col_] = false;
+}
+
+void DetailedListView::populateItem(DetailedEntryItem* item_) {
+ Data::EntryPtr entry = item_->entry();
+ if(!entry) {
+ return;
+ }
+
+ for(int colNum = 0; colNum < columns(); ++colNum) {
+ if(columnWidth(colNum) > 0) {
+ Data::FieldPtr field = entry->collection()->fieldByTitle(columnText(colNum));
+ if(!field) {
+ kdWarning() << "DetailedListView::populateItem() - no field found for " << columnText(colNum) << endl;
+ continue;
+ }
+ setPixmapAndText(item_, colNum, field);
+ } else {
+ m_isDirty[colNum] = true;
+ }
+ }
+}
+
+void DetailedListView::contextMenuRequested(QListViewItem* item_, const QPoint& point_, int) {
+ if(!item_) {
+ return;
+ }
+ KPopupMenu menu(this);
+ Controller::self()->plugEntryActions(&menu);
+ menu.exec(point_);
+}
+
+// don't shadow QListView::setSelected
+void DetailedListView::setEntrySelected(Data::EntryPtr entry_) {
+// myDebug() << "DetailedListView::setEntrySelected()" << endl;
+ // if entry_ is null pointer, just return
+ if(!entry_) {
+ return;
+ }
+
+ DetailedEntryItem* item = locateItem(entry_);
+
+ blockSignals(true);
+ clearSelection();
+ setSelected(item, true);
+ setCurrentItem(item);
+ blockSignals(false);
+ ensureItemVisible(item);
+}
+
+Tellico::DetailedEntryItem* DetailedListView::locateItem(Data::EntryPtr entry_) {
+ for(QListViewItemIterator it(this); it.current(); ++it) {
+ DetailedEntryItem* item = static_cast<DetailedEntryItem*>(it.current());
+ if(item->entry() == entry_) {
+ return item;
+ }
+ }
+
+ return 0;
+}
+
+bool DetailedListView::eventFilter(QObject* obj_, QEvent* ev_) {
+ if(ev_->type() == QEvent::MouseButtonPress
+ && static_cast<QMouseEvent*>(ev_)->button() == Qt::RightButton
+ && obj_ == header()) {
+ m_headerMenu->popup(static_cast<QMouseEvent*>(ev_)->globalPos());
+ return true;
+ }
+ return GUI::ListView::eventFilter(obj_, ev_);
+}
+
+void DetailedListView::slotHeaderMenuActivated(int id_) {
+// myDebug() << "DetailedListView::slotHeaderMenuActivated() - " << m_headerMenu->text(id_) << endl;
+ bool checked = m_headerMenu->isItemChecked(id_);
+ checked = !checked; // toggle
+ m_headerMenu->setItemChecked(id_, checked);
+
+ int col = m_headerMenu->indexOf(id_) - 1; // subtract 1 because there's a title item
+
+ if(checked) { // add a column
+ showColumn(col);
+ } else {
+ hideColumn(col);
+ }
+ slotUpdatePixmap();
+}
+
+void DetailedListView::slotRefresh() {
+ if(childCount() == 0) {
+ return;
+ }
+
+ // the algorithm here is to iterate over each column, then over every list item
+ Data::CollPtr coll = static_cast<DetailedEntryItem*>(firstChild())->entry()->collection();
+ Data::FieldPtr field;
+ DetailedEntryItem* item;
+
+ for(int colNum = 0; colNum < columns(); ++colNum) {
+ field = coll->fieldByTitle(columnText(colNum));
+
+ // iterate over all items
+
+ for(QListViewItemIterator it(this); it.current(); ++it) {
+ item = static_cast<DetailedEntryItem*>(it.current());
+
+ setPixmapAndText(item, colNum, field);
+
+ // if we're doing this for the first time, go ahead and pass through filter
+ if(colNum == 0) {
+ if(m_filter && !m_filter->matches(item->entry())) {
+ item->setVisible(false);
+ } else {
+ item->setVisible(true);
+ }
+ }
+ }
+ }
+}
+
+void DetailedListView::slotRefreshImages() {
+ for(QValueVector<int>::const_iterator it = m_imageColumns.begin(); it != m_imageColumns.end(); ++it) {
+ if(columnWidth(*it) > 0) {
+ populateColumn(*it);
+ }
+ }
+}
+
+void DetailedListView::setPixmapAndText(DetailedEntryItem* item_, int col_, Data::FieldPtr field_) {
+ if(!item_ || !field_) {
+ return;
+ }
+
+ // if the bool is not empty, show the checkmark pixmap
+ if(field_->type() == Data::Field::Bool) {
+ const QString value = item_->entry()->field(field_);
+ item_->setPixmap(col_, value.isEmpty() ? QPixmap() : m_checkPix);
+ item_->setText(col_, QString::null);
+ } else if(field_->type() == Data::Field::Image) {
+ // if we're currently loading a collection
+ // don't load the image just yet, it'll get refreshed later
+ if(m_loadingCollection || columnWidth(col_) == 0) {
+ item_->setPixmap(col_, QPixmap());
+ item_->setText(col_, QString::null);
+ } else {
+ item_->setPixmap(col_, ImageFactory::pixmap(item_->entry()->field(field_), m_pixWidth, m_pixHeight));
+ item_->setText(col_, QString::null);
+ }
+ } else if(field_->type() == Data::Field::Rating) {
+ item_->setPixmap(col_, GUI::RatingWidget::pixmap(item_->entry()->field(field_)));
+ item_->setText(col_, QString::null);
+ } else { // for everything else, there's no pixmap, unless it's the first column
+ item_->setPixmap(col_, col_ == m_firstSection ? m_entryPix : QPixmap());
+ item_->setText(col_, item_->entry()->formattedField(field_));
+ }
+ item_->widthChanged(col_);
+}
+
+void DetailedListView::showColumn(int col_) {
+// myDebug() << "DetailedListView::showColumn() - " << columnText(col_) << endl;
+ int w = m_columnWidths[col_]; // this should be safe - all were initialized to 0
+ if(w == 0) {
+ setColumnWidthMode(col_, QListView::Maximum);
+ for(QListViewItemIterator it(this); it.current(); ++it) {
+ w = QMAX(it.current()->width(fontMetrics(), this, col_), w);
+ }
+ w = QMAX(w, MIN_COL_WIDTH);
+ } else {
+ setColumnWidthMode(col_, QListView::Manual);
+ }
+
+ setColumnWidth(col_, w);
+ if(m_isDirty[col_]) {
+ populateColumn(col_);
+ }
+ header()->setResizeEnabled(true, col_);
+ triggerUpdate();
+}
+
+void DetailedListView::hideColumn(int col_) {
+// myDebug() << "DetailedListView::hideColumn() - " << columnText(col_) << endl;
+ setColumnWidthMode(col_, QListView::Manual);
+ setColumnWidth(col_, 0);
+ header()->setResizeEnabled(false, col_);
+
+ // special case for images, I don't want all the items to be tall, so remove pixmaps
+ if(childCount() > 0) {
+ Data::EntryPtr entry = static_cast<DetailedEntryItem*>(firstChild())->entry();
+ if(entry) {
+ Data::FieldPtr field = entry->collection()->fieldByTitle(columnText(col_));
+ if(field && field->type() == Data::Field::Image) {
+ m_isDirty[col_] = true;
+ for(QListViewItemIterator it(this); it.current(); ++it) {
+ it.current()->setPixmap(col_, QPixmap());
+ }
+ }
+ }
+ }
+
+ triggerUpdate();
+}
+
+void DetailedListView::slotCacheColumnWidth(int section_, int oldSize_, int newSize_) {
+ // if the old size was 0, update the menu
+ if(oldSize_ == 0 && newSize_ > 0) {
+ m_headerMenu->setItemChecked(m_headerMenu->idAt(section_+1), true); // add 1 for title item
+ }
+
+ if(newSize_ > 0) {
+ m_columnWidths[section_] = newSize_;
+ }
+ setColumnWidthMode(section_, QListView::Manual);
+}
+
+void DetailedListView::setFilter(FilterPtr filter_) {
+ if(m_filter.data() != filter_) { // might just be updating
+ m_filter = filter_;
+ }
+// clearSelection();
+
+ int count = 0;
+ // iterate over all items
+ DetailedEntryItem* item;
+ for(QListViewItemIterator it(this); it.current(); ++it) {
+ item = static_cast<DetailedEntryItem*>(it.current());
+ if(m_filter && !m_filter->matches(item->entry())) {
+ item->setVisible(false);
+ setSelected(item, false);
+ } else {
+ item->setVisible(true);
+ ++count;
+ }
+ }
+ m_visibleItems = count;
+}
+
+void DetailedListView::addField(Data::CollPtr, Data::FieldPtr field) {
+ addField(field, 0); /* field is hidden by default */
+}
+
+void DetailedListView::addField(Data::FieldPtr field_, int width_) {
+// myDebug() << "DetailedListView::addField() - " << field_->title() << endl;
+ int col = addColumn(field_->title());
+
+ // Bools, images, and numbers should be centered
+ if(field_->type() == Data::Field::Bool
+ || field_->type() == Data::Field::Number
+ || field_->type() == Data::Field::Image) {
+ setColumnAlignment(col, Qt::AlignHCenter | Qt::AlignVCenter);
+ if(field_->type() == Data::Field::Image) {
+ m_imageColumns.push_back(col);
+ }
+ } else {
+ setColumnAlignment(col, Qt::AlignLeft | Qt::AlignVCenter);
+ }
+
+ // width might be -1, which means set the width to maximum
+ // but m_columnWidths is the cached width, so just set it to 0
+ m_columnWidths.push_back(QMAX(width_, 0));
+
+ m_isDirty.push_back(true);
+
+ int id = m_headerMenu->insertItem(field_->title());
+ if(width_ == 0) {
+ m_headerMenu->setItemChecked(id, false);
+ hideColumn(col);
+ } else {
+ m_headerMenu->setItemChecked(id, true);
+ showColumn(col);
+ }
+ setComparison(col, ListViewComparison::create(field_));
+ resetComparisons();
+}
+
+void DetailedListView::modifyField(Tellico::Data::CollPtr, Data::FieldPtr oldField_, Data::FieldPtr newField_) {
+ int sec; // I need it for after the loop
+ for(sec = 0; sec < columns(); ++sec) {
+ if(header()->label(sec) == oldField_->title()) {
+ break;
+ }
+ }
+
+ // I thought this would have to be mapped to index, but not the case
+ setColumnText(sec, newField_->title());
+ if(newField_->type() == Data::Field::Bool
+ || newField_->type() == Data::Field::Number
+ || newField_->type() == Data::Field::Image) {
+ setColumnAlignment(sec, Qt::AlignHCenter | Qt::AlignVCenter);
+ if(oldField_->type() == Data::Field::Image) {
+ QValueVector<int>::iterator it = qFind(m_imageColumns.begin(), m_imageColumns.end(), sec);
+ if(it != m_imageColumns.end()) {
+ m_imageColumns.erase(it);
+ }
+ }
+ if(newField_->type() == Data::Field::Image) {
+ m_imageColumns.push_back(sec);
+ }
+ } else {
+ setColumnAlignment(sec, Qt::AlignLeft | Qt::AlignVCenter);
+ }
+ m_headerMenu->changeItem(m_headerMenu->idAt(sec+1), newField_->title()); // add 1 since menu has title
+ setComparison(sec, ListViewComparison::create(newField_));
+ resetComparisons();
+}
+
+void DetailedListView::removeField(Tellico::Data::CollPtr, Data::FieldPtr field_) {
+// myDebug() << "DetailedListView::removeField() - " << field_->name() << endl;
+
+ int sec; // I need it for after the loop
+ for(sec = 0; sec < columns(); ++sec) {
+ if(header()->label(sec) == field_->title()) {
+// myDebug() << "Removing section " << sec << endl;
+ break;
+ }
+ }
+
+ if(sec == columns()) {
+ kdWarning() << "DetailedListView::removeField() - no column named " << field_->title() << endl;
+ return;
+ }
+
+ m_headerMenu->removeItem(m_headerMenu->idAt(sec+1)); // add 1 since menu has title
+
+ m_columnWidths.erase(&m_columnWidths[sec]);
+ m_isDirty.erase(&m_isDirty[sec]);
+
+ // I thought this would have to be mapped to index, but not the case
+ removeComparison(sec); // must be before removeColumn();
+ removeColumn(sec);
+
+ // sometimes resizeEnabled gets messed up
+ for(int i = sec; i < columns(); ++i) {
+ header()->setResizeEnabled(columnWidth(i) > 0, header()->mapToSection(i));
+ }
+ resetComparisons();
+ slotUpdatePixmap();
+ triggerUpdate();
+}
+
+void DetailedListView::reorderFields(const Data::FieldVec& fields_) {
+// myDebug() << "DetailedListView::reorderFields()" << endl;
+ // find the first out of place field
+ int sec = 0;
+ Data::FieldVec::ConstIterator it = fields_.begin();
+ for(sec = 0; it != fields_.end() && sec < columns(); ++sec, ++it) {
+ if(header()->label(sec) != it->title()) {
+ break;
+ }
+ }
+
+ QStringList visible = visibleColumns();
+ for( ; it != fields_.end() && sec < columns(); ++sec, ++it) {
+ header()->setLabel(sec, it->title());
+ bool isVisible = (visible.findIndex(it->title()) > -1);
+ m_headerMenu->changeItem(m_headerMenu->idAt(sec+1), it->title());
+ m_headerMenu->setItemChecked(m_headerMenu->idAt(sec+1), isVisible);
+ m_columnWidths[sec] = 0;
+ if(it->type() == Data::Field::Bool
+ || it->type() == Data::Field::Number
+ || it->type() == Data::Field::Image) {
+ setColumnAlignment(sec, Qt::AlignHCenter | Qt::AlignVCenter);
+ } else {
+ setColumnAlignment(sec, Qt::AlignLeft | Qt::AlignVCenter);
+ }
+
+ if(isVisible) {
+ showColumn(sec);
+ } else {
+ hideColumn(sec);
+ }
+ }
+
+ slotRefresh();
+ slotUpdatePixmap();
+ triggerUpdate();
+}
+
+int DetailedListView::prevSortedColumn() const {
+ return m_prevSortColumn;
+}
+
+int DetailedListView::prev2SortedColumn() const {
+ return m_prev2SortColumn;
+}
+
+void DetailedListView::setPrevSortedColumn(int prev1_, int prev2_) {
+ m_prevSortColumn = prev1_;
+ m_prev2SortColumn = prev2_;
+}
+
+void DetailedListView::setSorting(int column_, bool ascending_/*=true*/) {
+// DEBUG_BLOCK;
+ if(column_ != columnSorted()) {
+ m_prev2SortColumn = m_prevSortColumn;
+ m_prevSortColumn = columnSorted();
+ }
+ GUI::ListView::setSorting(column_, ascending_);
+}
+
+void DetailedListView::updateFirstSection() {
+ for(int numCol = 0; numCol < columns(); ++numCol) {
+ if(columnWidth(header()->mapToSection(numCol)) > 0) {
+ m_firstSection = header()->mapToSection(numCol);
+ break;
+ }
+ }
+}
+
+void DetailedListView::slotUpdatePixmap() {
+ int oldSection = m_firstSection;
+ updateFirstSection();
+ if(childCount() == 0 || oldSection == m_firstSection) {
+ return;
+ }
+
+ Data::EntryPtr entry = static_cast<DetailedEntryItem*>(firstChild())->entry();
+ if(!entry) {
+ return;
+ }
+
+ Data::FieldPtr field1 = entry->collection()->fieldByTitle(columnText(oldSection));
+ Data::FieldPtr field2 = entry->collection()->fieldByTitle(columnText(m_firstSection));
+ if(!field1 || !field2) {
+ kdWarning() << "DetailedListView::slotUpdatePixmap() - no field found." << endl;
+ return;
+ }
+
+ for(QListViewItemIterator it(this); it.current(); ++it) {
+ setPixmapAndText(static_cast<DetailedEntryItem*>(it.current()), oldSection, field1);
+ setPixmapAndText(static_cast<DetailedEntryItem*>(it.current()), m_firstSection, field2);
+ }
+}
+
+void DetailedListView::saveConfig(Tellico::Data::CollPtr coll_, int configIndex_) {
+ KConfigGroup config(kapp->config(), QString::fromLatin1("Options - %1").arg(coll_->typeName()));
+
+ // all of this is to have custom settings on a per file basis
+ QString configN;
+ if(coll_->type() == Data::Collection::Base) {
+ QValueList<ConfigInfo> info;
+ for(uint i = 0; i < Config::maxCustomURLSettings(); ++i) {
+ KURL u = config.readEntry(QString::fromLatin1("URL_%1").arg(i));
+ if(!u.isEmpty() && static_cast<int>(i) != configIndex_) {
+ configN = QString::fromLatin1("_%1").arg(i);
+ ConfigInfo ci;
+ ci.cols = config.readListEntry("ColumnNames" + configN);
+ ci.widths = config.readIntListEntry("ColumnWidths" + configN);
+ ci.order = config.readIntListEntry("ColumnOrder" + configN);
+ ci.colSorted = config.readNumEntry("SortColumn" + configN);
+ ci.ascSort = config.readBoolEntry("SortAscending" + configN);
+ ci.prevSort = config.readNumEntry("PrevSortColumn" + configN);
+ ci.prev2Sort = config.readNumEntry("Prev2SortColumn" + configN);
+ info.append(ci);
+ }
+ }
+ // subtract one since we're writing the current settings, too
+ uint limit = QMIN(info.count(), Config::maxCustomURLSettings()-1);
+ for(uint i = 0; i < limit; ++i) {
+ // starts at one since the current config will be written below
+ configN = QString::fromLatin1("_%1").arg(i+1);
+ config.writeEntry("ColumnNames" + configN, info[i].cols);
+ config.writeEntry("ColumnWidths" + configN, info[i].widths);
+ config.writeEntry("ColumnOrder" + configN, info[i].order);
+ config.writeEntry("SortColumn" + configN, info[i].colSorted);
+ config.writeEntry("SortAscending" + configN, info[i].ascSort);
+ config.writeEntry("PrevSortColumn" + configN, info[i].prevSort);
+ config.writeEntry("Prev2SortColumn" + configN, info[i].prev2Sort);
+ }
+ configN = QString::fromLatin1("_0");
+ }
+
+ QValueList<int> widths, order;
+ for(int i = 0; i < columns(); ++i) {
+ if(columnWidthMode(i) == QListView::Manual) {
+ widths += columnWidth(i);
+ } else {
+ widths += -1; // Maximum width mode
+ }
+ order += header()->mapToIndex(i);
+ }
+
+ config.writeEntry("ColumnWidths" + configN, widths);
+ config.writeEntry("ColumnOrder" + configN, order);
+ config.writeEntry("SortColumn" + configN, columnSorted());
+ config.writeEntry("SortAscending" + configN, ascendingSort());
+ config.writeEntry("PrevSortColumn" + configN, prevSortedColumn());
+ config.writeEntry("Prev2SortColumn" + configN, prev2SortedColumn());
+
+ QStringList colNames;
+ for(int col = 0; col < columns(); ++col) {
+ colNames += coll_->fieldNameByTitle(columnText(col));
+ }
+ config.writeEntry("ColumnNames" + configN, colNames);
+}
+
+QString DetailedListView::sortColumnTitle1() const {
+ return columnSorted() == -1 ? QString::null : header()->label(columnSorted());
+}
+
+QString DetailedListView::sortColumnTitle2() const {
+ return prevSortedColumn() == -1 ? QString::null : header()->label(prevSortedColumn());
+}
+
+QString DetailedListView::sortColumnTitle3() const {
+ return prev2SortedColumn() == -1 ? QString::null : header()->label(prev2SortedColumn());
+}
+
+QStringList DetailedListView::visibleColumns() const {
+ QStringList titles;
+ for(int i = 0; i < columns(); ++i) {
+ if(columnWidth(header()->mapToSection(i)) > 0) {
+ titles << columnText(header()->mapToSection(i));
+ }
+ }
+ return titles;
+}
+
+// can't be const
+Tellico::Data::EntryVec DetailedListView::visibleEntries() {
+ // We could just return the full collection entry list if the filter is 0
+ // but printing depends on the sorted order
+ Data::EntryVec entries;
+ for(QListViewItemIterator it(this); it.current(); ++it) {
+ if(it.current()->isVisible()) {
+ entries.append(static_cast<DetailedEntryItem*>(it.current())->entry());
+ }
+ }
+ return entries;
+}
+
+void DetailedListView::selectAllVisible() {
+ blockSignals(true);
+ for(QListViewItemIterator it(this); it.current(); ++it) {
+ if(it.current()->isVisible()) {
+ setSelected(it.current(), true);
+ }
+ }
+ blockSignals(false);
+ // FIXME: not right with MultiSelectionListView
+ slotSelectionChanged();
+}
+
+void DetailedListView::resetEntryStatus() {
+ for(QListViewItemIterator it(this); it.current(); ++it) {
+ static_cast<DetailedEntryItem*>(it.current())->setState(DetailedEntryItem::Normal);
+ }
+ triggerUpdate();
+}
+
+int DetailedListView::compare(int col_, const GUI::ListViewItem* item1_, GUI::ListViewItem* item2_, bool asc_) {
+ DetailedEntryItem* item2 = static_cast<DetailedEntryItem*>(item2_);
+ int res = 0;
+ return (res = compareColumn(col_, item1_, item2, asc_)) != 0 ? res :
+ (res = compareColumn(m_prevSortColumn, item1_, item2, asc_)) != 0 ? res :
+ (res = compareColumn(m_prev2SortColumn, item1_, item2, asc_)) != 0 ? res : 0;
+}
+
+int DetailedListView::compareColumn(int col, const GUI::ListViewItem* item1, GUI::ListViewItem* item2, bool asc) {
+ return GUI::ListView::compare(col, item1, item2, asc);
+}
+
+void DetailedListView::resetComparisons() {
+ // this is only allowed when the view is not empty, so we can grab a collection ptr
+ if(childCount() == 0) {
+ return;
+ }
+ Data::CollPtr coll = static_cast<DetailedEntryItem*>(firstChild())->entry()->collection();
+ if(!coll) {
+ return;
+ }
+ for(int i = 0; i < columns(); ++i) {
+ Data::FieldPtr f = coll->fieldByTitle(header()->label(i));
+ if(f) {
+ setComparison(i, ListViewComparison::create(f));
+ }
+ }
+}
+
+#include "detailedlistview.moc"