]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiSelectionManager.cpp
removed unused includes
[lyx.git] / src / frontends / qt4 / GuiSelectionManager.cpp
1 /**
2  * \file GuiSelectionManager.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Richard Heck
7  * \author Et Alia
8  *
9  * Some of the material in this file previously appeared in 
10  * GuiCitationDialog.cpp.
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "GuiSelectionManager.h"
18
19 #include <QAbstractListModel>
20 #include <QItemSelection>
21 #include <QListView>
22 #include <QKeyEvent>
23 #include <QPushButton>
24
25 #ifdef KeyPress
26 #undef KeyPress
27 #endif
28
29 #ifdef ControlModifier
30 #undef ControlModifier
31 #endif
32
33 #ifdef FocusIn
34 #undef FocusIn
35 #endif
36
37
38 namespace lyx {
39 namespace frontend {
40
41 GuiSelectionManager::GuiSelectionManager(
42         QAbstractItemView * avail,
43         QListView * sel,
44         QPushButton * add, 
45         QPushButton * del, 
46         QPushButton * up, 
47         QPushButton * down,
48         QAbstractListModel * amod,
49         QAbstractListModel * smod)
50   : availableLV(avail), selectedLV(sel), addPB(add), deletePB(del),
51                 upPB(up), downPB(down), availableModel(amod), selectedModel(smod),
52     selectedHasFocus_(false)
53 {
54         
55         selectedLV->setModel(smod);
56         availableLV->setModel(amod);
57         
58         connect(availableLV->selectionModel(),
59                 SIGNAL(currentChanged(QModelIndex, QModelIndex)),
60                 this, SLOT(availableChanged(QModelIndex, QModelIndex)));
61         connect(selectedLV->selectionModel(),
62                 SIGNAL(currentChanged(QModelIndex, QModelIndex)),
63                 this, SLOT(selectedChanged(QModelIndex, QModelIndex)));
64         connect(availableLV->selectionModel(),
65                 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
66                 this, SLOT(availableChanged(QItemSelection, QItemSelection)));
67         connect(selectedLV->selectionModel(),
68                 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
69                 this, SLOT(selectedChanged(QItemSelection, QItemSelection)));
70         connect(addPB, SIGNAL(clicked()), 
71                 this, SLOT(addPB_clicked()));
72         connect(deletePB, SIGNAL(clicked()), 
73                 this, SLOT(deletePB_clicked()));
74         connect(upPB, SIGNAL(clicked()), 
75                 this, SLOT(upPB_clicked()));
76         connect(downPB, SIGNAL(clicked()), 
77                 this, SLOT(downPB_clicked()));
78         connect(availableLV, SIGNAL(doubleClicked(QModelIndex)), 
79                 this, SLOT(availableLV_doubleClicked(QModelIndex)));
80         
81         availableLV->installEventFilter(this);
82         selectedLV->installEventFilter(this);
83 }
84
85
86 void GuiSelectionManager::update()
87 {
88         updateAddPB();
89         updateDelPB();
90         updateDownPB();
91         updateUpPB();
92 }
93
94
95 QModelIndex GuiSelectionManager::getSelectedIndex() const
96 {
97         QModelIndexList avail = availableLV->selectionModel()->selectedIndexes();
98         QModelIndexList sel   = selectedLV->selectionModel()->selectedIndexes();
99         bool const have_avl = !avail.isEmpty();
100         bool const have_sel = !sel.isEmpty();
101
102         if (selectedFocused()) { 
103                 if (have_sel)
104                         return sel.front();
105                 if (have_avl)
106                         return avail.front();
107         } 
108         else { // available has focus
109                 if (have_avl)
110                         return avail.front();
111                 if (have_sel)
112                         return sel.front();
113         }
114         return QModelIndex();
115 }
116
117
118 void GuiSelectionManager::updateAddPB()
119 {
120         int const arows = availableModel->rowCount();
121         QModelIndexList const availSels = 
122                 availableLV->selectionModel()->selectedIndexes();
123         addPB->setEnabled(arows > 0 &&
124                 !availSels.isEmpty() &&
125                 !isSelected(availSels.first()));
126 }
127
128
129 void GuiSelectionManager::updateDelPB()
130 {
131         int const srows = selectedModel->rowCount();
132         if (srows == 0) {
133                 deletePB->setEnabled(false);
134                 return;
135         }
136         QModelIndexList const selSels = 
137                 selectedLV->selectionModel()->selectedIndexes();
138         int const sel_nr =      selSels.empty() ? -1 : selSels.first().row();
139         deletePB->setEnabled(sel_nr >= 0);
140 }
141
142
143 void GuiSelectionManager::updateUpPB()
144 {
145         int const srows = selectedModel->rowCount();
146         if (srows == 0) {
147                 upPB->setEnabled(false);
148                 return;
149         }
150         QModelIndexList const selSels = 
151                         selectedLV->selectionModel()->selectedIndexes();
152         int const sel_nr =      selSels.empty() ? -1 : selSels.first().row();
153         upPB->setEnabled(sel_nr > 0);
154 }
155
156
157 void GuiSelectionManager::updateDownPB()
158 {
159         int const srows = selectedModel->rowCount();
160         if (srows == 0) {
161                 downPB->setEnabled(false);
162                 return;
163         }
164         QModelIndexList const selSels = 
165                         selectedLV->selectionModel()->selectedIndexes();
166         int const sel_nr =      selSels.empty() ? -1 : selSels.first().row();
167         downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
168 }
169
170
171 bool GuiSelectionManager::isSelected(const QModelIndex & idx)
172 {
173         if (selectedModel->rowCount() == 0)
174                 return false;
175         QVariant const & str = availableModel->data(idx, Qt::DisplayRole);
176         QModelIndexList qmil = 
177                         selectedModel->match(selectedModel->index(0), 
178                                              Qt::DisplayRole, str, 1,
179                                              Qt::MatchFlags(Qt::MatchExactly | Qt::MatchWrap));
180         return !qmil.empty();
181 }
182
183
184 void GuiSelectionManager::availableChanged(QItemSelection const & qis, QItemSelection const &)
185 {
186         QModelIndexList il = qis.indexes();
187         if (il.empty()) 
188                 return;
189         availableChanged(il.front(), QModelIndex());
190 }
191
192
193 void GuiSelectionManager::availableChanged(const QModelIndex & idx, const QModelIndex &)
194 {
195         if (!idx.isValid())
196                 return;
197         
198         selectedHasFocus_ = false;
199         updateHook();
200 }
201
202
203 void GuiSelectionManager::selectedChanged(QItemSelection const & qis, QItemSelection const &)
204 {
205         QModelIndexList il = qis.indexes();
206         if (il.empty()) 
207                 return;
208         selectedChanged(il.front(), QModelIndex());
209 }
210
211
212 void GuiSelectionManager::selectedChanged(const QModelIndex & idx, const QModelIndex &)
213 {
214         if (!idx.isValid())
215                 return;
216         
217         selectedHasFocus_ = true;
218         updateHook();
219 }
220
221
222 bool GuiSelectionManager::insertRowToSelected(int i, 
223                 QMap<int, QVariant> const & itemData)
224 {
225         if (i <= -1)
226                 i = 0;
227         if (i > selectedModel->rowCount())
228                 i = selectedModel->rowCount();
229         if (!selectedModel->insertRow(i))
230                 return false;
231         return selectedModel->setItemData(selectedModel->index(i), itemData);
232 }
233
234
235 void GuiSelectionManager::addPB_clicked()
236 {
237         QModelIndexList selIdx =
238                 availableLV->selectionModel()->selectedIndexes();
239         if (selIdx.isEmpty())
240                 return;
241
242         QModelIndex const idxToAdd = selIdx.first();
243         QModelIndex const idx = selectedLV->currentIndex();
244         int const srows = selectedModel->rowCount();
245         
246         QMap<int, QVariant> qm = availableModel->itemData(idxToAdd);
247         insertRowToSelected(srows, qm);
248         
249         selectionChanged(); //signal
250
251         if (idx.isValid())
252                 selectedLV->setCurrentIndex(idx);
253         
254         updateHook();
255 }
256
257
258 void GuiSelectionManager::deletePB_clicked()
259 {
260         QModelIndexList selIdx =
261                 selectedLV->selectionModel()->selectedIndexes();
262         if (selIdx.isEmpty())
263                 return;
264         QModelIndex idx = selIdx.first();
265         selectedModel->removeRow(idx.row());
266         selectionChanged(); //signal
267         
268         int nrows = selectedLV->model()->rowCount();
269         if (idx.row() == nrows) //was last item on list
270                 idx = idx.sibling(idx.row() - 1, idx.column());
271         
272         if (nrows > 1)
273                 selectedLV->setCurrentIndex(idx);
274         else if (nrows == 1)
275                 selectedLV->setCurrentIndex(selectedLV->model()->index(0, 0));
276         selectedHasFocus_ = (nrows > 0);
277         updateHook();
278 }
279
280
281 void GuiSelectionManager::upPB_clicked()
282 {
283         QModelIndexList selIdx =
284                 selectedLV->selectionModel()->selectedIndexes();
285         if (selIdx.isEmpty())
286                 return;
287         QModelIndex idx = selIdx.first();
288
289         int const pos = idx.row();
290         if (pos <= 0)
291                 return;
292         
293         QMap<int, QVariant> qm = selectedModel->itemData(idx);
294
295         selectedModel->removeRow(pos);
296         insertRowToSelected(pos - 1, qm);
297
298         selectionChanged(); //signal
299
300         selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column()));
301         selectedHasFocus_ = true;
302         updateHook();
303 }
304
305
306 void GuiSelectionManager::downPB_clicked()
307 {
308         QModelIndexList selIdx =
309                 selectedLV->selectionModel()->selectedIndexes();
310         if (selIdx.isEmpty())
311                 return;
312         QModelIndex idx = selIdx.first();
313
314         int const pos = idx.row();
315         if (pos >= selectedModel->rowCount() - 1)
316                 return;
317
318         QMap<int, QVariant> qm = selectedModel->itemData(idx);
319
320         selectedModel->removeRow(pos);
321         insertRowToSelected(pos + 1, qm);
322
323         selectionChanged(); //signal
324         
325         selectedLV->setCurrentIndex(idx.sibling(idx.row() + 1, idx.column()));
326         selectedHasFocus_ = true;
327         updateHook();
328 }
329
330
331 void GuiSelectionManager::availableLV_doubleClicked(const QModelIndex & idx)
332 {
333         if (isSelected(idx) || !addPB->isEnabled())
334                 return;
335         
336         if (idx.isValid())
337                 selectedHasFocus_ = false;
338         addPB_clicked();
339         //updateHook() will be emitted there
340 }
341
342
343 bool GuiSelectionManager::eventFilter(QObject * obj, QEvent * event) 
344 {
345         QEvent::Type etype = event->type();
346         if (obj == availableLV) {
347                 if (etype == QEvent::KeyPress) {
348                         QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
349                         int const keyPressed = keyEvent->key();
350                         Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
351                         // Enter key without modifier will add current item.
352                         // Ctrl-Enter will add it and close the dialog.
353                         // This is designed to work both with the main enter key
354                         // and the one on the numeric keypad.
355                         if (keyPressed == Qt::Key_Enter || keyPressed == Qt::Key_Return) {
356                                 if (addPB->isEnabled()) {
357                                         if (!keyModifiers) {
358                                                 addPB_clicked();
359                                         } else if (keyModifiers == Qt::ControlModifier || 
360                                                   keyModifiers == Qt::KeypadModifier  ||
361                                                   keyModifiers == (Qt::ControlModifier | Qt::KeypadModifier)) {
362                                                 addPB_clicked();
363                                                 okHook(); //signal
364                                         }
365                                 }
366                                 event->accept();
367                                 return true;
368                         }
369                 } else if (etype == QEvent::FocusIn) {
370                         if (selectedHasFocus_) {
371                                 selectedHasFocus_ = false;
372                                 updateHook();
373                         }
374                         event->accept();
375                         return true;
376                 } 
377         } else if (obj == selectedLV) {
378                 if (etype == QEvent::KeyPress) {
379                         QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
380                         int const keyPressed = keyEvent->key();
381                         Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
382                         // Delete or backspace key will delete current item
383                         // ...with control modifier will clear the list
384                         if (keyPressed == Qt::Key_Delete || keyPressed == Qt::Key_Backspace) {
385                                 if (keyModifiers == Qt::NoModifier && deletePB->isEnabled()) {
386                                         deletePB_clicked();
387                                         updateHook();
388                                 } else if (keyModifiers == Qt::ControlModifier) {
389                                         selectedModel->removeRows(0, selectedModel->rowCount());
390                                         updateHook();
391                                 } else
392                                         return QObject::eventFilter(obj, event);
393                         } 
394                         // Ctrl-Up activates upPB
395                         else if (keyPressed == Qt::Key_Up) {
396                                 if (keyModifiers == Qt::ControlModifier) {
397                                         if (upPB->isEnabled())
398                                                 upPB_clicked();
399                                         event->accept();
400                                         return true;
401                                 }
402                         } 
403                         // Ctrl-Down activates downPB
404                         else if (keyPressed == Qt::Key_Down) {
405                                 if (keyModifiers == Qt::ControlModifier) {
406                                         if (downPB->isEnabled())
407                                                 downPB_clicked();
408                                         event->accept();
409                                         return true;
410                                 }
411                         }
412                 } else if (etype == QEvent::FocusIn) {
413                         if (!selectedHasFocus_) {
414                                 selectedHasFocus_ = true;
415                                 updateHook();
416                         }
417                         event->accept();
418                         return true;
419                 }
420         }
421         return QObject::eventFilter(obj, event);
422 }
423
424 } // namespace frontend
425 } // namespace lyx
426
427 #include "moc_GuiSelectionManager.cpp"