eventlistview.cpp 8.63 KB
Newer Older
David Jarvie's avatar
David Jarvie committed
1
/*
2
 *  eventlistview.cpp  -  base class for widget showing list of alarms
David Jarvie's avatar
David Jarvie committed
3
 *  Program:  kalarm
4
 *  Copyright © 2007-2020 David Jarvie <djarvie@kde.org>
David Jarvie's avatar
David Jarvie committed
5
6
7
8
9
10
11
12
13
14
15
 *
 *  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.
 *
David Jarvie's avatar
David Jarvie committed
16
17
18
 *  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.
David Jarvie's avatar
David Jarvie committed
19
20
 */

Laurent Montel's avatar
Laurent Montel committed
21
#include "eventlistview.h"
David Jarvie's avatar
David Jarvie committed
22

23
#include "find.h"
David Jarvie's avatar
David Jarvie committed
24
#include "resources/eventmodel.h"
25
#include "resources/resourcedatamodelbase.h"
26
#include "kalarm_debug.h"
David Jarvie's avatar
David Jarvie committed
27

28
#include <KLocalizedString>
David Jarvie's avatar
David Jarvie committed
29

30
31
32
#include <QMouseEvent>
#include <QToolTip>
#include <QApplication>
David Jarvie's avatar
David Jarvie committed
33
34


35
EventListView::EventListView(QWidget* parent)
David Jarvie's avatar
David Jarvie committed
36
    : QTreeView(parent)
David Jarvie's avatar
David Jarvie committed
37
{
38
39
40
41
42
43
44
45
    setRootIsDecorated(false);    // don't show expander icons for child-less items
    setSortingEnabled(true);
    setAllColumnsShowFocus(true);
    setSelectionMode(ExtendedSelection);
    setSelectionBehavior(SelectRows);
    setTextElideMode(Qt::ElideRight);
    // Set default WhatsThis text to be displayed when no actual item is clicked on
    setWhatsThis(i18nc("@info:whatsthis", "List of scheduled alarms"));
David Jarvie's avatar
David Jarvie committed
46
47
}

48
49
50
51
52
53
54
55
56
void EventListView::setModel(QAbstractItemModel* model)
{
    EventListModel* elm = qobject_cast<EventListModel*>(model);
    Q_ASSERT(elm);   // model must be derived from EventListModel

    QTreeView::setModel(model);
    connect(elm, &EventListModel::haveEventsStatus, this, &EventListView::initSections);
}

David Jarvie's avatar
David Jarvie committed
57
58
59
60
61
62
63
64
/******************************************************************************
* Return the source data model.
*/
EventListModel* EventListView::itemModel() const
{
    return static_cast<EventListModel*>(model());
}

65
66
67
/******************************************************************************
* Return the event referred to by an index.
*/
68
69
KAEvent EventListView::event(const QModelIndex& index) const
{
70
    return itemModel()->event(index);
71
72
73
74
}

KAEvent EventListView::event(int row) const
{
75
    return itemModel()->event(itemModel()->index(row, 0));
76
}
77

