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 <QAbstractListModel>
22 #include <QItemSelection>
25 #include <QPushButton>
31 #ifdef ControlModifier
32 #undef ControlModifier
39 GuiSelectionManager::GuiSelectionManager(
40 QAbstractItemView * avail,
46 QAbstractListModel * amod,
47 QAbstractListModel * smod)
55 availableModel = amod;
58 selectedLV->setModel(smod);
59 availableLV->setModel(amod);
61 connect(availableLV->selectionModel(),
62 SIGNAL(currentChanged(QModelIndex, QModelIndex)),
63 this, SLOT(availableChanged(QModelIndex, QModelIndex)));
64 connect(selectedLV->selectionModel(),
65 SIGNAL(currentChanged(QModelIndex, QModelIndex)),
66 this, SLOT(selectedChanged(QModelIndex, QModelIndex)));
67 connect(availableLV->selectionModel(),
68 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
69 this, SLOT(availableChanged(QItemSelection, QItemSelection)));
70 connect(selectedLV->selectionModel(),
71 SIGNAL(currentChanged(QItemSelection, QItemSelection)),
72 this, SLOT(selectedChanged(QItemSelection, QItemSelection)));
73 connect(addPB, SIGNAL(clicked()),
74 this, SLOT(addPB_clicked()));
75 connect(deletePB, SIGNAL(clicked()),
76 this, SLOT(deletePB_clicked()));
77 connect(upPB, SIGNAL(clicked()),
78 this, SLOT(upPB_clicked()));
79 connect(downPB, SIGNAL(clicked()),
80 this, SLOT(downPB_clicked()));
81 connect(availableLV, SIGNAL(clicked(QModelIndex)),
82 this, SLOT(availableLV_clicked(QModelIndex)));
83 connect(availableLV, SIGNAL(doubleClicked(QModelIndex)),
84 this, SLOT(availableLV_doubleClicked(QModelIndex)));
85 connect(selectedLV, SIGNAL(clicked(QModelIndex)),
86 this, SLOT(selectedLV_clicked(QModelIndex)));
88 availableLV->installEventFilter(this);
89 selectedLV->installEventFilter(this);
93 void GuiSelectionManager::update()
102 QModelIndex GuiSelectionManager::getSelectedIndex() const
104 QModelIndexList avail = availableLV->selectionModel()->selectedIndexes();
105 QModelIndexList sel = selectedLV->selectionModel()->selectedIndexes();
106 bool const have_avl = !avail.isEmpty();
107 bool const have_sel = !sel.isEmpty();
109 if (selectedFocused()) {
113 return avail.front();
115 else { // available has focus
117 return avail.front();
121 return QModelIndex();
125 void GuiSelectionManager::updateAddPB()
127 int const arows = availableModel->rowCount();
128 QModelIndexList const availSels =
129 availableLV->selectionModel()->selectedIndexes();
130 addPB->setEnabled(arows > 0 &&
131 !availSels.isEmpty() &&
132 !isSelected(availSels.first()));
136 void GuiSelectionManager::updateDelPB()
138 int const srows = selectedModel->rowCount();
140 deletePB->setEnabled(false);
143 QModelIndexList const selSels =
144 selectedLV->selectionModel()->selectedIndexes();
145 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
146 deletePB->setEnabled(sel_nr >= 0);
150 void GuiSelectionManager::updateUpPB()
152 int const srows = selectedModel->rowCount();
154 upPB->setEnabled(false);
157 QModelIndexList const selSels =
158 selectedLV->selectionModel()->selectedIndexes();
159 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
160 upPB->setEnabled(sel_nr > 0);
164 void GuiSelectionManager::updateDownPB()
166 int const srows = selectedModel->rowCount();
168 downPB->setEnabled(false);
171 QModelIndexList const selSels =
172 selectedLV->selectionModel()->selectedIndexes();
173 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
174 downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
178 bool GuiSelectionManager::isSelected(const QModelIndex & idx)
180 if (selectedModel->rowCount() == 0)
182 QVariant const & str = availableModel->data(idx, Qt::DisplayRole);
183 QModelIndexList qmil =
184 selectedModel->match(selectedModel->index(0),
185 Qt::DisplayRole, str, 1,
186 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchWrap));
187 return !qmil.empty();
191 void GuiSelectionManager::availableChanged(QItemSelection const & qis, QItemSelection const &)
193 QModelIndexList il = qis.indexes();
196 availableChanged(il.front(), QModelIndex());
200 void GuiSelectionManager::availableChanged(const QModelIndex & idx, const QModelIndex &)
205 selectedHasFocus_ = false;
210 void GuiSelectionManager::selectedChanged(QItemSelection const & qis, QItemSelection const &)
212 QModelIndexList il = qis.indexes();
215 selectedChanged(il.front(), QModelIndex());
219 void GuiSelectionManager::selectedChanged(const QModelIndex & idx, const QModelIndex &)
224 selectedHasFocus_ = true;
229 bool GuiSelectionManager::insertRowToSelected(int i,
230 QMap<int, QVariant> const & itemData)
232 if (i <= -1 || i > selectedModel->rowCount())
234 if (!selectedModel->insertRow(i))
236 return selectedModel->setItemData(selectedModel->index(i), itemData);
240 void GuiSelectionManager::addPB_clicked()
242 QModelIndexList selIdx =
243 availableLV->selectionModel()->selectedIndexes();
244 if (selIdx.isEmpty())
247 QModelIndex const idxToAdd = selIdx.first();
248 QModelIndex const idx = selectedLV->currentIndex();
249 int const srows = selectedModel->rowCount();
251 QMap<int, QVariant> qm = availableModel->itemData(idxToAdd);
252 insertRowToSelected(srows, qm);
254 selectionChanged(); //signal
257 selectedLV->setCurrentIndex(idx);
263 void GuiSelectionManager::deletePB_clicked()
265 QModelIndexList selIdx =
266 selectedLV->selectionModel()->selectedIndexes();
267 if (selIdx.isEmpty())
269 QModelIndex idx = selIdx.first();
270 selectedModel->removeRow(idx.row());
271 selectionChanged(); //signal
273 int nrows = selectedLV->model()->rowCount();
274 if (idx.row() == nrows) //was last item on list
275 idx = idx.sibling(idx.row() - 1, idx.column());
278 selectedLV->setCurrentIndex(idx);
280 selectedLV->setCurrentIndex(selectedLV->model()->index(0, 0));
281 selectedHasFocus_ = (nrows > 0);
286 void GuiSelectionManager::upPB_clicked()
288 QModelIndex idx = selectedLV->currentIndex();
290 int const pos = idx.row();
294 QMap<int, QVariant> qm = selectedModel->itemData(idx);
296 selectedModel->removeRow(pos);
297 insertRowToSelected(pos - 1, qm);
299 selectionChanged(); //signal
301 selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column()));
302 selectedHasFocus_ = true;
307 void GuiSelectionManager::downPB_clicked()
309 QModelIndex idx = selectedLV->currentIndex();
311 int const pos = idx.row();
312 if (pos >= selectedModel->rowCount() - 1)
315 QMap<int, QVariant> qm = selectedModel->itemData(idx);
317 selectedModel->removeRow(pos);
318 insertRowToSelected(pos + 1, qm);
320 selectionChanged(); //signal
322 selectedLV->setCurrentIndex(idx.sibling(idx.row() + 1, idx.column()));
323 selectedHasFocus_ = true;
328 // FIXME These slots do not really do what they need to do, since focus
329 // can enter the QListView in other ways. But there are no signals sent
330 // in that case. We need to reimplement focusInEvent() to capture those,
331 // which means subclassing QListView. (rgh)
332 // Or by installing an event listener.. (andre)
333 void GuiSelectionManager::availableLV_clicked(const QModelIndex &)
335 selectedHasFocus_ = false;
340 void GuiSelectionManager::availableLV_doubleClicked(const QModelIndex & idx)
342 if (isSelected(idx) || !addPB->isEnabled())
346 selectedHasFocus_ = false;
348 //updateHook() will be emitted there
352 void GuiSelectionManager::selectedLV_clicked(const QModelIndex &)
354 selectedHasFocus_ = true;
359 bool GuiSelectionManager::eventFilter(QObject * obj, QEvent * event)
361 if (obj == availableLV) {
362 if (event->type() != QEvent::KeyPress)
363 return QObject::eventFilter(obj, event);
364 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
365 int const keyPressed = keyEvent->key();
366 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
367 // Enter key without modifier will add current item.
368 // Ctrl-Enter will add it and close the dialog.
369 // This is designed to work both with the main enter key
370 // and the one on the numeric keypad.
371 if (keyPressed == Qt::Key_Enter || keyPressed == Qt::Key_Return) {
374 else if (keyModifiers == Qt::ControlModifier ||
375 keyModifiers == Qt::KeypadModifier ||
376 keyModifiers == (Qt::ControlModifier | Qt::KeypadModifier)) {
377 if (addPB->isEnabled()) {
385 } else if (obj == selectedLV) {
386 if (event->type() != QEvent::KeyPress)
387 return QObject::eventFilter(obj, event);
388 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
389 int const keyPressed = keyEvent->key();
390 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
391 // Delete or backspace key will delete current item
392 // ...with control modifier will clear the list
393 if (keyPressed == Qt::Key_Delete || keyPressed == Qt::Key_Backspace) {
394 if (keyModifiers == Qt::NoModifier && deletePB->isEnabled()) {
397 } else if (keyModifiers == Qt::ControlModifier) {
398 selectedModel->removeRows(0, selectedModel->rowCount());
401 return QObject::eventFilter(obj, event);
403 // Ctrl-Up activates upPB
404 else if (keyPressed == Qt::Key_Up) {
405 if (keyModifiers == Qt::ControlModifier) {
406 if (upPB->isEnabled())
412 // Ctrl-Down activates downPB
413 else if (keyPressed == Qt::Key_Down) {
414 if (keyModifiers == Qt::ControlModifier) {
415 if (downPB->isEnabled())
422 return QObject::eventFilter(obj, event);
425 } // namespace frontend
428 #include "moc_GuiSelectionManager.cpp"