File indexing completed on 2024-05-12 16:34:42
0001 /* This file is part of the Calligra project 0002 * Copyright (C) 2010-2014 Yue Liu <yue.liu@mail.com> 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Library General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2 of the License, or (at your option) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Library General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Library General Public License 0015 * along with this library; see the file COPYING.LIB. If not, write to 0016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "CollectionTreeWidget.h" 0021 0022 #include "StencilListView.h" 0023 #include "CollectionItemModel.h" 0024 #include "StencilBoxDebug.h" 0025 0026 #include <klocalizedstring.h> 0027 #include <ksharedconfig.h> 0028 #include <kconfiggroup.h> 0029 0030 #include <QTreeWidgetItem> 0031 #include <QApplication> 0032 #include <QContextMenuEvent> 0033 #include <QAction> 0034 #include <QActionGroup> 0035 #include <QMenu> 0036 #include <QHeaderView> 0037 #include <QSortFilterProxyModel> 0038 #include <QPainter> 0039 0040 SheetDelegate::SheetDelegate(QTreeView* view, QWidget* parent) 0041 : QItemDelegate(parent), 0042 m_view(view) 0043 { 0044 } 0045 0046 // style comes from qt designer 0047 // https://qt.gitorious.org/qt/qttools/source/src/designer/src/lib/shared/sheet_delegate.cpp 0048 void SheetDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const 0049 { 0050 const QAbstractItemModel* model = index.model(); 0051 Q_ASSERT(model); 0052 0053 if (!model->parent(index).isValid()) { 0054 // this is a top-level item. 0055 QStyleOptionButton buttonOption; 0056 0057 buttonOption.state = option.state; 0058 #ifdef Q_OS_MAC 0059 buttonOption.state |= QStyle::State_Raised; 0060 #endif 0061 buttonOption.state &= ~QStyle::State_HasFocus; 0062 0063 buttonOption.rect = option.rect; 0064 buttonOption.palette = option.palette; 0065 buttonOption.features = QStyleOptionButton::None; 0066 0067 painter->save(); 0068 QColor buttonColor(230, 230, 230); 0069 QBrush buttonBrush = option.palette.button(); 0070 if (!buttonBrush.gradient() && buttonBrush.texture().isNull()) 0071 buttonColor = buttonBrush.color(); 0072 QColor outlineColor = buttonColor.darker(150); 0073 QColor highlightColor = buttonColor.lighter(130); 0074 0075 // Only draw topline if the previous item is expanded 0076 QModelIndex previousIndex = model->index(index.row() - 1, index.column()); 0077 bool drawTopline = (index.row() > 0 && m_view->isExpanded(previousIndex)); 0078 int highlightOffset = drawTopline ? 1 : 0; 0079 0080 QLinearGradient gradient(option.rect.topLeft(), option.rect.bottomLeft()); 0081 gradient.setColorAt(0, buttonColor.lighter(102)); 0082 gradient.setColorAt(1, buttonColor.darker(106)); 0083 0084 painter->setPen(Qt::NoPen); 0085 painter->setBrush(gradient); 0086 painter->drawRect(option.rect); 0087 painter->setPen(QPen(highlightColor, 0)); 0088 painter->drawLine(option.rect.topLeft() + QPoint(0, highlightOffset), 0089 option.rect.topRight() + QPoint(0, highlightOffset)); 0090 painter->setPen(QPen(outlineColor, 0)); 0091 if (drawTopline) 0092 painter->drawLine(option.rect.topLeft(), option.rect.topRight()); 0093 painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight()); 0094 painter->restore(); 0095 0096 QStyleOption branchOption; 0097 static const int i = 9; // ### hardcoded in qcommonstyle.cpp 0098 QRect r = option.rect; 0099 branchOption.rect = QRect(r.left() + i / 2, r.top() + (r.height() - i) / 2, i, i); 0100 branchOption.palette = option.palette; 0101 branchOption.state = QStyle::State_Children; 0102 0103 if (m_view->isExpanded(index)) 0104 branchOption.state |= QStyle::State_Open; 0105 0106 m_view->style()->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, painter, m_view); 0107 0108 // draw text 0109 QRect textrect = QRect(r.left() + i * 2, r.top(), r.width() - ((5 * i) / 2), r.height()); 0110 QString text = elidedText(option.fontMetrics, textrect.width(), Qt::ElideMiddle, 0111 model->data(index, Qt::DisplayRole).toString()); 0112 m_view->style()->drawItemText(painter, textrect, Qt::AlignCenter, 0113 option.palette, m_view->isEnabled(), text); 0114 0115 } else { 0116 QItemDelegate::paint(painter, option, index); 0117 } 0118 } 0119 0120 QSize SheetDelegate::sizeHint(const QStyleOptionViewItem& opt, const QModelIndex& index) const 0121 { 0122 QSize sz = QItemDelegate::sizeHint(opt, index) + QSize(2, 2); 0123 return sz; 0124 } 0125 0126 0127 CollectionTreeWidget::CollectionTreeWidget(QWidget* parent): QTreeWidget(parent) 0128 { 0129 header()->hide(); 0130 header()->setResizeMode(QHeaderView::Stretch); 0131 setRootIsDecorated(false); 0132 setItemsExpandable(true); 0133 setFocusPolicy(Qt::NoFocus); 0134 setIndentation(0); 0135 setColumnCount(1); 0136 setVerticalScrollMode(ScrollPerPixel); 0137 setAcceptDrops(true); 0138 setItemDelegate(new SheetDelegate(this, this)); 0139 0140 connect(this, SIGNAL(itemPressed(QTreeWidgetItem*,int)), 0141 this, SLOT(handleMousePress(QTreeWidgetItem*))); 0142 0143 loadOptions(); 0144 } 0145 0146 CollectionTreeWidget::~CollectionTreeWidget() 0147 { 0148 saveOptions(); 0149 } 0150 0151 void CollectionTreeWidget::setFamilyMap(QMap<QString, CollectionItemModel*> map) 0152 { 0153 m_familyMap = map; 0154 } 0155 0156 void CollectionTreeWidget::regenerateFilteredMap() 0157 { 0158 QMapIterator<QString, CollectionItemModel*> i(m_familyMap); 0159 while (i.hasNext()) { 0160 i.next(); 0161 i.value()->setViewMode(m_viewMode); 0162 QSortFilterProxyModel* proxy = new QSortFilterProxyModel(); 0163 proxy->setSourceModel(i.value()); 0164 m_filteredMap.insert(i.key(), proxy); 0165 } 0166 0167 //regenerate category view 0168 QMapIterator<QString, QSortFilterProxyModel*> j(m_filteredMap); 0169 while (j.hasNext()) { 0170 j.next(); 0171 QTreeWidgetItem* category = new QTreeWidgetItem(this); 0172 category->setText(0, j.key()); 0173 addStencilListView(category, m_viewMode, j.value()); 0174 } 0175 } 0176 0177 //Link a StencilListView to each TreeWidgetItem 0178 void CollectionTreeWidget::addStencilListView(QTreeWidgetItem* parent, 0179 QListView::ViewMode viewMode, QSortFilterProxyModel* model) 0180 { 0181 QTreeWidgetItem* embed_item = new QTreeWidgetItem(parent); 0182 embed_item->setFlags(Qt::ItemIsEnabled); 0183 StencilListView* categoryView = new StencilListView(); 0184 categoryView->setViewMode(viewMode); 0185 categoryView->setModel(model); 0186 setItemWidget(embed_item, 0, categoryView); 0187 } 0188 0189 StencilListView* CollectionTreeWidget::stencilListViewAt(int idx) const 0190 { 0191 StencilListView* rc = 0; 0192 if (QTreeWidgetItem* cat_item = topLevelItem(idx)) { 0193 if (QTreeWidgetItem* embedItem = cat_item->child(0)) { 0194 rc = qobject_cast<StencilListView*>(itemWidget(embedItem, 0)); 0195 } 0196 } 0197 Q_ASSERT(rc); 0198 return rc; 0199 } 0200 0201 void CollectionTreeWidget::saveOptions() 0202 { 0203 KConfigGroup group = KSharedConfig::openConfig()->group("Stencil Box"); 0204 group.writeEntry("viewMode", (int)m_viewMode); 0205 } 0206 0207 void CollectionTreeWidget::loadOptions() 0208 { 0209 KConfigGroup group = KSharedConfig::openConfig()->group("Stencil Box"); 0210 int viewMode = group.readEntry("viewMode", (int)QListView::IconMode); 0211 m_viewMode = (QListView::ViewMode)viewMode; 0212 updateViewMode(); 0213 } 0214 0215 void CollectionTreeWidget::handleMousePress(QTreeWidgetItem* item) 0216 { 0217 if (item && !item->parent() && 0218 QApplication::mouseButtons() == Qt::LeftButton) 0219 setItemExpanded(item, !isItemExpanded(item)); 0220 } 0221 0222 void CollectionTreeWidget::slotListMode() 0223 { 0224 m_viewMode = QListView::ListMode; 0225 updateViewMode(); 0226 } 0227 0228 void CollectionTreeWidget::slotIconMode() 0229 { 0230 m_viewMode = QListView::IconMode; 0231 updateViewMode(); 0232 } 0233 0234 void CollectionTreeWidget::updateViewMode() 0235 { 0236 QMapIterator<QString, CollectionItemModel*> i(m_familyMap); 0237 while (i.hasNext()) { 0238 i.next(); 0239 i.value()->setViewMode(m_viewMode); 0240 } 0241 if (const int numTopLevels = topLevelItemCount()) { 0242 for (int i = numTopLevels - 1; i >= 0; --i) { 0243 StencilListView* categoryView = stencilListViewAt(i); 0244 0245 if (m_viewMode != categoryView->viewMode()) { 0246 categoryView->setViewMode(m_viewMode); 0247 categoryView->setMovement(QListView::Static); 0248 categoryView->setDragDropMode(QAbstractItemView::DragDrop); 0249 adjustStencilListSize(topLevelItem(i)); 0250 } 0251 } 0252 } 0253 updateGeometries(); 0254 } 0255 0256 void CollectionTreeWidget::adjustStencilListSize(QTreeWidgetItem* cat_item) 0257 { 0258 QTreeWidgetItem* embedItem = cat_item->child(0); 0259 if (embedItem == 0) 0260 return; 0261 0262 StencilListView* list_widget = static_cast<StencilListView*>(itemWidget(embedItem, 0)); 0263 list_widget->setFixedWidth(header()->width()); 0264 list_widget->doItemsLayout(); 0265 const int height = qMax(list_widget->contentsSize().height() , 1); 0266 list_widget->setFixedHeight(height); 0267 embedItem->setSizeHint(0, QSize(-1, height - 1)); 0268 } 0269 0270 void CollectionTreeWidget::setFilter(QRegExp regExp) 0271 { 0272 QMapIterator<QString, QSortFilterProxyModel*> j(m_filteredMap); 0273 while (j.hasNext()) { 0274 j.next(); 0275 j.value()->setFilterRegExp(regExp); 0276 j.value()->setFilterRole(Qt::UserRole + 1); 0277 } 0278 for (int i = 0; i < topLevelItemCount(); i++) { 0279 QTreeWidgetItem* tl = topLevelItem(i); 0280 StencilListView* categoryView = stencilListViewAt(i); 0281 QAbstractItemModel* model = categoryView->model(); 0282 const bool categoryEnabled = model->rowCount() > 0; 0283 if (categoryView->model()->rowCount() > 0) { 0284 categoryView->adjustSize(); 0285 adjustStencilListSize(tl); 0286 } 0287 setRowHidden(i, QModelIndex(), !categoryEnabled); 0288 } 0289 updateGeometries(); 0290 } 0291 0292 void CollectionTreeWidget::resizeEvent(QResizeEvent* e) 0293 { 0294 QTreeWidget::resizeEvent(e); 0295 if (const int numTopLevels = topLevelItemCount()) { 0296 for (int i = numTopLevels - 1; i >= 0; --i) { 0297 adjustStencilListSize(topLevelItem(i)); 0298 } 0299 } 0300 } 0301 0302 void CollectionTreeWidget::contextMenuEvent(QContextMenuEvent* e) 0303 { 0304 QMenu menu; 0305 menu.addAction(i18n("Expand all"), this, SLOT(expandAll())); 0306 menu.addAction(i18n("Collapse all"), this, SLOT(collapseAll())); 0307 menu.addSeparator(); 0308 0309 QAction* listModeAction = menu.addAction(i18n("List View")); 0310 QAction* iconModeAction = menu.addAction(i18n("Icon View")); 0311 listModeAction->setCheckable(true); 0312 iconModeAction->setCheckable(true); 0313 QActionGroup* viewModeGroup = new QActionGroup(&menu); 0314 viewModeGroup->addAction(listModeAction); 0315 viewModeGroup->addAction(iconModeAction); 0316 if (m_viewMode == QListView::IconMode) { 0317 iconModeAction->setChecked(true); 0318 } else { 0319 listModeAction->setChecked(true); 0320 } 0321 connect(listModeAction, SIGNAL(triggered()), SLOT(slotListMode())); 0322 connect(iconModeAction, SIGNAL(triggered()), SLOT(slotIconMode())); 0323 0324 e->accept(); 0325 menu.exec(mapToGlobal(e->pos())); 0326 }