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"
19 #include "support/debug.h"
21 #include <QAbstractItemModel>
22 #include <QAbstractListModel>
23 #include <QItemSelection>
26 #include <QPushButton>
32 #ifdef ControlModifier
33 #undef ControlModifier
44 GuiSelectionManager::GuiSelectionManager(QObject * parent,
45 QAbstractItemView * avail,
46 QAbstractItemView * sel,
51 QAbstractListModel * amod,
52 QAbstractItemModel * smod,
53 int const main_sel_col)
54 : QObject(parent), availableLV(avail), selectedLV(sel),
55 addPB(add), deletePB(del), upPB(up), downPB(down),
56 availableModel(amod), selectedModel(smod),
57 selectedHasFocus_(false), main_sel_col_(main_sel_col)
59 selectedLV->setModel(smod);
60 availableLV->setModel(amod);
61 selectedLV->setSelectionBehavior(QAbstractItemView::SelectRows);
62 selectedLV->setSelectionMode(QAbstractItemView::SingleSelection);
64 connect(availableLV->selectionModel(),
65 SIGNAL(currentChanged(QModelIndex, QModelIndex)),
66 this, SLOT(availableChanged(QModelIndex, QModelIndex)));
67 connect(selectedLV->selectionModel(),
68 SIGNAL(currentChanged(QModelIndex, QModelIndex)),
69 this, SLOT(selectedChanged(QModelIndex, QModelIndex)));
70 connect(availableLV->selectionModel(),
71 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
72 this, SLOT(availableChanged(QItemSelection, QItemSelection)));
73 connect(selectedLV->selectionModel(),
74 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
75 this, SLOT(selectedChanged(QItemSelection, QItemSelection)));
76 connect(selectedLV->itemDelegate(), SIGNAL(commitData(QWidget*)),
77 this, SLOT(selectedEdited()));
78 connect(addPB, SIGNAL(clicked()),
79 this, SLOT(addPB_clicked()));
80 connect(deletePB, SIGNAL(clicked()),
81 this, SLOT(deletePB_clicked()));
82 connect(upPB, SIGNAL(clicked()),
83 this, SLOT(upPB_clicked()));
84 connect(downPB, SIGNAL(clicked()),
85 this, SLOT(downPB_clicked()));
86 connect(availableLV, SIGNAL(doubleClicked(QModelIndex)),
87 this, SLOT(availableLV_doubleClicked(QModelIndex)));
89 availableLV->installEventFilter(this);
90 selectedLV->installEventFilter(this);
94 void GuiSelectionManager::update()
103 QModelIndex GuiSelectionManager::getSelectedIndex(int const c) const
105 QModelIndexList avail = availableLV->selectionModel()->selectedIndexes();
106 QModelIndexList sel = selectedLV->selectionModel()->selectedRows(c);
107 bool const have_avl = !avail.isEmpty();
108 bool const have_sel = !sel.isEmpty();
110 if (selectedFocused()) {
114 return avail.front();
116 else { // available has focus
118 return avail.front();
122 return QModelIndex();
126 void GuiSelectionManager::updateAddPB()
128 int const arows = availableModel->rowCount();
129 QModelIndexList const availSels =
130 availableLV->selectionModel()->selectedIndexes();
131 addPB->setEnabled(arows > 0 &&
132 !availSels.isEmpty() &&
133 !isSelected(availSels.first()));
137 void GuiSelectionManager::updateDelPB()
139 int const srows = selectedModel->rowCount();
141 deletePB->setEnabled(false);
144 QModelIndexList const selSels =
145 selectedLV->selectionModel()->selectedIndexes();
146 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
147 deletePB->setEnabled(sel_nr >= 0);
151 void GuiSelectionManager::updateUpPB()
153 int const srows = selectedModel->rowCount();
155 upPB->setEnabled(false);
158 QModelIndexList const selSels =
159 selectedLV->selectionModel()->selectedIndexes();
160 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
161 upPB->setEnabled(sel_nr > 0);
165 void GuiSelectionManager::updateDownPB()
167 int const srows = selectedModel->rowCount();
169 downPB->setEnabled(false);
172 QModelIndexList const selSels =
173 selectedLV->selectionModel()->selectedIndexes();
174 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
175 downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
179 bool GuiSelectionManager::isSelected(const QModelIndex & idx)
181 if (selectedModel->rowCount() == 0)
183 QVariant const & str = availableModel->data(idx, Qt::DisplayRole);
184 QModelIndexList qmil =
185 selectedModel->match(selectedModel->index(0, main_sel_col_),
186 Qt::DisplayRole, str, 1,
187 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchWrap));
188 return !qmil.empty();
192 void GuiSelectionManager::availableChanged(QItemSelection const & qis, QItemSelection const &)
194 QModelIndexList il = qis.indexes();
197 availableChanged(il.front(), QModelIndex());
201 void GuiSelectionManager::availableChanged(const QModelIndex & idx, const QModelIndex &)
206 selectedHasFocus_ = false;
211 void GuiSelectionManager::selectedChanged(QItemSelection const & qis, QItemSelection const &)
213 QModelIndexList il = qis.indexes();
216 selectedChanged(il.front(), QModelIndex());
220 void GuiSelectionManager::selectedChanged(const QModelIndex & idx, const QModelIndex &)
225 selectedHasFocus_ = true;
230 void GuiSelectionManager::selectedEdited()
236 bool GuiSelectionManager::insertRowToSelected(int i,
237 QMap<int, QVariant> const & itemData)
241 if (i > selectedModel->rowCount())
242 i = selectedModel->rowCount();
243 if (!selectedModel->insertRow(i))
245 return selectedModel->setItemData(selectedModel->index(i, main_sel_col_), itemData);
249 bool GuiSelectionManager::insertRowToSelected(int i, QMap<int, QMap<int, QVariant>> & qms)
253 if (i > selectedModel->rowCount())
254 i = selectedModel->rowCount();
255 if (!selectedModel->insertRow(i))
258 QMap<int, QMap<int, QVariant>>::const_iterator it = qms.constBegin();
259 for (; it != qms.constEnd(); ++it)
260 res &= selectedModel->setItemData(selectedModel->index(i, it.key()), it.value());
265 void GuiSelectionManager::addPB_clicked()
267 QModelIndexList selIdx =
268 availableLV->selectionModel()->selectedIndexes();
269 if (selIdx.isEmpty())
272 QModelIndex const idxToAdd = selIdx.first();
273 QModelIndex const idx = selectedLV->currentIndex();
274 int const srows = selectedModel->rowCount();
276 QMap<int, QVariant> qm = availableModel->itemData(idxToAdd);
277 insertRowToSelected(srows, qm);
279 selectionChanged(); //signal
282 selectedLV->setCurrentIndex(idx);
288 void GuiSelectionManager::deletePB_clicked()
290 QModelIndexList selIdx =
291 selectedLV->selectionModel()->selectedIndexes();
292 if (selIdx.isEmpty())
294 QModelIndex idx = selIdx.first();
295 selectedModel->removeRow(idx.row());
296 selectionChanged(); //signal
298 int nrows = selectedLV->model()->rowCount();
299 if (idx.row() == nrows) //was last item on list
300 idx = idx.sibling(idx.row() - 1, idx.column());
303 selectedLV->setCurrentIndex(idx);
305 selectedLV->setCurrentIndex(selectedLV->model()->index(0, 0));
306 selectedHasFocus_ = (nrows > 0);
311 void GuiSelectionManager::upPB_clicked()
313 QModelIndexList selIdx =
314 selectedLV->selectionModel()->selectedIndexes();
315 if (selIdx.isEmpty())
317 QModelIndex idx = selIdx.first();
319 int const pos = idx.row();
323 QMap<int, QMap<int, QVariant>> qms;
324 QList<QModelIndex>::const_iterator it = selIdx.constBegin();
325 for (; it != selIdx.constEnd(); ++it)
326 qms[it->column()] = selectedModel->itemData(*it);
328 selectedModel->removeRow(pos);
329 insertRowToSelected(pos - 1, qms);
331 selectionChanged(); //signal
333 selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column()));
334 selectedHasFocus_ = true;
339 void GuiSelectionManager::downPB_clicked()
341 QModelIndexList selIdx =
342 selectedLV->selectionModel()->selectedIndexes();
343 if (selIdx.isEmpty())
345 QModelIndex idx = selIdx.first();
347 int const pos = idx.row();
348 if (pos >= selectedModel->rowCount() - 1)
351 QMap<int, QMap<int, QVariant>> qms;
352 QList<QModelIndex>::const_iterator it = selIdx.constBegin();
353 for (; it != selIdx.constEnd(); ++it)
354 qms[it->column()] = selectedModel->itemData(*it);
356 selectedModel->removeRow(pos);
357 insertRowToSelected(pos + 1, qms);
359 selectionChanged(); //signal
361 selectedLV->setCurrentIndex(idx.sibling(idx.row() + 1, idx.column()));
362 selectedHasFocus_ = true;
367 void GuiSelectionManager::availableLV_doubleClicked(const QModelIndex & idx)
369 if (isSelected(idx) || !addPB->isEnabled())
373 selectedHasFocus_ = false;
375 //updateHook() will be emitted there
379 bool GuiSelectionManager::eventFilter(QObject * obj, QEvent * event)
381 QEvent::Type etype = event->type();
382 if (obj == availableLV) {
383 if (etype == QEvent::KeyPress) {
384 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
385 int const keyPressed = keyEvent->key();
386 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
387 // Enter key without modifier will add current item.
388 // Ctrl-Enter will add it and close the dialog.
389 // This is designed to work both with the main enter key
390 // and the one on the numeric keypad.
391 if (keyPressed == Qt::Key_Enter || keyPressed == Qt::Key_Return) {
392 if (addPB->isEnabled()) {
395 } else if (keyModifiers == Qt::ControlModifier ||
396 keyModifiers == Qt::KeypadModifier ||
397 keyModifiers == (Qt::ControlModifier | Qt::KeypadModifier)) {
405 } else if (etype == QEvent::FocusIn) {
406 if (selectedHasFocus_) {
407 selectedHasFocus_ = false;
413 } else if (obj == selectedLV) {
414 if (etype == QEvent::KeyPress) {
415 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
416 int const keyPressed = keyEvent->key();
417 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
418 // Delete or backspace key will delete current item
419 // ...with control modifier will clear the list
420 if (keyPressed == Qt::Key_Delete || keyPressed == Qt::Key_Backspace) {
421 if (keyModifiers == Qt::NoModifier && deletePB->isEnabled()) {
424 } else if (keyModifiers == Qt::ControlModifier) {
425 selectedModel->removeRows(0, selectedModel->rowCount());
428 return QObject::eventFilter(obj, event);
430 // Ctrl-Up activates upPB
431 else if (keyPressed == Qt::Key_Up) {
432 if (keyModifiers == Qt::ControlModifier) {
433 if (upPB->isEnabled())
439 // Ctrl-Down activates downPB
440 else if (keyPressed == Qt::Key_Down) {
441 if (keyModifiers == Qt::ControlModifier) {
442 if (downPB->isEnabled())
448 } else if (etype == QEvent::FocusIn) {
449 if (!selectedHasFocus_) {
450 selectedHasFocus_ = true;
457 return QObject::eventFilter(obj, event);
460 } // namespace frontend
463 #include "moc_GuiSelectionManager.cpp"