2 * \file GuiSelectionManager.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
9 * Some of the material in this file previously appeared in
10 * GuiCitationDialog.cpp.
12 * Full author contact details are available in file CREDITS.
17 #include "GuiSelectionManager.h"
18 #include "qt_helpers.h"
20 #include "support/debug.h"
22 #include <QAbstractItemModel>
23 #include <QAbstractListModel>
24 #include <QItemSelection>
27 #include <QPushButton>
33 #ifdef ControlModifier
34 #undef ControlModifier
45 GuiSelectionManager::GuiSelectionManager(QObject * parent,
46 QAbstractItemView * avail,
47 QAbstractItemView * sel,
52 QAbstractListModel * amod,
53 QAbstractItemModel * smod,
54 int const main_sel_col)
55 : QObject(parent), availableLV(avail), selectedLV(sel),
56 addPB(add), deletePB(del), upPB(up), downPB(down),
57 availableModel(amod), selectedModel(smod),
58 selectedHasFocus_(false), main_sel_col_(main_sel_col)
60 selectedLV->setModel(smod);
61 availableLV->setModel(amod);
62 selectedLV->setSelectionBehavior(QAbstractItemView::SelectRows);
63 selectedLV->setSelectionMode(QAbstractItemView::SingleSelection);
65 connect(availableLV->selectionModel(),
66 SIGNAL(currentChanged(QModelIndex, QModelIndex)),
67 this, SLOT(availableChanged(QModelIndex, QModelIndex)));
68 connect(selectedLV->selectionModel(),
69 SIGNAL(currentChanged(QModelIndex, QModelIndex)),
70 this, SLOT(selectedChanged(QModelIndex, QModelIndex)));
71 connect(availableLV->selectionModel(),
72 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
73 this, SLOT(availableChanged(QItemSelection, QItemSelection)));
74 connect(availableLV->selectionModel(),
75 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
76 this, SLOT(updateButtons()));
77 connect(selectedLV->selectionModel(),
78 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
79 this, SLOT(selectedChanged(QItemSelection, QItemSelection)));
80 connect(selectedLV->selectionModel(),
81 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
82 this, SLOT(updateButtons()));
83 connect(selectedLV->itemDelegate(), SIGNAL(commitData(QWidget*)),
84 this, SLOT(selectedEdited()));
85 connect(addPB, SIGNAL(clicked()),
86 this, SLOT(addPB_clicked()));
87 connect(deletePB, SIGNAL(clicked()),
88 this, SLOT(deletePB_clicked()));
89 connect(upPB, SIGNAL(clicked()),
90 this, SLOT(upPB_clicked()));
91 connect(downPB, SIGNAL(clicked()),
92 this, SLOT(downPB_clicked()));
93 connect(availableLV, SIGNAL(doubleClicked(QModelIndex)),
94 this, SLOT(availableLV_doubleClicked(QModelIndex)));
96 availableLV->installEventFilter(this);
97 selectedLV->installEventFilter(this);
101 void GuiSelectionManager::update()
110 void GuiSelectionManager::updateButtons()
117 QModelIndex GuiSelectionManager::getSelectedIndex(int const c) const
119 QModelIndexList avail = availableLV->selectionModel()->selectedIndexes();
120 QModelIndexList sel = selectedLV->selectionModel()->selectedRows(c);
121 bool const have_avl = !avail.isEmpty();
122 bool const have_sel = !sel.isEmpty();
124 if (selectedFocused()) {
128 return avail.front();
130 else { // available has focus
132 return avail.front();
136 return QModelIndex();
140 void GuiSelectionManager::updateAddPB()
142 int const arows = availableModel->rowCount();
143 QModelIndexList const availSels =
144 availableLV->selectionModel()->selectedIndexes();
145 addPB->setEnabled(arows > 0 &&
146 !availSels.isEmpty() &&
147 !isSelected(availSels.first()));
151 void GuiSelectionManager::updateDelPB()
153 int const srows = selectedModel->rowCount();
155 deletePB->setEnabled(false);
158 QModelIndexList const selSels =
159 selectedLV->selectionModel()->selectedIndexes();
160 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
161 deletePB->setEnabled(sel_nr >= 0);
165 void GuiSelectionManager::updateUpPB()
167 int const srows = selectedModel->rowCount();
169 upPB->setEnabled(false);
172 QModelIndexList const selSels =
173 selectedLV->selectionModel()->selectedIndexes();
174 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
175 upPB->setEnabled(sel_nr > 0);
179 void GuiSelectionManager::updateDownPB()
181 int const srows = selectedModel->rowCount();
183 downPB->setEnabled(false);
186 QModelIndexList const selSels =
187 selectedLV->selectionModel()->selectedIndexes();
188 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
189 downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
193 bool GuiSelectionManager::isSelected(const QModelIndex & idx)
195 if (selectedModel->rowCount() == 0)
197 QVariant const & str = availableModel->data(idx, Qt::DisplayRole);
198 QModelIndexList qmil =
199 selectedModel->match(selectedModel->index(0, main_sel_col_),
200 Qt::DisplayRole, str, 1,
201 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchWrap));
202 return !qmil.empty();
206 void GuiSelectionManager::availableChanged(QItemSelection const & qis, QItemSelection const &)
208 QModelIndexList il = qis.indexes();
211 availableChanged(il.front(), QModelIndex());
215 void GuiSelectionManager::availableChanged(const QModelIndex & idx, const QModelIndex &)
220 selectedHasFocus_ = false;
225 void GuiSelectionManager::selectedChanged(QItemSelection const & qis, QItemSelection const &)
227 QModelIndexList il = qis.indexes();
230 selectedChanged(il.front(), QModelIndex());
234 void GuiSelectionManager::selectedChanged(const QModelIndex & idx, const QModelIndex &)
239 selectedHasFocus_ = true;
244 void GuiSelectionManager::selectedEdited()
250 bool GuiSelectionManager::insertRowToSelected(int i,
251 QMap<int, QVariant> const & itemData)
255 if (i > selectedModel->rowCount())
256 i = selectedModel->rowCount();
257 if (!selectedModel->insertRow(i))
259 return selectedModel->setItemData(selectedModel->index(i, main_sel_col_), itemData);
263 bool GuiSelectionManager::insertRowToSelected(int i, QMap<int, QMap<int, QVariant>> & qms)
267 if (i > selectedModel->rowCount())
268 i = selectedModel->rowCount();
269 if (!selectedModel->insertRow(i))
272 QMap<int, QMap<int, QVariant>>::const_iterator it = qms.constBegin();
273 for (; it != qms.constEnd(); ++it)
274 res &= selectedModel->setItemData(selectedModel->index(i, it.key()), it.value());
279 void GuiSelectionManager::addPB_clicked()
281 QModelIndexList selIdx =
282 availableLV->selectionModel()->selectedIndexes();
283 if (selIdx.isEmpty())
286 QModelIndex const idxToAdd = selIdx.first();
287 QModelIndex const idx = selectedLV->currentIndex();
288 int const srows = selectedModel->rowCount();
290 QMap<int, QVariant> qm = availableModel->itemData(idxToAdd);
291 insertRowToSelected(srows, qm);
293 selectionChanged(); //signal
296 selectedLV->setCurrentIndex(idx);
302 void GuiSelectionManager::deletePB_clicked()
304 QModelIndexList selIdx =
305 selectedLV->selectionModel()->selectedIndexes();
306 if (selIdx.isEmpty())
308 QModelIndex idx = selIdx.first();
309 selectedModel->removeRow(idx.row());
310 selectionChanged(); //signal
312 int nrows = selectedLV->model()->rowCount();
313 if (idx.row() == nrows) //was last item on list
314 idx = idx.sibling(idx.row() - 1, idx.column());
317 selectedLV->setCurrentIndex(idx);
319 selectedLV->setCurrentIndex(selectedLV->model()->index(0, 0));
320 selectedHasFocus_ = (nrows > 0);
325 void GuiSelectionManager::upPB_clicked()
327 QModelIndexList selIdx =
328 selectedLV->selectionModel()->selectedIndexes();
329 if (selIdx.isEmpty())
331 QModelIndex idx = selIdx.first();
333 int const pos = idx.row();
337 QMap<int, QMap<int, QVariant>> qms;
338 QList<QModelIndex>::const_iterator it = selIdx.constBegin();
339 for (; it != selIdx.constEnd(); ++it)
340 qms[it->column()] = selectedModel->itemData(*it);
342 selectedModel->removeRow(pos);
343 insertRowToSelected(pos - 1, qms);
345 selectionChanged(); //signal
347 selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column()));
348 selectedHasFocus_ = true;
353 void GuiSelectionManager::downPB_clicked()
355 QModelIndexList selIdx =
356 selectedLV->selectionModel()->selectedIndexes();
357 if (selIdx.isEmpty())
359 QModelIndex idx = selIdx.first();
361 int const pos = idx.row();
362 if (pos >= selectedModel->rowCount() - 1)
365 QMap<int, QMap<int, QVariant>> qms;
366 QList<QModelIndex>::const_iterator it = selIdx.constBegin();
367 for (; it != selIdx.constEnd(); ++it)
368 qms[it->column()] = selectedModel->itemData(*it);
370 selectedModel->removeRow(pos);
371 insertRowToSelected(pos + 1, qms);
373 selectionChanged(); //signal
375 selectedLV->setCurrentIndex(idx.sibling(idx.row() + 1, idx.column()));
376 selectedHasFocus_ = true;
381 void GuiSelectionManager::availableLV_doubleClicked(const QModelIndex & idx)
383 if (isSelected(idx) || !addPB->isEnabled())
387 selectedHasFocus_ = false;
389 //updateHook() will be emitted there
393 bool GuiSelectionManager::eventFilter(QObject * obj, QEvent * event)
395 QEvent::Type etype = event->type();
396 if (obj == availableLV) {
397 if (etype == QEvent::KeyPress) {
398 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
399 int const keyPressed = keyEvent->key();
400 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
401 // Enter key without modifier will add current item.
402 // Ctrl-Enter will add it and close the dialog.
403 // This is designed to work both with the main enter key
404 // and the one on the numeric keypad.
405 if (keyPressed == Qt::Key_Enter || keyPressed == Qt::Key_Return) {
407 keyModifiers == Qt::ControlModifier ||
408 keyModifiers == Qt::KeypadModifier ||
409 keyModifiers == (Qt::ControlModifier
410 | Qt::KeypadModifier)) {
411 if (addPB->isEnabled()) {
420 else if (keyPressed == Qt::Key_Right) {
421 focusAndHighlight(selectedLV);
425 } else if (etype == QEvent::FocusIn) {
426 if (selectedHasFocus_) {
427 selectedHasFocus_ = false;
432 } else if (obj == selectedLV) {
433 if (etype == QEvent::KeyPress) {
434 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
435 int const keyPressed = keyEvent->key();
436 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
437 // Delete or backspace key will delete current item
438 // ...with control modifier will clear the list
439 if (keyPressed == Qt::Key_Delete || keyPressed == Qt::Key_Backspace) {
440 if (keyModifiers == Qt::NoModifier && deletePB->isEnabled()) {
443 } else if (keyModifiers == Qt::ControlModifier) {
444 selectedModel->removeRows(0, selectedModel->rowCount());
447 return QObject::eventFilter(obj, event);
449 // Ctrl-Up activates upPB
450 else if (keyPressed == Qt::Key_Up) {
451 if (keyModifiers == Qt::ControlModifier) {
452 if (upPB->isEnabled())
458 // Ctrl-Down activates downPB
459 else if (keyPressed == Qt::Key_Down) {
460 if (keyModifiers == Qt::ControlModifier) {
461 if (downPB->isEnabled())
467 else if (keyPressed == Qt::Key_Left) {
468 focusAndHighlight(availableLV);
472 } else if (etype == QEvent::FocusIn) {
473 if (!selectedHasFocus_) {
474 selectedHasFocus_ = true;
480 return QObject::eventFilter(obj, event);
483 } // namespace frontend
486 #include "moc_GuiSelectionManager.cpp"