David Jarvie's avatar
David Jarvie committed
78
/******************************************************************************
79
* Select one event and make it the current item.
David Jarvie's avatar
David Jarvie committed
80
*/
81
void EventListView::select(const QModelIndex& index, bool scrollToIndex)
David Jarvie's avatar
David Jarvie committed
82
{
83
    selectionModel()->select(index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
84
85
    if (scrollToIndex)
        scrollTo(index);
David Jarvie's avatar
David Jarvie committed
86
87
}

88
89
90
91
92
void EventListView::clearSelection()
{
    selectionModel()->clearSelection();
}

David Jarvie's avatar
David Jarvie committed
93
/******************************************************************************
94
95
* Return the single selected item.
* Reply = invalid if no items are selected, or if multiple items are selected.
David Jarvie's avatar
David Jarvie committed
96
*/
97
QModelIndex EventListView::selectedIndex() const
David Jarvie's avatar
David Jarvie committed
98
{
David Jarvie's avatar
David Jarvie committed
99
    const QModelIndexList list = selectionModel()->selectedRows();
100
101
102
    if (list.count() != 1)
        return QModelIndex();
    return list[0];
David Jarvie's avatar
David Jarvie committed
103
104
105
}

/******************************************************************************
106
107
* Return the single selected event.
* Reply = null if no items are selected, or if multiple items are selected.
David Jarvie's avatar
David Jarvie committed
108
*/
109
110
KAEvent EventListView::selectedEvent() const
{
David Jarvie's avatar
David Jarvie committed
111
    const QModelIndexList list = selectionModel()->selectedRows();
112
113
    if (list.count() != 1)
        return KAEvent();
David Jarvie's avatar
David Jarvie committed
114
    const EventListModel* model = static_cast<const EventListModel*>(list[0].model());
115
    return model->event(list[0]);
116
}
117

David Jarvie's avatar
David Jarvie committed
118
/******************************************************************************
119
* Return the selected events.
David Jarvie's avatar
David Jarvie committed
120
*/
121
QVector<KAEvent> EventListView::selectedEvents() const
David Jarvie's avatar
David Jarvie committed
122
{
123
    QVector<KAEvent> elist;
David Jarvie's avatar
David Jarvie committed
124
    const QModelIndexList ixlist = selectionModel()->selectedRows();
125
126
127
    int count = ixlist.count();
    if (count)
    {
David Jarvie's avatar
David Jarvie committed
128
        const EventListModel* model = static_cast<const EventListModel*>(ixlist[0].model());
Laurent Montel's avatar
Laurent Montel committed
129
        elist.reserve(count);
130
131
132
133
        for (int i = 0;  i < count;  ++i)
            elist += model->event(ixlist[i]);
    }
    return elist;
David Jarvie's avatar
David Jarvie committed
134
135
}

David Jarvie's avatar
David Jarvie committed
136
/******************************************************************************
David Jarvie's avatar
David Jarvie committed
137
138
* Called when the Find action is selected.
* Display the non-modal Find dialog.
David Jarvie's avatar
David Jarvie committed
139
140
141
*/
void EventListView::slotFind()
{
142
143
144
    if (!mFind)
    {
        mFind = new Find(this);
Laurent Montel's avatar
Laurent Montel committed
145
        connect(mFind, &Find::active, this, &EventListView::findActive);
146
147
    }
    mFind->display();
David Jarvie's avatar
David Jarvie committed
148
149
150
}

/******************************************************************************
David Jarvie's avatar
David Jarvie committed
151
* Called when the Find Next or Find Prev action is selected.
David Jarvie's avatar
David Jarvie committed
152
153
154
*/
void EventListView::findNext(bool forward)
{
155
156
    if (mFind)
        mFind->findNext(forward);
David Jarvie's avatar
David Jarvie committed
157
158
}

159
160
161
162
163
164
void EventListView::resizeEvent(QResizeEvent* se)
{
    QTreeView::resizeEvent(se);
    initSections();
}

David Jarvie's avatar
David Jarvie committed
165
/******************************************************************************
166
167
* Called when a ToolTip or WhatsThis event occurs.
*/
David Jarvie's avatar
David Jarvie committed
168
169
bool EventListView::viewportEvent(QEvent* e)
{
170
171
172
    if (e->type() == QEvent::ToolTip  &&  isActiveWindow())
    {
        QHelpEvent* he = static_cast<QHelpEvent*>(e);
David Jarvie's avatar
David Jarvie committed
173
        const QModelIndex index = indexAt(he->pos());
174
        QVariant value = model()->data(index, Qt::ToolTipRole);
Laurent Montel's avatar
Laurent Montel committed
175
        if (value.canConvert<QString>())
176
177
        {
            QString toolTip = value.toString();
Laurent Montel's avatar
Laurent Montel committed
178
            int i = toolTip.indexOf(QLatin1Char('\n'));
179
180
            if (i < 0)
            {
David Jarvie's avatar
David Jarvie committed
181
                EventListModel* m = qobject_cast<EventListModel*>(model());
182
183
                if (index.column() == ResourceDataModelBase::TextColumn
                ||  !m  ||  m->event(index).commandError() == KAEvent::CMD_NO_ERROR)
184
185
186
187
                {
                    // Single line tooltip. Only display it if the text column
                    // is truncated in the view display.
                    value = model()->data(index, Qt::FontRole);
David Jarvie's avatar
David Jarvie committed
188
189
                    const QFontMetrics fm(qvariant_cast<QFont>(value).resolve(viewOptions().font));
                    const int textWidth = fm.boundingRect(toolTip).width() + 1;
190
                    const int margin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
David Jarvie's avatar
David Jarvie committed
191
192
                    const int left = columnViewportPosition(index.column()) + margin;
                    const int right = left + textWidth;
193
194
195
196
197
198
199
200
201
                    if (left >= 0  &&  right <= width() - 2*frameWidth())
                        toolTip.clear();    // prevent any tooltip showing
                }
            }
            QToolTip::showText(he->globalPos(), toolTip, this);
            return true;
        }
    }
    return QTreeView::viewportEvent(e);
David Jarvie's avatar
David Jarvie committed
202
203
}

David Jarvie's avatar
David Jarvie committed
204
/******************************************************************************
David Jarvie's avatar
David Jarvie committed
205
* Called when a context menu event is requested by mouse or key.
David Jarvie's avatar
David Jarvie committed
206
*/
David Jarvie's avatar
David Jarvie committed
207
void EventListView::contextMenuEvent(QContextMenuEvent* e)
David Jarvie's avatar
David Jarvie committed
208
{
Laurent Montel's avatar
Laurent Montel committed
209
    Q_EMIT contextMenuRequested(e->globalPos());
210
}
211
212
213
214


bool EventListDelegate::editorEvent(QEvent* e, QAbstractItemModel* model, const QStyleOptionViewItem&, const QModelIndex& index)
{
215
216
217
218
219
220
221
222
223
224
225
226
    // Don't invoke the editor unless it's either a double click or,
    // if KDE is in single click mode and it's a left button release
    // with no other buttons pressed and no keyboard modifiers.
    switch (e->type())
    {
        case QEvent::MouseButtonPress:
        case QEvent::MouseMove:
            return false;
        case QEvent::MouseButtonDblClick:
            break;
        case QEvent::MouseButtonRelease:
        {
David Jarvie's avatar
David Jarvie committed
227
228
            EventListView* view = static_cast<EventListView*>(parent());
            if (!view->editOnSingleClick()
Laurent Montel's avatar
Laurent Montel committed
229
            ||  !view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, view))
230
231
232
233
234
235
236
237
238
239
240
241
                return false;
            QMouseEvent* me = static_cast<QMouseEvent*>(e);
            if (me->button() != Qt::LeftButton  ||  me->buttons()
            ||  me->modifiers() != Qt::NoModifier)
                return false;
            break;
        }
        default:
            break;
    }
    if (index.isValid())
    {
242
        qCDebug(KALARM_LOG) << "EventListDelegate::editorEvent";
David Jarvie's avatar
David Jarvie committed
243
        EventListModel* itemModel = qobject_cast<EventListModel*>(model);
244
        if (!itemModel)
David Jarvie's avatar
David Jarvie committed
245
            qCCritical(KALARM_LOG) << "EventListDelegate::editorEvent: Invalid cast to EventListModel*";
246
247
248
249
250
251
252
253
        else
        {
            KAEvent event = itemModel->event(index);
            edit(&event, static_cast<EventListView*>(parent()));
            return true;
        }
    }
    return false;   // indicate that the event has not been handled
254
}
Laurent Montel's avatar
Laurent Montel committed
255

256
// vim: et sw=4: