mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-23 18:32:51 +00:00
969 lines
33 KiB
C++
969 lines
33 KiB
C++
/*
|
|
* eventlistmodel.cpp - model class for lists of alarms or templates
|
|
* Program: kalarm
|
|
* Copyright © 2007-2012 by David Jarvie <djarvie@kde.org>
|
|
*
|
|
* 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.
|
|
*
|
|
* 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU 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 "kalarm.h"
|
|
|
|
#include "resources/alarmresource.h"
|
|
#include "resources/alarmresources.h"
|
|
#include "alarmcalendar.h"
|
|
#include "alarmtime.h"
|
|
#include "preferences.h"
|
|
#include "synchtimer.h"
|
|
#include "eventlistmodel.moc"
|
|
|
|
#include <kalarmcal/alarmtext.h>
|
|
|
|
#include <klocale.h>
|
|
#include <kiconloader.h>
|
|
#include <kdebug.h>
|
|
|
|
#include <QPixmap>
|
|
|
|
/*=============================================================================
|
|
= Class: EventListModel
|
|
= Contains all active/archived alarms, or all alarm templates, unsorted.
|
|
=============================================================================*/
|
|
|
|
EventListModel* EventListModel::mAlarmInstance = 0;
|
|
EventListModel* EventListModel::mTemplateInstance = 0;
|
|
QPixmap* EventListModel::mTextIcon = 0;
|
|
QPixmap* EventListModel::mFileIcon = 0;
|
|
QPixmap* EventListModel::mCommandIcon = 0;
|
|
QPixmap* EventListModel::mEmailIcon = 0;
|
|
QPixmap* EventListModel::mAudioIcon = 0;
|
|
QSize EventListModel::mIconSize;
|
|
int EventListModel::mTimeHourPos = -2;
|
|
|
|
|
|
EventListModel* EventListModel::alarms()
|
|
{
|
|
if (!mAlarmInstance)
|
|
{
|
|
mAlarmInstance = new EventListModel(CalEvent::ACTIVE | CalEvent::ARCHIVED);
|
|
Preferences::connect(SIGNAL(archivedColourChanged(QColor)), mAlarmInstance, SLOT(slotUpdateArchivedColour(QColor)));
|
|
Preferences::connect(SIGNAL(disabledColourChanged(QColor)), mAlarmInstance, SLOT(slotUpdateDisabledColour(QColor)));
|
|
Preferences::connect(SIGNAL(holidaysChanged(KHolidays::HolidayRegion)), mAlarmInstance, SLOT(slotUpdateHolidays()));
|
|
Preferences::connect(SIGNAL(workTimeChanged(QTime,QTime,QBitArray)), mAlarmInstance, SLOT(slotUpdateWorkingHours()));
|
|
}
|
|
return mAlarmInstance;
|
|
}
|
|
|
|
EventListModel* EventListModel::templates()
|
|
{
|
|
if (!mTemplateInstance)
|
|
mTemplateInstance = new EventListModel(CalEvent::TEMPLATE);
|
|
return mTemplateInstance;
|
|
}
|
|
|
|
EventListModel::~EventListModel()
|
|
{
|
|
if (this == mAlarmInstance)
|
|
mAlarmInstance = 0;
|
|
else if (this == mTemplateInstance)
|
|
mTemplateInstance = 0;
|
|
}
|
|
|
|
EventListModel::EventListModel(CalEvent::Types status, QObject* parent)
|
|
: QAbstractTableModel(parent),
|
|
mStatus(status)
|
|
{
|
|
// Load the current list of alarms.
|
|
// The list will be updated whenever a signal is received notifying changes.
|
|
// We need to store the list so that when deletions occur, the deleted alarm's
|
|
// position in the list can be determined.
|
|
mEvents = AlarmCalendar::resources()->events(mStatus);
|
|
mHaveEvents = !mEvents.isEmpty();
|
|
//for(int x=0; x<mEvents.count(); ++x)kDebug(0)<<"Resource"<<(void*)mEvents[x]->resource()<<"Event"<<(void*)mEvents[x];
|
|
if (!mTextIcon)
|
|
{
|
|
mTextIcon = new QPixmap(SmallIcon("dialog-information"));
|
|
mFileIcon = new QPixmap(SmallIcon("document-open"));
|
|
mCommandIcon = new QPixmap(SmallIcon("system-run"));
|
|
mEmailIcon = new QPixmap(SmallIcon("mail-message-unread"));
|
|
mAudioIcon = new QPixmap(SmallIcon("audio-x-generic"));
|
|
mIconSize = mTextIcon->size().expandedTo(mFileIcon->size()).expandedTo(mCommandIcon->size()).expandedTo(mEmailIcon->size()).expandedTo(mAudioIcon->size());
|
|
}
|
|
MinuteTimer::connect(this, SLOT(slotUpdateTimeTo()));
|
|
AlarmResources* resources = AlarmResources::instance();
|
|
connect(resources, SIGNAL(resourceStatusChanged(AlarmResource*,AlarmResources::Change)),
|
|
SLOT(slotResourceStatusChanged(AlarmResource*,AlarmResources::Change)));
|
|
connect(resources, SIGNAL(resourceLoaded(AlarmResource*,bool)),
|
|
SLOT(slotResourceLoaded(AlarmResource*,bool)));
|
|
}
|
|
|
|
int EventListModel::rowCount(const QModelIndex& parent) const
|
|
{
|
|
if (parent.isValid())
|
|
return 0;
|
|
return mEvents.count();
|
|
}
|
|
|
|
int EventListModel::columnCount(const QModelIndex& parent) const
|
|
{
|
|
if (parent.isValid())
|
|
return 0;
|
|
return ColumnCount;
|
|
}
|
|
|
|
QModelIndex EventListModel::index(int row, int column, const QModelIndex& parent) const
|
|
{
|
|
if (parent.isValid() || row >= mEvents.count())
|
|
return QModelIndex();
|
|
return createIndex(row, column, mEvents[row]);
|
|
}
|
|
|
|
QVariant EventListModel::data(const QModelIndex& index, int role) const
|
|
{
|
|
int column = index.column();
|
|
if (role == Qt::WhatsThisRole)
|
|
return whatsThisText(column);
|
|
KAEvent* event = static_cast<KAEvent*>(index.internalPointer());
|
|
if (!event)
|
|
return QVariant();
|
|
bool resourceColour = false;
|
|
switch (column)
|
|
{
|
|
case TimeColumn:
|
|
switch (role)
|
|
{
|
|
case Qt::BackgroundRole:
|
|
resourceColour = true;
|
|
break;
|
|
case Qt::DisplayRole:
|
|
{
|
|
DateTime due = event->expired() ? event->startDateTime() : event->nextTrigger(KAEvent::DISPLAY_TRIGGER);
|
|
return AlarmTime::alarmTimeText(due);
|
|
}
|
|
case SortRole:
|
|
{
|
|
DateTime due = event->expired() ? event->startDateTime() : event->nextTrigger(KAEvent::DISPLAY_TRIGGER);
|
|
return due.isValid() ? due.effectiveKDateTime().toUtc().dateTime()
|
|
: QDateTime(QDate(9999,12,31), QTime(0,0,0));
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case TimeToColumn:
|
|
switch (role)
|
|
{
|
|
case Qt::BackgroundRole:
|
|
resourceColour = true;
|
|
break;
|
|
case Qt::DisplayRole:
|
|
if (event->expired())
|
|
return QString();
|
|
return AlarmTime::timeToAlarmText(event->nextTrigger(KAEvent::DISPLAY_TRIGGER));
|
|
case SortRole:
|
|
{
|
|
if (event->expired())
|
|
return -1;
|
|
KDateTime now = KDateTime::currentUtcDateTime();
|
|
DateTime due = event->nextTrigger(KAEvent::DISPLAY_TRIGGER);
|
|
if (due.isDateOnly())
|
|
return now.date().daysTo(due.date()) * 1440;
|
|
return (now.secsTo(due.effectiveKDateTime()) + 59) / 60;
|
|
}
|
|
}
|
|
break;
|
|
case RepeatColumn:
|
|
switch (role)
|
|
{
|
|
case Qt::BackgroundRole:
|
|
resourceColour = true;
|
|
break;
|
|
case Qt::DisplayRole:
|
|
return repeatText(event);
|
|
case Qt::TextAlignmentRole:
|
|
return Qt::AlignHCenter;
|
|
case SortRole:
|
|
return repeatOrder(event);
|
|
}
|
|
break;
|
|
case ColourColumn:
|
|
switch (role)
|
|
{
|
|
case Qt::BackgroundRole:
|
|
switch (event->actionTypes())
|
|
{
|
|
case KAEvent::ACT_DISPLAY_COMMAND:
|
|
case KAEvent::ACT_DISPLAY:
|
|
return event->bgColour();
|
|
case KAEvent::ACT_COMMAND:
|
|
if (event->commandError() != KAEvent::CMD_NO_ERROR)
|
|
return Qt::red;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case Qt::ForegroundRole:
|
|
if (event->commandError() != KAEvent::CMD_NO_ERROR)
|
|
{
|
|
if (event->actionTypes() == KAEvent::ACT_COMMAND)
|
|
return Qt::white;
|
|
QColor colour = Qt::red;
|
|
int r, g, b;
|
|
event->bgColour().getRgb(&r, &g, &b);
|
|
if (r > 128 && g <= 128 && b <= 128)
|
|
colour = Qt::white;
|
|
return colour;
|
|
}
|
|
break;
|
|
case Qt::DisplayRole:
|
|
if (event->commandError() != KAEvent::CMD_NO_ERROR)
|
|
return QString::fromLatin1("!");
|
|
break;
|
|
case SortRole:
|
|
{
|
|
unsigned i = (event->actionTypes() == KAEvent::ACT_DISPLAY)
|
|
? event->bgColour().rgb() : 0;
|
|
return QString("%1").arg(i, 6, 10, QLatin1Char('0'));
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case TypeColumn:
|
|
switch (role)
|
|
{
|
|
case Qt::DecorationRole:
|
|
{
|
|
QVariant v;
|
|
v.setValue(*eventIcon(event));
|
|
return v;
|
|
}
|
|
case Qt::TextAlignmentRole:
|
|
return Qt::AlignHCenter;
|
|
case Qt::SizeHintRole:
|
|
return mIconSize;
|
|
case Qt::AccessibleTextRole:
|
|
#ifdef __GNUC__
|
|
#warning Implement this
|
|
#endif
|
|
return QString();
|
|
case ValueRole:
|
|
return static_cast<int>(event->actionSubType());
|
|
case SortRole:
|
|
return QString("%1").arg(event->actionSubType(), 2, 10, QLatin1Char('0'));
|
|
}
|
|
break;
|
|
case TextColumn:
|
|
switch (role)
|
|
{
|
|
case Qt::BackgroundRole:
|
|
resourceColour = true;
|
|
break;
|
|
case Qt::DisplayRole:
|
|
case SortRole:
|
|
return AlarmText::summary(*event, 1);
|
|
case Qt::ToolTipRole:
|
|
return AlarmText::summary(*event, 10);
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case TemplateNameColumn:
|
|
switch (role)
|
|
{
|
|
case Qt::BackgroundRole:
|
|
resourceColour = true;
|
|
break;
|
|
case Qt::DisplayRole:
|
|
return event->templateName();
|
|
case SortRole:
|
|
return event->templateName().toUpper();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (role)
|
|
{
|
|
case Qt::ForegroundRole:
|
|
if (!event->enabled())
|
|
return Preferences::disabledColour();
|
|
if (event->expired())
|
|
return Preferences::archivedColour();
|
|
break; // use the default for normal active alarms
|
|
case Qt::ToolTipRole:
|
|
// Show the last command execution error message
|
|
switch (event->commandError())
|
|
{
|
|
case KAEvent::CMD_ERROR:
|
|
return i18nc("@info:tooltip", "Command execution failed");
|
|
case KAEvent::CMD_ERROR_PRE:
|
|
return i18nc("@info:tooltip", "Pre-alarm action execution failed");
|
|
case KAEvent::CMD_ERROR_POST:
|
|
return i18nc("@info:tooltip", "Post-alarm action execution failed");
|
|
case KAEvent::CMD_ERROR_PRE_POST:
|
|
return i18nc("@info:tooltip", "Pre- and post-alarm action execution failed");
|
|
default:
|
|
case KAEvent::CMD_NO_ERROR:
|
|
break;
|
|
}
|
|
break;
|
|
case StatusRole:
|
|
return event->category();
|
|
case EnabledRole:
|
|
return event->enabled();
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (resourceColour)
|
|
{
|
|
AlarmResource* resource = AlarmResources::instance()->resourceForIncidence(event->id());
|
|
if (resource && resource->colour().isValid())
|
|
return resource->colour();
|
|
}
|
|
return QVariant();
|
|
}
|
|
|
|
bool EventListModel::setData(const QModelIndex& ix, const QVariant&, int role)
|
|
{
|
|
if (ix.isValid() && role == Qt::EditRole)
|
|
{
|
|
int row = ix.row();
|
|
emit dataChanged(index(row, 0), index(row, ColumnCount - 1));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
QVariant EventListModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
if (orientation == Qt::Horizontal)
|
|
{
|
|
if (role == Qt::DisplayRole)
|
|
{
|
|
switch (section)
|
|
{
|
|
case TimeColumn:
|
|
return i18nc("@title:column", "Time");
|
|
case TimeToColumn:
|
|
return i18nc("@title:column", "Time To");
|
|
case RepeatColumn:
|
|
return i18nc("@title:column", "Repeat");
|
|
case ColourColumn:
|
|
return QString();
|
|
case TypeColumn:
|
|
return QString();
|
|
case TextColumn:
|
|
return i18nc("@title:column", "Message, File or Command");
|
|
case TemplateNameColumn:
|
|
return i18nc("@title:column Template name", "Name");
|
|
}
|
|
}
|
|
else if (role == Qt::WhatsThisRole)
|
|
return whatsThisText(section);
|
|
}
|
|
return QVariant();
|
|
}
|
|
|
|
Qt::ItemFlags EventListModel::flags(const QModelIndex& index) const
|
|
{
|
|
if (!index.isValid())
|
|
return Qt::ItemIsEnabled;
|
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Signal every minute that the time-to-alarm values have changed.
|
|
*/
|
|
void EventListModel::slotUpdateTimeTo()
|
|
{
|
|
int n = mEvents.count();
|
|
if (n > 0)
|
|
emit dataChanged(index(0, TimeToColumn), index(n - 1, TimeToColumn));
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Called when the colour used to display archived alarms has changed.
|
|
*/
|
|
void EventListModel::slotUpdateArchivedColour(const QColor&)
|
|
{
|
|
kDebug();
|
|
int firstRow = -1;
|
|
for (int row = 0, end = mEvents.count(); row < end; ++row)
|
|
{
|
|
if (mEvents[row]->category() == CalEvent::ARCHIVED)
|
|
{
|
|
// For efficiency, emit a single signal for each group
|
|
// of consecutive archived alarms, rather than a separate
|
|
// signal for each alarm.
|
|
if (firstRow < 0)
|
|
firstRow = row;
|
|
}
|
|
else if (firstRow >= 0)
|
|
{
|
|
emit dataChanged(index(firstRow, 0), index(row - 1, ColumnCount - 1));
|
|
firstRow = -1;
|
|
}
|
|
}
|
|
if (firstRow >= 0)
|
|
emit dataChanged(index(firstRow, 0), index(mEvents.count() - 1, ColumnCount - 1));
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Called when the colour used to display disabled alarms has changed.
|
|
*/
|
|
void EventListModel::slotUpdateDisabledColour(const QColor&)
|
|
{
|
|
kDebug();
|
|
int firstRow = -1;
|
|
for (int row = 0, end = mEvents.count(); row < end; ++row)
|
|
{
|
|
if (!mEvents[row]->enabled())
|
|
{
|
|
// For efficiency, emit a single signal for each group
|
|
// of consecutive disabled alarms, rather than a separate
|
|
// signal for each alarm.
|
|
if (firstRow < 0)
|
|
firstRow = row;
|
|
}
|
|
else if (firstRow >= 0)
|
|
{
|
|
emit dataChanged(index(firstRow, 0), index(row - 1, ColumnCount - 1));
|
|
firstRow = -1;
|
|
}
|
|
}
|
|
if (firstRow >= 0)
|
|
emit dataChanged(index(firstRow, 0), index(mEvents.count() - 1, ColumnCount - 1));
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Called when the definition of holidays has changed.
|
|
* Update the next trigger time for all alarms which are set to recur only on
|
|
* non-holidays.
|
|
*/
|
|
void EventListModel::slotUpdateHolidays()
|
|
{
|
|
kDebug();
|
|
int firstRow = -1;
|
|
for (int row = 0, end = mEvents.count(); row < end; ++row)
|
|
{
|
|
if (mEvents[row]->holidaysExcluded())
|
|
{
|
|
// For efficiency, emit a single signal for each group
|
|
// of consecutive alarms to update, rather than a separate
|
|
// signal for each alarm.
|
|
if (firstRow < 0)
|
|
firstRow = row;
|
|
}
|
|
else if (firstRow >= 0)
|
|
{
|
|
emit dataChanged(index(firstRow, TimeColumn), index(row - 1, TimeColumn));
|
|
emit dataChanged(index(firstRow, TimeToColumn), index(row - 1, TimeToColumn));
|
|
firstRow = -1;
|
|
}
|
|
}
|
|
if (firstRow >= 0)
|
|
{
|
|
emit dataChanged(index(firstRow, TimeColumn), index(mEvents.count() - 1, TimeColumn));
|
|
emit dataChanged(index(firstRow, TimeToColumn), index(mEvents.count() - 1, TimeToColumn));
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Called when the definition of working hours has changed.
|
|
* Update the next trigger time for all alarms which are set to recur only
|
|
* during working hours.
|
|
*/
|
|
void EventListModel::slotUpdateWorkingHours()
|
|
{
|
|
kDebug();
|
|
int firstRow = -1;
|
|
for (int row = 0, end = mEvents.count(); row < end; ++row)
|
|
{
|
|
if (mEvents[row]->workTimeOnly())
|
|
{
|
|
// For efficiency, emit a single signal for each group
|
|
// of consecutive alarms to update, rather than a separate
|
|
// signal for each alarm.
|
|
if (firstRow < 0)
|
|
firstRow = row;
|
|
}
|
|
else if (firstRow >= 0)
|
|
{
|
|
emit dataChanged(index(firstRow, TimeColumn), index(row - 1, TimeColumn));
|
|
emit dataChanged(index(firstRow, TimeToColumn), index(row - 1, TimeToColumn));
|
|
firstRow = -1;
|
|
}
|
|
}
|
|
if (firstRow >= 0)
|
|
{
|
|
emit dataChanged(index(firstRow, TimeColumn), index(mEvents.count() - 1, TimeColumn));
|
|
emit dataChanged(index(firstRow, TimeToColumn), index(mEvents.count() - 1, TimeToColumn));
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Called when the command error status of an alarm has changed.
|
|
* Update the visual command error indication.
|
|
*/
|
|
void EventListModel::updateCommandError(const QString& eventId)
|
|
{
|
|
int row = findEvent(eventId);
|
|
if (row >= 0)
|
|
{
|
|
QModelIndex ix = index(row, ColourColumn);
|
|
emit dataChanged(ix, ix);
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Called when loading of a resource is complete.
|
|
*/
|
|
void EventListModel::slotResourceLoaded(AlarmResource* resource, bool active)
|
|
{
|
|
if (active)
|
|
slotResourceStatusChanged(resource, AlarmResources::Added);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Static method called when a resource status has changed.
|
|
*/
|
|
void EventListModel::resourceStatusChanged(AlarmResource* resource, AlarmResources::Change change)
|
|
{
|
|
if (mAlarmInstance)
|
|
mAlarmInstance->slotResourceStatusChanged(resource, change);
|
|
if (mTemplateInstance)
|
|
mTemplateInstance->slotResourceStatusChanged(resource, change);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Called when a resource status has changed.
|
|
*/
|
|
void EventListModel::slotResourceStatusChanged(AlarmResource* resource, AlarmResources::Change change)
|
|
{
|
|
bool added = false;
|
|
switch (change)
|
|
{
|
|
case AlarmResources::Added:
|
|
kDebug() << resource->resourceName() << "Added";
|
|
added = true;
|
|
break;
|
|
case AlarmResources::Deleted:
|
|
kDebug() << resource->resourceName() << "Deleted";
|
|
removeResource(resource);
|
|
return;
|
|
case AlarmResources::Invalidated:
|
|
kDebug() << resource->resourceName() << "Invalidated";
|
|
removeResource(resource);
|
|
return;
|
|
case AlarmResources::Location:
|
|
kDebug() << resource->resourceName() << "Location";
|
|
removeResource(resource);
|
|
added = true;
|
|
break;
|
|
case AlarmResources::Enabled:
|
|
if (resource->isActive())
|
|
added = true;
|
|
else
|
|
removeResource(resource);
|
|
break;
|
|
case AlarmResources::Colour:
|
|
{
|
|
kDebug() << "Colour";
|
|
int firstRow = -1;
|
|
for (int row = 0, end = mEvents.count(); row < end; ++row)
|
|
{
|
|
if (mEvents[row]->resource() == resource)
|
|
{
|
|
// For efficiency, emit a single signal for each group
|
|
// of consecutive alarms for the resource, rather than a separate
|
|
// signal for each alarm.
|
|
if (firstRow < 0)
|
|
firstRow = row;
|
|
}
|
|
else if (firstRow >= 0)
|
|
{
|
|
emit dataChanged(index(firstRow, 0), index(row - 1, ColumnCount - 1));
|
|
firstRow = -1;
|
|
}
|
|
}
|
|
if (firstRow >= 0)
|
|
emit dataChanged(index(firstRow, 0), index(mEvents.count() - 1, ColumnCount - 1));
|
|
return;
|
|
}
|
|
case AlarmResources::ReadOnly:
|
|
case AlarmResources::WrongType:
|
|
return;
|
|
}
|
|
|
|
if (added)
|
|
{
|
|
KAEvent::List list = AlarmCalendar::resources()->events(resource, mStatus);
|
|
for (int i = list.count(); --i >= 0; )
|
|
{
|
|
if (mEvents.indexOf(list[i]) >= 0)
|
|
list.remove(i); // avoid creating duplicate entries
|
|
}
|
|
if (!list.isEmpty())
|
|
{
|
|
int row = mEvents.count();
|
|
beginInsertRows(QModelIndex(), row, row + list.count() - 1);
|
|
mEvents += list;
|
|
endInsertRows();
|
|
if (!mHaveEvents)
|
|
updateHaveEvents(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Remove a resource's events from the list.
|
|
* This has to be called before the resource is actually deleted or reloaded. If
|
|
* not, timer based updates can occur between the resource being deleted and
|
|
* slotResourceStatusChanged(Deleted) being triggered, leading to crashes when
|
|
* data from the resource's events is fetched.
|
|
*/
|
|
void EventListModel::removeResource(AlarmResource* resource)
|
|
{
|
|
kDebug();
|
|
int lastRow = -1;
|
|
for (int row = mEvents.count(); --row >= 0; )
|
|
{
|
|
AlarmResource* r = mEvents[row]->resource();
|
|
if (!r || r == resource)
|
|
{
|
|
// For efficiency, delete each group of consecutive
|
|
// alarms for the resource, rather than deleting each
|
|
// alarm separately.
|
|
if (lastRow < 0)
|
|
lastRow = row;
|
|
}
|
|
else if (lastRow >= 0)
|
|
{
|
|
beginRemoveRows(QModelIndex(), row + 1, lastRow);
|
|
while (lastRow > row)
|
|
mEvents.remove(lastRow--);
|
|
endRemoveRows();
|
|
lastRow = -1;
|
|
}
|
|
}
|
|
if (lastRow >= 0)
|
|
{
|
|
beginRemoveRows(QModelIndex(), 0, lastRow);
|
|
while (lastRow >= 0)
|
|
mEvents.remove(lastRow--);
|
|
endRemoveRows();
|
|
}
|
|
if (mHaveEvents && mEvents.isEmpty())
|
|
updateHaveEvents(false);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Reload the event list.
|
|
*/
|
|
void EventListModel::reload()
|
|
{
|
|
// This would be better done by a reset(), but the signals are private to QAbstractItemModel
|
|
if (!mEvents.isEmpty())
|
|
{
|
|
beginRemoveRows(QModelIndex(), 0, mEvents.count() - 1);
|
|
mEvents.clear();
|
|
endRemoveRows();
|
|
}
|
|
KAEvent::List list = AlarmCalendar::resources()->events(mStatus);
|
|
if (!list.isEmpty())
|
|
{
|
|
beginInsertRows(QModelIndex(), 0, list.count() - 1);
|
|
mEvents = list;
|
|
endInsertRows();
|
|
}
|
|
if (mHaveEvents == mEvents.isEmpty())
|
|
updateHaveEvents(!mHaveEvents);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Return the index to a specified event.
|
|
*/
|
|
QModelIndex EventListModel::eventIndex(const QString& eventId) const
|
|
{
|
|
for (int row = 0, end = mEvents.count(); row < end; ++row)
|
|
{
|
|
if (mEvents[row]->id() == eventId)
|
|
return createIndex(row, 0, mEvents[row]);
|
|
}
|
|
return QModelIndex();
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Return the index to a specified event.
|
|
*/
|
|
QModelIndex EventListModel::eventIndex(const KAEvent* event) const
|
|
{
|
|
int row = mEvents.indexOf(const_cast<KAEvent*>(event));
|
|
if (row < 0)
|
|
return QModelIndex();
|
|
return createIndex(row, 0, mEvents[row]);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Add an event to the list.
|
|
*/
|
|
void EventListModel::addEvent(KAEvent* event)
|
|
{
|
|
if (!(event->category() & mStatus) || mEvents.contains(event))
|
|
return;
|
|
int row = mEvents.count();
|
|
beginInsertRows(QModelIndex(), row, row);
|
|
mEvents += event;
|
|
endInsertRows();
|
|
if (!mHaveEvents)
|
|
updateHaveEvents(true);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Add an event to the list.
|
|
*/
|
|
void EventListModel::addEvents(const KAEvent::List& events)
|
|
{
|
|
KAEvent::List evs;
|
|
for (int i = 0, count = events.count(); i < count; ++i)
|
|
if (events[i]->category() & mStatus)
|
|
evs += events[i];
|
|
int row = mEvents.count();
|
|
beginInsertRows(QModelIndex(), row, row + evs.count() - 1);
|
|
mEvents += evs;
|
|
endInsertRows();
|
|
if (!mHaveEvents)
|
|
updateHaveEvents(true);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Remove an event from the list.
|
|
*/
|
|
void EventListModel::removeEvent(int row)
|
|
{
|
|
if (row < 0)
|
|
return;
|
|
beginRemoveRows(QModelIndex(), row, row);
|
|
mEvents.remove(row);
|
|
endRemoveRows();
|
|
if (mHaveEvents && mEvents.isEmpty())
|
|
updateHaveEvents(false);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Notify that an event in the list has been updated.
|
|
*/
|
|
bool EventListModel::updateEvent(int row)
|
|
{
|
|
if (row < 0)
|
|
return false;
|
|
emit dataChanged(index(row, 0), index(row, ColumnCount - 1));
|
|
return true;
|
|
}
|
|
|
|
bool EventListModel::updateEvent(const QString& oldId, KAEvent* newEvent)
|
|
{
|
|
int row = findEvent(oldId);
|
|
if (row < 0)
|
|
return false;
|
|
mEvents[row] = newEvent;
|
|
emit dataChanged(index(row, 0), index(row, ColumnCount - 1));
|
|
return true;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Find the row of an event in the list, given its unique ID.
|
|
*/
|
|
int EventListModel::findEvent(const QString& eventId) const
|
|
{
|
|
for (int row = 0, end = mEvents.count(); row < end; ++row)
|
|
{
|
|
if (mEvents[row]->id() == eventId)
|
|
return row;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Return the event for a given row.
|
|
*/
|
|
KAEvent* EventListModel::event(int row) const
|
|
{
|
|
if (row < 0 || row >= mEvents.count())
|
|
return 0;
|
|
return mEvents[row];
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Return the event referred to by an index.
|
|
*/
|
|
KAEvent* EventListModel::event(const QModelIndex& index)
|
|
{
|
|
if (!index.isValid())
|
|
return 0;
|
|
return static_cast<KAEvent*>(index.internalPointer());
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Return the repetition text.
|
|
*/
|
|
QString EventListModel::repeatText(const KAEvent* event) const
|
|
{
|
|
QString repeatText = event->recurrenceText(true);
|
|
if (repeatText.isEmpty())
|
|
repeatText = event->repetitionText(true);
|
|
return repeatText;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Return a string for sorting the repetition column.
|
|
*/
|
|
QString EventListModel::repeatOrder(const KAEvent* event) const
|
|
{
|
|
int repeatOrder = 0;
|
|
int repeatInterval = 0;
|
|
if (event->repeatAtLogin())
|
|
repeatOrder = 1;
|
|
else
|
|
{
|
|
repeatInterval = event->recurInterval();
|
|
switch (event->recurType())
|
|
{
|
|
case KARecurrence::MINUTELY:
|
|
repeatOrder = 2;
|
|
break;
|
|
case KARecurrence::DAILY:
|
|
repeatOrder = 3;
|
|
break;
|
|
case KARecurrence::WEEKLY:
|
|
repeatOrder = 4;
|
|
break;
|
|
case KARecurrence::MONTHLY_DAY:
|
|
case KARecurrence::MONTHLY_POS:
|
|
repeatOrder = 5;
|
|
break;
|
|
case KARecurrence::ANNUAL_DATE:
|
|
case KARecurrence::ANNUAL_POS:
|
|
repeatOrder = 6;
|
|
break;
|
|
case KARecurrence::NO_RECUR:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return QString("%1%2").arg(static_cast<char>('0' + repeatOrder)).arg(repeatInterval, 8, 10, QLatin1Char('0'));
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Return the icon associated with the event's action.
|
|
*/
|
|
QPixmap* EventListModel::eventIcon(const KAEvent* event) const
|
|
{
|
|
switch (event->actionTypes())
|
|
{
|
|
case KAEvent::ACT_EMAIL:
|
|
return mEmailIcon;
|
|
case KAEvent::ACT_AUDIO:
|
|
return mAudioIcon;
|
|
case KAEvent::ACT_COMMAND:
|
|
return mCommandIcon;
|
|
case KAEvent::ACT_DISPLAY:
|
|
if (event->actionSubType() == KAEvent::FILE)
|
|
return mFileIcon;
|
|
// fall through to ACT_DISPLAY_COMMAND
|
|
case KAEvent::ACT_DISPLAY_COMMAND:
|
|
default:
|
|
return mTextIcon;
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Returns the QWhatsThis text for a specified column.
|
|
*/
|
|
QString EventListModel::whatsThisText(int column) const
|
|
{
|
|
switch (column)
|
|
{
|
|
case TimeColumn:
|
|
return i18nc("@info:whatsthis", "Next scheduled date and time of the alarm");
|
|
case TimeToColumn:
|
|
return i18nc("@info:whatsthis", "How long until the next scheduled trigger of the alarm");
|
|
case RepeatColumn:
|
|
return i18nc("@info:whatsthis", "How often the alarm recurs");
|
|
case ColourColumn:
|
|
return i18nc("@info:whatsthis", "Background color of alarm message");
|
|
case TypeColumn:
|
|
return i18nc("@info:whatsthis", "Alarm type (message, file, command or email)");
|
|
case TextColumn:
|
|
return i18nc("@info:whatsthis", "Alarm message text, URL of text file to display, command to execute, or email subject line");
|
|
case TemplateNameColumn:
|
|
return i18nc("@info:whatsthis", "Name of the alarm template");
|
|
default:
|
|
return QString();
|
|
}
|
|
}
|
|
|
|
|
|
/*=============================================================================
|
|
= Class: EventListFilterModel
|
|
= Base class for all filters on EventListModel.
|
|
=============================================================================*/
|
|
|
|
EventListFilterModel::EventListFilterModel(EventListModel* baseModel, QObject* parent)
|
|
: QSortFilterProxyModel(parent)
|
|
{
|
|
setSourceModel(baseModel);
|
|
setSortRole(EventListModel::SortRole);
|
|
setDynamicSortFilter(true);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Return the event referred to by an index.
|
|
*/
|
|
KAEvent* EventListFilterModel::event(const QModelIndex& index) const
|
|
{
|
|
return static_cast<EventListModel*>(sourceModel())->event(mapToSource(index));
|
|
}
|
|
|
|
KAEvent* EventListFilterModel::event(int row) const
|
|
{
|
|
return static_cast<EventListModel*>(sourceModel())->event(mapToSource(index(row, 0)));
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Return the index to a specified event.
|
|
*/
|
|
QModelIndex EventListFilterModel::eventIndex(const QString& eventId) const
|
|
{
|
|
return mapFromSource(static_cast<EventListModel*>(sourceModel())->eventIndex(eventId));
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Return the index to a specified event.
|
|
*/
|
|
QModelIndex EventListFilterModel::eventIndex(const KAEvent* event) const
|
|
{
|
|
return mapFromSource(static_cast<EventListModel*>(sourceModel())->eventIndex(event));
|
|
}
|
|
|
|
void EventListFilterModel::slotDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
|
{
|
|
emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight));
|
|
}
|
|
|
|
// vim: et sw=4:
|