/* * Copyright (C) 2007, 2008, 2009, 2010 Ivan Cukic * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser/Library General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser/Library General Public License for more details * * You should have received a copy of the GNU Lesser/Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "MergedActionListModel.h" namespace Lancelot { class MergedActionListModel::Private { public: void toChildCoordinates(int index, int & model, int & modelIndex) const; void fromChildCoordinates(int & index, int model, int modelIndex) const; QList < ActionListModel * > models; QList < QPair < QString, QIcon > > modelsMetadata; bool hideEmptyModels : 1; bool showModelTitles : 1; }; MergedActionListModel::MergedActionListModel() : d(new Private) { d->hideEmptyModels = true; d->showModelTitles = true; } MergedActionListModel::~MergedActionListModel() { delete d; } void MergedActionListModel::modelUpdated() { emit updated(); } void MergedActionListModel::modelItemInserted(int modelIndex) { if (!sender()) return; ActionListModel * m = (ActionListModel *)sender(); int model = d->models.indexOf(m); if (model == -1) return; int index; d->fromChildCoordinates(index, model, modelIndex); if (d->hideEmptyModels && m->size() == 1) { modelUpdated(); } else { emit itemInserted(index); } } void MergedActionListModel::modelItemDeleted(int modelIndex) { if (!sender()) return; ActionListModel * m = (ActionListModel *)sender(); int model = d->models.indexOf(m); if (model == -1) return; int index; d->fromChildCoordinates(index, model, modelIndex); if (d->hideEmptyModels && m->size() == 0) { modelUpdated(); } else { emit itemDeleted(index); } } void MergedActionListModel::modelItemAltered(int modelIndex) { if (!sender()) return; int model = d->models.indexOf((ActionListModel *)sender()); if (model == -1) return; int index; d->fromChildCoordinates(index, model, modelIndex); emit itemAltered(index); } QString MergedActionListModel::description(int index) const { int model, modelIndex; d->toChildCoordinates(index, model, modelIndex); if (model == -1 || modelIndex == -1) return ""; return d->models.at(model)->description(modelIndex); } QIcon MergedActionListModel::icon(int index) const { int model, modelIndex; d->toChildCoordinates(index, model, modelIndex); if (model == -1) return QIcon(); if (modelIndex == -1) return d->modelsMetadata.at(model).second; return d->models.at(model)->icon(modelIndex); } QMimeData * MergedActionListModel::mimeData(int index) const { int model, modelIndex; d->toChildCoordinates(index, model, modelIndex); if (model == -1) return NULL; if (modelIndex == -1) return modelMimeData(model); return d->models.at(model)->mimeData(modelIndex); } void MergedActionListModel::dataDragFinished(int index, Qt::DropAction action) { int model, modelIndex; d->toChildCoordinates(index, model, modelIndex); d->showModelTitles = true; if (model == -1) return; if (modelIndex == -1) return modelDataDropped(model, action); return d->models.at(model)->dataDragFinished(modelIndex, action); } void MergedActionListModel::modelDataDropped(int index, Qt::DropAction action) { Q_UNUSED(index); Q_UNUSED(action); } void MergedActionListModel::setDropActions(int index, Qt::DropActions & actions, Qt::DropAction & defaultAction) { int model, modelIndex; d->toChildCoordinates(index, model, modelIndex); if (model == -1) return; if (modelIndex == -1) return setModelDropActions(model, actions, defaultAction); return d->models.at(model)->setDropActions(modelIndex, actions, defaultAction); } void MergedActionListModel::setModelDropActions(int index, Qt::DropActions & actions, Qt::DropAction & defaultAction) { Q_UNUSED(index); actions = Qt::IgnoreAction; defaultAction = Qt::IgnoreAction; } QMimeData * MergedActionListModel::modelMimeData(int index) const { Q_UNUSED(index); return NULL; } bool MergedActionListModel::dataDropAvailable(int where, const QMimeData * mimeData) { int model, modelIndex; d->toChildCoordinates(where, model, modelIndex); if (model == -1) return false; if (modelIndex == -1) return false; return d->models.at(model)->dataDropAvailable(modelIndex, mimeData); } void MergedActionListModel::dataDropped(int where, const QMimeData * mimeData) { int model, modelIndex; d->toChildCoordinates(where, model, modelIndex); if (model == -1) return; if (modelIndex == -1) return; return d->models.at(model)->dataDropped(modelIndex, mimeData); } bool MergedActionListModel::hasModelContextActions(int index) const { Q_UNUSED(index); return false; } void MergedActionListModel::setModelContextActions(int index, Lancelot::PopupMenu * menu) { Q_UNUSED(index); Q_UNUSED(menu); // do nothing } void MergedActionListModel::modelContextActivate(int index, QAction * context) { Q_UNUSED(index); Q_UNUSED(context); // do nothing } bool MergedActionListModel::isCategory(int index) const { int model, modelIndex; d->toChildCoordinates(index, model, modelIndex); if (model == -1) return false; if (model != -1 && modelIndex == -1) return true; return d->models.at(model)->isCategory(modelIndex); } void MergedActionListModel::activate(int index) { int model, modelIndex; d->toChildCoordinates(index, model, modelIndex); if (model == -1 || modelIndex == -1) return; d->models.at(model)->activated(modelIndex); } QString MergedActionListModel::title(int index) const { int model, modelIndex; d->toChildCoordinates(index, model, modelIndex); if (model == -1) return "Error"; if (modelIndex == -1) return d->modelsMetadata.at(model).first; return d->models.at(model)->title(modelIndex); } bool MergedActionListModel::hasContextActions(int index) const { int model, modelIndex; d->toChildCoordinates(index, model, modelIndex); if (model == -1) return false; if (modelIndex == -1) return hasModelContextActions(model); return d->models.at(model)->hasContextActions(modelIndex); } void MergedActionListModel::setContextActions(int index, Lancelot::PopupMenu * menu) { int model, modelIndex; d->toChildCoordinates(index, model, modelIndex); if (model == -1) return; if (modelIndex == -1) return setModelContextActions(model, menu); d->models.at(model)->setContextActions(modelIndex, menu); } void MergedActionListModel::contextActivate(int index, QAction * context) { int model, modelIndex; d->toChildCoordinates(index, model, modelIndex); if (model == -1) return; if (modelIndex == -1) return modelContextActivate(model, context); d->models.at(model)->contextActivate(modelIndex, context); } #define TITLE_OFFSET (showModelTitles ? 1 : 0) void MergedActionListModel::Private::toChildCoordinates(int index, int & model, int & modelIndex) const { model = 0; modelIndex = 0; foreach (ActionListModel * m, models) { if (!hideEmptyModels || m->size() != 0) { if (index < m->size() + TITLE_OFFSET) { modelIndex = index - TITLE_OFFSET; return; } else { index -= m->size() + TITLE_OFFSET; ++model; } } else { ++model; } } model = -1; modelIndex = -1; } void MergedActionListModel::Private::fromChildCoordinates(int & index, int model, int modelIndex) const { index = -1; if (model >= models.size()) return; if (modelIndex >= models.at(model)->size()) return; index = 0; foreach (ActionListModel * m, models) { if (!hideEmptyModels || m->size() != 0) { if (model > 0) { index += m->size() + 1;//TITLE_OFFSET; } else { index += modelIndex + 1;//TITLE_OFFSET; return; } } --model; } index = -1; } #undef TITLE_OFFSET void MergedActionListModel::addModel(ActionListModel * model) { addModel(model->selfIcon(), model->selfTitle(), model); } void MergedActionListModel::addModel(QIcon icon, const QString & title, ActionListModel * model) { if (!model) return; d->models.append(model); d->modelsMetadata.append(QPair< QString, QIcon >(title, icon)); connect(model, SIGNAL(updated()), this, SLOT(modelUpdated())); connect(model, SIGNAL(itemInserted(int)), this, SLOT(modelItemInserted(int))); connect(model, SIGNAL(itemDeleted(int)), this, SLOT(modelItemDeleted(int))); connect(model, SIGNAL(itemAltered(int)), this, SLOT(modelItemAltered(int))); if (d->hideEmptyModels && model->size() == 0) return; // We will not show empty models emit updated(); } ActionListModel * MergedActionListModel::modelAt(int index) { return d->models.at(index); } void MergedActionListModel::removeModel(int index) { if (index < 0 || index >= d->models.size()) { return; } ActionListModel * model = d->models.takeAt(index); d->modelsMetadata.removeAt(index); model->disconnect(this); emit updated(); } int MergedActionListModel::modelCount() const { return d->models.size(); } int MergedActionListModel::size() const { int result = 0; foreach (ActionListModel * model, d->models) { if (d->hideEmptyModels && model->size() == 0) continue; // We will not show empty models result += model->size() + (d->showModelTitles ? 1 : 0); } return result; } bool MergedActionListModel::hideEmptyModels() const { return d->hideEmptyModels; } void MergedActionListModel::setHideEmptyModels(bool hide) { if (d->hideEmptyModels == hide) return; d->hideEmptyModels = hide; emit updated(); } bool MergedActionListModel::showModelTitles() const { return d->showModelTitles; } void MergedActionListModel::setShowModelTitles(bool show) { if (d->showModelTitles == show) return; d->showModelTitles = show; emit updated(); } } // namespace Lancelot #include "moc_MergedActionListModel.cpp"