00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kalarm.h"
00022
00023 #include <QApplication>
00024 #include <QToolTip>
00025 #include <QMouseEvent>
00026 #include <QKeyEvent>
00027 #include <QHelpEvent>
00028 #include <QTextLayout>
00029 #include <QTextLine>
00030
00031 #include <klocale.h>
00032 #include <kmessagebox.h>
00033 #include <kdebug.h>
00034
00035 #include "preferences.h"
00036 #include "resourcemodelview.moc"
00037
00038
00039 ResourceModel* ResourceModel::mInstance = 0;
00040
00041
00042 ResourceModel* ResourceModel::instance(QObject* parent)
00043 {
00044 if (!mInstance)
00045 mInstance = new ResourceModel(parent);
00046 return mInstance;
00047 }
00048
00049 ResourceModel::ResourceModel(QObject* parent)
00050 : QAbstractListModel(parent)
00051 {
00052 refresh();
00053 AlarmResources* resources = AlarmResources::instance();
00054 connect(resources, SIGNAL(signalResourceModified(AlarmResource*)), SLOT(updateResource(AlarmResource*)));
00055 connect(resources, SIGNAL(standardResourceChange(AlarmResource::Type)), SLOT(slotStandardChanged(AlarmResource::Type)));
00056 connect(resources, SIGNAL(resourceStatusChanged(AlarmResource*, AlarmResources::Change)), SLOT(slotStatusChanged(AlarmResource*, AlarmResources::Change)));
00057 connect(resources, SIGNAL(resourceLoaded(AlarmResource*, bool)), SLOT(slotLoaded(AlarmResource*, bool)));
00058 }
00059
00060 int ResourceModel::rowCount(const QModelIndex& parent) const
00061 {
00062 if (parent.isValid())
00063 return 0;
00064 return mResources.count();
00065 }
00066
00067 QModelIndex ResourceModel::index(int row, int column, const QModelIndex& parent) const
00068 {
00069 if (parent.isValid() || row >= mResources.count())
00070 return QModelIndex();
00071 return createIndex(row, column, mResources[row]);
00072 }
00073
00074 QVariant ResourceModel::data(const QModelIndex& index, int role) const
00075 {
00076 if (!index.isValid())
00077 return QVariant();
00078 AlarmResource* resource = static_cast<AlarmResource*>(index.internalPointer());
00079 if (!resource)
00080 return QVariant();
00081 switch (role)
00082 {
00083 case Qt::DisplayRole:
00084 return resource->resourceName();
00085 case Qt::CheckStateRole:
00086 return resource->isEnabled() ? Qt::Checked : Qt::Unchecked;
00087 case Qt::DecorationRole:
00088 if (!resource->colour().isValid())
00089 return QApplication::palette().color(QPalette::Base);
00090 return resource->colour();
00091 case Qt::ForegroundRole:
00092 switch (resource->alarmType())
00093 {
00094 case AlarmResource::ACTIVE: return resource->readOnly() ? Qt::darkGray : Qt::black;
00095 case AlarmResource::ARCHIVED: return resource->readOnly() ? Qt::green : Qt::darkGreen;
00096 case AlarmResource::TEMPLATE: return resource->readOnly() ? Qt::blue : Qt::darkBlue;
00097 default: break;
00098 }
00099 break;
00100 case Qt::FontRole:
00101 {
00102 if (!resource->isEnabled() || !resource->standardResource())
00103 break;
00104 QFont font = mFont;
00105 font.setBold(true);
00106 return font;
00107 }
00108 case Qt::ToolTipRole:
00109 {
00110 QString name = '@' + resource->resourceName();
00111 QString type = '@' + resource->displayType();
00112 bool inactive = !resource->isActive();
00113 QString disabled = i18nc("@info/plain", "Disabled");
00114 QString readonly = i18nc("@info/plain", "Read-only");
00115 if (inactive && resource->readOnly())
00116 return i18nc("@info:tooltip",
00117 "%1"
00118 "<nl/>%2: <filename>%3</filename>"
00119 "<nl/>%4, %5",
00120 name, type, resource->displayLocation(), disabled, readonly);
00121 if (inactive || resource->readOnly())
00122 return i18nc("@info:tooltip",
00123 "%1"
00124 "<nl/>%2: <filename>%3</filename>"
00125 "<nl/>%4",
00126 name, type, resource->displayLocation(),
00127 (inactive ? disabled : readonly));
00128 return i18nc("@info:tooltip",
00129 "%1"
00130 "<nl/>%2: <filename>%3</filename>",
00131 name, type, resource->displayLocation());
00132 }
00133 default:
00134 break;
00135 }
00136 return QVariant();
00137 }
00138
00139
00140
00141
00142
00143 bool ResourceModel::setData(const QModelIndex& index, const QVariant& value, int role)
00144 {
00145 mErrorPrompt.clear();
00146 if (role == Qt::FontRole)
00147 {
00148
00149
00150 mFont = value.value<QFont>();
00151 return true;
00152 }
00153 if (role != Qt::CheckStateRole || !index.isValid())
00154 return false;
00155 AlarmResource* resource = static_cast<AlarmResource*>(index.internalPointer());
00156 if (!resource)
00157 return false;
00158 Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
00159 bool active = (state == Qt::Checked);
00160 bool saveChange = false;
00161 AlarmResources* resources = AlarmResources::instance();
00162 if (active)
00163 {
00164
00165 resource->setActive(true);
00166 saveChange = resources->load(resource);
00167 resource->setActive(false);
00168 }
00169 else
00170 {
00171
00172 saveChange = resource->saveAndClose();
00173 }
00174 if (saveChange)
00175 resource->setEnabled(active);
00176 emit dataChanged(index, index);
00177 return true;
00178 }
00179
00180 Qt::ItemFlags ResourceModel::flags(const QModelIndex&) const
00181 {
00182 return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
00183 }
00184
00185
00186
00187
00188 AlarmResource* ResourceModel::resource(const QModelIndex& index) const
00189 {
00190 if (!index.isValid())
00191 return 0;
00192 return static_cast<AlarmResource*>(index.internalPointer());
00193 }
00194
00195
00196
00197
00198 void ResourceModel::notifyChange(const QModelIndex& index)
00199 {
00200 if (index.isValid())
00201 emit dataChanged(index, index);
00202 }
00203
00204
00205
00206
00207 void ResourceModel::refresh()
00208 {
00209
00210 if (!mResources.isEmpty())
00211 {
00212 beginRemoveRows(QModelIndex(), 0, mResources.count() - 1);
00213 mResources.clear();
00214 endRemoveRows();
00215 }
00216 QList<AlarmResource*> newResources;
00217 AlarmResourceManager* manager = AlarmResources::instance()->resourceManager();
00218 for (AlarmResourceManager::Iterator it = manager->begin(); it != manager->end(); ++it)
00219 newResources += *it;
00220 if (!newResources.isEmpty())
00221 {
00222 beginInsertRows(QModelIndex(), 0, newResources.count() - 1);
00223 mResources = newResources;
00224 endInsertRows();
00225 }
00226 }
00227
00228
00229
00230
00231 void ResourceModel::addResource(AlarmResource* resource)
00232 {
00233 int row = mResources.count();
00234 beginInsertRows(QModelIndex(), row, row);
00235 mResources += resource;
00236 endInsertRows();
00237 }
00238
00239
00240
00241
00242 void ResourceModel::removeResource(AlarmResource* resource)
00243 {
00244 int row = mResources.indexOf(resource);
00245 if (row >= 0)
00246 {
00247 beginRemoveRows(QModelIndex(), row, row);
00248 mResources.removeAt(row);
00249 endRemoveRows();
00250 }
00251 }
00252
00253
00254
00255
00256
00257 void ResourceModel::updateResource(AlarmResource* resource)
00258 {
00259 int row = mResources.indexOf(resource);
00260 if (row >= 0)
00261 {
00262 QModelIndex ix = index(row, 0, QModelIndex());
00263 emit dataChanged(ix, ix);
00264 }
00265 }
00266
00267
00268
00269
00270 void ResourceModel::slotStandardChanged(AlarmResource::Type type)
00271 {
00272 for (int row = 0, end = mResources.count(); row < end; ++row)
00273 {
00274 if (mResources[row]->alarmType() == type)
00275 {
00276 QModelIndex ix = index(row, 0, QModelIndex());
00277 emit dataChanged(ix, ix);
00278 }
00279 }
00280 }
00281
00282
00283
00284
00285
00286 void ResourceModel::slotLoaded(AlarmResource* resource, bool active)
00287 {
00288 if (active)
00289 updateResource(resource);
00290 }
00291
00292
00293
00294
00295 void ResourceModel::slotStatusChanged(AlarmResource* resource, AlarmResources::Change change)
00296 {
00297 switch (change)
00298 {
00299 case AlarmResources::Added:
00300 addResource(resource);
00301 break;
00302 case AlarmResources::Enabled:
00303 case AlarmResources::ReadOnly:
00304 case AlarmResources::Colour:
00305 updateResource(resource);
00306 break;
00307 default:
00308 break;
00309 }
00310 }
00311
00312
00313
00314
00315
00316
00317
00318 ResourceFilterModel::ResourceFilterModel(QAbstractItemModel* baseModel, QObject* parent)
00319 : QSortFilterProxyModel(parent),
00320 mResourceType(AlarmResource::INVALID)
00321 {
00322 setSourceModel(baseModel);
00323 }
00324
00325 void ResourceFilterModel::setFilter(AlarmResource::Type type)
00326 {
00327 if (type != mResourceType)
00328 {
00329 mResourceType = type;
00330 filterChanged();
00331 }
00332 }
00333
00334 bool ResourceFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex&) const
00335 {
00336 return static_cast<ResourceModel*>(sourceModel())->resource(sourceModel()->index(sourceRow, 0))->alarmType() == mResourceType;
00337 }
00338
00339
00340
00341
00342 AlarmResource* ResourceFilterModel::resource(int row) const
00343 {
00344 return static_cast<ResourceModel*>(sourceModel())->resource(mapToSource(index(row, 0)));
00345 }
00346
00347 AlarmResource* ResourceFilterModel::resource(const QModelIndex& index) const
00348 {
00349 return static_cast<ResourceModel*>(sourceModel())->resource(mapToSource(index));
00350 }
00351
00352
00353
00354
00355 void ResourceFilterModel::notifyChange(int row)
00356 {
00357 static_cast<ResourceModel*>(sourceModel())->notifyChange(mapToSource(index(row, 0)));
00358 }
00359
00360 void ResourceFilterModel::notifyChange(const QModelIndex& index)
00361 {
00362 static_cast<ResourceModel*>(sourceModel())->notifyChange(mapToSource(index));
00363 }
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374 bool ResourceDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index)
00375 {
00376 if (!(model->flags(index) & Qt::ItemIsEnabled))
00377 return false;
00378 if (event->type() == QEvent::MouseButtonRelease
00379 || event->type() == QEvent::MouseButtonDblClick)
00380 {
00381 const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
00382 QRect checkRect = QStyle::alignedRect(option.direction, Qt::AlignLeft | Qt::AlignVCenter,
00383 check(option, option.rect, Qt::Checked).size(),
00384 QRect(option.rect.x() + textMargin, option.rect.y(), option.rect.width(), option.rect.height()));
00385 if (!checkRect.contains(static_cast<QMouseEvent*>(event)->pos()))
00386 return false;
00387 if (event->type() == QEvent::MouseButtonDblClick)
00388 return true;
00389 }
00390 else if (event->type() == QEvent::KeyPress)
00391 {
00392 if (static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space
00393 && static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select)
00394 return false;
00395 }
00396 else
00397 return false;
00398
00399 QVariant value = index.data(Qt::CheckStateRole);
00400 if (!value.isValid())
00401 return false;
00402 Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked ? Qt::Unchecked : Qt::Checked);
00403 if (state == Qt::Unchecked)
00404 {
00405
00406
00407 AlarmResource* resource = static_cast<ResourceFilterModel*>(model)->resource(index);
00408 if (!resource)
00409 return false;
00410 if (resource->standardResource())
00411 {
00412
00413 if (resource->alarmType() == AlarmResource::ACTIVE)
00414 {
00415 KMessageBox::sorry(static_cast<QWidget*>(parent()),
00416 i18nc("@info", "You cannot disable your default active alarm resource."));
00417 return false;
00418
00419 }
00420 if (resource->alarmType() == AlarmResource::ARCHIVED && Preferences::archivedKeepDays())
00421 {
00422
00423
00424 KMessageBox::sorry(static_cast<QWidget*>(parent()),
00425 i18nc("@info", "You cannot disable your default archived alarm resource "
00426 "while expired alarms are configured to be kept."));
00427 return false;
00428 }
00429 if (KMessageBox::warningContinueCancel(static_cast<QWidget*>(parent()),
00430 i18nc("@info", "Do you really want to disable your default resource?"))
00431 == KMessageBox::Cancel)
00432 return false;
00433 }
00434 }
00435 return model->setData(index, state, Qt::CheckStateRole);
00436 }
00437
00438
00439
00440
00441
00442
00443
00444 void ResourceView::setModel(QAbstractItemModel* model)
00445 {
00446 model->setData(QModelIndex(), viewOptions().font, Qt::FontRole);
00447 QListView::setModel(model);
00448 }
00449
00450
00451
00452
00453 AlarmResource* ResourceView::resource(int row) const
00454 {
00455 return static_cast<ResourceFilterModel*>(model())->resource(row);
00456 }
00457
00458 AlarmResource* ResourceView::resource(const QModelIndex& index) const
00459 {
00460 return static_cast<ResourceFilterModel*>(model())->resource(index);
00461 }
00462
00463
00464
00465
00466 void ResourceView::notifyChange(int row) const
00467 {
00468 static_cast<ResourceFilterModel*>(model())->notifyChange(row);
00469 }
00470
00471 void ResourceView::notifyChange(const QModelIndex& index) const
00472 {
00473 static_cast<ResourceFilterModel*>(model())->notifyChange(index);
00474 }
00475
00476
00477
00478
00479
00480 void ResourceView::mouseReleaseEvent(QMouseEvent* e)
00481 {
00482 if (!indexAt(e->pos()).isValid())
00483 clearSelection();
00484 QListView::mouseReleaseEvent(e);
00485 }
00486
00487
00488
00489
00490 bool ResourceView::viewportEvent(QEvent* e)
00491 {
00492 if (e->type() == QEvent::ToolTip && isActiveWindow())
00493 {
00494 QHelpEvent* he = static_cast<QHelpEvent*>(e);
00495 QModelIndex index = indexAt(he->pos());
00496 QVariant value = model()->data(index, Qt::ToolTipRole);
00497 if (qVariantCanConvert<QString>(value))
00498 {
00499 QString toolTip = value.toString();
00500 int i = toolTip.indexOf('@');
00501 if (i > 0)
00502 {
00503 int j = toolTip.indexOf(QRegExp("<(nl|br)", Qt::CaseInsensitive), i + 1);
00504 int k = toolTip.indexOf('@', j);
00505 QString name = toolTip.mid(i + 1, j - i - 1);
00506 value = model()->data(index, Qt::FontRole);
00507 QFontMetrics fm(qvariant_cast<QFont>(value).resolve(viewOptions().font));
00508 int textWidth = fm.boundingRect(name).width() + 1;
00509 const int margin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
00510 QStyleOptionButton opt;
00511 opt.QStyleOption::operator=(viewOptions());
00512 opt.rect = rectForIndex(index);
00513 int checkWidth = QApplication::style()->subElementRect(QStyle::SE_ViewItemCheckIndicator, &opt).width();
00514 int left = spacing() + 3*margin + checkWidth + viewOptions().decorationSize.width();
00515 int right = left + textWidth;
00516 if (left >= horizontalOffset() + spacing()
00517 && right <= horizontalOffset() + width() - spacing() - 2*frameWidth())
00518 {
00519
00520
00521 if (k > 0)
00522 toolTip.remove(i, k + 1 - i);
00523 }
00524 else
00525 {
00526 toolTip.remove(k, 1);
00527 toolTip.remove(i, 1);
00528 }
00529 }
00530 QToolTip::showText(he->globalPos(), toolTip, this);
00531 return true;
00532 }
00533 }
00534 return QListView::viewportEvent(e);
00535 }