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(selectedLV->selectionModel(),
75 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
76 this, SLOT(selectedChanged(QItemSelection, QItemSelection)));
77 connect(selectedLV->itemDelegate(), SIGNAL(commitData(QWidget*)),
78 this, SLOT(selectedEdited()));
79 connect(addPB, SIGNAL(clicked()),
80 this, SLOT(addPB_clicked()));
81 connect(deletePB, SIGNAL(clicked()),
82 this, SLOT(deletePB_clicked()));
83 connect(upPB, SIGNAL(clicked()),
84 this, SLOT(upPB_clicked()));
85 connect(downPB, SIGNAL(clicked()),
86 this, SLOT(downPB_clicked()));
87 connect(availableLV, SIGNAL(doubleClicked(QModelIndex)),
88 this, SLOT(availableLV_doubleClicked(QModelIndex)));
90 availableLV->installEventFilter(this);
91 selectedLV->installEventFilter(this);
95 void GuiSelectionManager::update()
104 QModelIndex GuiSelectionManager::getSelectedIndex(int const c) const
106 QModelIndexList avail = availableLV->selectionModel()->selectedIndexes();
107 QModelIndexList sel = selectedLV->selectionModel()->selectedRows(c);
108 bool const have_avl = !avail.isEmpty();
109 bool const have_sel = !sel.isEmpty();
111 if (selectedFocused()) {
115 return avail.front();
117 else { // available has focus
119 return avail.front();
123 return QModelIndex();
127 void GuiSelectionManager::updateAddPB()
129 int const arows = availableModel->rowCount();
130 QModelIndexList const availSels =
131 availableLV->selectionModel()->selectedIndexes();
132 addPB->setEnabled(arows > 0 &&
133 !availSels.isEmpty() &&
134 !isSelected(availSels.first()));
138 void GuiSelectionManager::updateDelPB()
140 int const srows = selectedModel->rowCount();
142 deletePB->setEnabled(false);
145 QModelIndexList const selSels =
146 selectedLV->selectionModel()->selectedIndexes();
147 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
148 deletePB->setEnabled(sel_nr >= 0);
152 void GuiSelectionManager::updateUpPB()
154 int const srows = selectedModel->rowCount();
156 upPB->setEnabled(false);
159 QModelIndexList const selSels =
160 selectedLV->selectionModel()->selectedIndexes();
161 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
162 upPB->setEnabled(sel_nr > 0);
166 void GuiSelectionManager::updateDownPB()
168 int const srows = selectedModel->rowCount();
170 downPB->setEnabled(false);
173 QModelIndexList const selSels =
174 selectedLV->selectionModel()->selectedIndexes();
175 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
176 downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
180 bool GuiSelectionManager::isSelected(const QModelIndex & idx)
182 if (selectedModel->rowCount() == 0)
184 QVariant const & str = availableModel->data(idx, Qt::DisplayRole);
185 QModelIndexList qmil =
186 selectedModel->match(selectedModel->index(0, main_sel_col_),
187 Qt::DisplayRole, str, 1,
188 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchWrap));
189 return !qmil.empty();
193 void GuiSelectionManager::availableChanged(QItemSelection const & qis, QItemSelection const &)
195 QModelIndexList il = qis.indexes();
198 availableChanged(il.front(), QModelIndex());
202 void GuiSelectionManager::availableChanged(const QModelIndex & idx, const QModelIndex &)
207 selectedHasFocus_ = false;
212 void GuiSelectionManager::selectedChanged(QItemSelection const & qis, QItemSelection const &)
214 QModelIndexList il = qis.indexes();
217 selectedChanged(il.front(), QModelIndex());
221 void GuiSelectionManager::selectedChanged(const QModelIndex & idx, const QModelIndex &)
226 selectedHasFocus_ = true;
231 void GuiSelectionManager::selectedEdited()
237 bool GuiSelectionManager::insertRowToSelected(int i,
238 QMap<int, QVariant> const & itemData)
242 if (i > selectedModel->rowCount())
243 i = selectedModel->rowCount();
244 if (!selectedModel->insertRow(i))
246 return selectedModel->setItemData(selectedModel->index(i, main_sel_col_), itemData);
250 bool GuiSelectionManager::insertRowToSelected(int i, QMap<int, QMap<int, QVariant>> & qms)
254 if (i > selectedModel->rowCount())
255 i = selectedModel->rowCount();
256 if (!selectedModel->insertRow(i))
259 QMap<int, QMap<int, QVariant>>::const_iterator it = qms.constBegin();
260 for (; it != qms.constEnd(); ++it)
261 res &= selectedModel->setItemData(selectedModel->index(i, it.key()), it.value());
266 void GuiSelectionManager::addPB_clicked()
268 QModelIndexList selIdx =
269 availableLV->selectionModel()->selectedIndexes();
270 if (selIdx.isEmpty())
273 QModelIndex const idxToAdd = selIdx.first();
274 QModelIndex const idx = selectedLV->currentIndex();
275 int const srows = selectedModel->rowCount();
277 QMap<int, QVariant> qm = availableModel->itemData(idxToAdd);
278 insertRowToSelected(srows, qm);
280 selectionChanged(); //signal
283 selectedLV->setCurrentIndex(idx);
289 void GuiSelectionManager::deletePB_clicked()
291 QModelIndexList selIdx =
292 selectedLV->selectionModel()->selectedIndexes();
293 if (selIdx.isEmpty())
295 QModelIndex idx = selIdx.first();
296 selectedModel->removeRow(idx.row());
297 selectionChanged(); //signal
299 int nrows = selectedLV->model()->rowCount();
300 if (idx.row() == nrows) //was last item on list
301 idx = idx.sibling(idx.row() - 1, idx.column());
304 selectedLV->setCurrentIndex(idx);
306 selectedLV->setCurrentIndex(selectedLV->model()->index(0, 0));
307 selectedHasFocus_ = (nrows > 0);
312 void GuiSelectionManager::upPB_clicked()
314 QModelIndexList selIdx =
315 selectedLV->selectionModel()->selectedIndexes();
316 if (selIdx.isEmpty())
318 QModelIndex idx = selIdx.first();
320 int const pos = idx.row();
324 QMap<int, QMap<int, QVariant>> qms;
325 QList<QModelIndex>::const_iterator it = selIdx.constBegin();
326 for (; it != selIdx.constEnd(); ++it)
327 qms[it->column()] = selectedModel->itemData(*it);
329 selectedModel->removeRow(pos);
330 insertRowToSelected(pos - 1, qms);
332 selectionChanged(); //signal
334 selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column()));
335 selectedHasFocus_ = true;
340 void GuiSelectionManager::downPB_clicked()
342 QModelIndexList selIdx =
343 selectedLV->selectionModel()->selectedIndexes();
344 if (selIdx.isEmpty())
346 QModelIndex idx = selIdx.first();
348 int const pos = idx.row();
349 if (pos >= selectedModel->rowCount() - 1)
352 QMap<int, QMap<int, QVariant>> qms;
353 QList<QModelIndex>::const_iterator it = selIdx.constBegin();
354 for (; it != selIdx.constEnd(); ++it)
355 qms[it->column()] = selectedModel->itemData(*it);
357 selectedModel->removeRow(pos);
358 insertRowToSelected(pos + 1, qms);
360 selectionChanged(); //signal
362 selectedLV->setCurrentIndex(idx.sibling(idx.row() + 1, idx.column()));
363 selectedHasFocus_ = true;
368 void GuiSelectionManager::availableLV_doubleClicked(const QModelIndex & idx)
370 if (isSelected(idx) || !addPB->isEnabled())
374 selectedHasFocus_ = false;
376 //updateHook() will be emitted there
380 bool GuiSelectionManager::eventFilter(QObject * obj, QEvent * event)
382 QEvent::Type etype = event->type();
383 if (obj == availableLV) {
384 if (etype == QEvent::KeyPress) {
385 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
386 int const keyPressed = keyEvent->key();
387 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
388 // Enter key without modifier will add current item.
389 // Ctrl-Enter will add it and close the dialog.
390 // This is designed to work both with the main enter key
391 // and the one on the numeric keypad.
392 if (keyPressed == Qt::Key_Enter || keyPressed == Qt::Key_Return) {
394 keyModifiers == Qt::ControlModifier ||
395 keyModifiers == Qt::KeypadModifier ||
396 keyModifiers == (Qt::ControlModifier
397 | Qt::KeypadModifier)) {
398 if (addPB->isEnabled()) {
407 else if (keyPressed == Qt::Key_Right) {
408 focusAndHighlight(selectedLV);
412 } else if (etype == QEvent::FocusIn) {
413 if (selectedHasFocus_) {
414 selectedHasFocus_ = false;
419 } else if (obj == selectedLV) {
420 if (etype == QEvent::KeyPress) {
421 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
422 int const keyPressed = keyEvent->key();
423 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
424 // Delete or backspace key will delete current item
425 // ...with control modifier will clear the list
426 if (keyPressed == Qt::Key_Delete || keyPressed == Qt::Key_Backspace) {
427 if (keyModifiers == Qt::NoModifier && deletePB->isEnabled()) {
430 } else if (keyModifiers == Qt::ControlModifier) {
431 selectedModel->removeRows(0, selectedModel->rowCount());
434 return QObject::eventFilter(obj, event);
436 // Ctrl-Up activates upPB
437 else if (keyPressed == Qt::Key_Up) {
438 if (keyModifiers == Qt::ControlModifier) {
439 if (upPB->isEnabled())
445 // Ctrl-Down activates downPB
446 else if (keyPressed == Qt::Key_Down) {
447 if (keyModifiers == Qt::ControlModifier) {
448 if (downPB->isEnabled())
454 else if (keyPressed == Qt::Key_Left) {
455 focusAndHighlight(availableLV);
459 } else if (etype == QEvent::FocusIn) {
460 if (!selectedHasFocus_) {
461 selectedHasFocus_ = true;
467 return QObject::eventFilter(obj, event);
470 } // namespace frontend
473 #include "moc_GuiSelectionManager.cpp"