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(selectionChanged(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(doubleClicked(QModelIndex)),
82 this, SLOT(availableLV_doubleClicked(QModelIndex)));
84 availableLV->installEventFilter(this);
85 selectedLV->installEventFilter(this);
89 void GuiSelectionManager::update()
98 QModelIndex GuiSelectionManager::getSelectedIndex() const
100 QModelIndexList avail = availableLV->selectionModel()->selectedIndexes();
101 QModelIndexList sel = selectedLV->selectionModel()->selectedIndexes();
102 bool const have_avl = !avail.isEmpty();
103 bool const have_sel = !sel.isEmpty();
105 if (selectedFocused()) {
109 return avail.front();
111 else { // available has focus
113 return avail.front();
117 return QModelIndex();
121 void GuiSelectionManager::updateAddPB()
123 int const arows = availableModel->rowCount();
124 QModelIndexList const availSels =
125 availableLV->selectionModel()->selectedIndexes();
126 addPB->setEnabled(arows > 0 &&
127 !availSels.isEmpty() &&
128 !isSelected(availSels.first()));
132 void GuiSelectionManager::updateDelPB()
134 int const srows = selectedModel->rowCount();
136 deletePB->setEnabled(false);
139 QModelIndexList const selSels =
140 selectedLV->selectionModel()->selectedIndexes();
141 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
142 deletePB->setEnabled(sel_nr >= 0);
146 void GuiSelectionManager::updateUpPB()
148 int const srows = selectedModel->rowCount();
150 upPB->setEnabled(false);
153 QModelIndexList const selSels =
154 selectedLV->selectionModel()->selectedIndexes();
155 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
156 upPB->setEnabled(sel_nr > 0);
160 void GuiSelectionManager::updateDownPB()
162 int const srows = selectedModel->rowCount();
164 downPB->setEnabled(false);
167 QModelIndexList const selSels =
168 selectedLV->selectionModel()->selectedIndexes();
169 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
170 downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
174 bool GuiSelectionManager::isSelected(const QModelIndex & idx)
176 if (selectedModel->rowCount() == 0)
178 QVariant const & str = availableModel->data(idx, Qt::DisplayRole);
179 QModelIndexList qmil =
180 selectedModel->match(selectedModel->index(0),
181 Qt::DisplayRole, str, 1,
182 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchWrap));
183 return !qmil.empty();
187 void GuiSelectionManager::availableChanged(QItemSelection const & qis, QItemSelection const &)
189 QModelIndexList il = qis.indexes();
192 availableChanged(il.front(), QModelIndex());
196 void GuiSelectionManager::availableChanged(const QModelIndex & idx, const QModelIndex &)
201 selectedHasFocus_ = false;
206 void GuiSelectionManager::selectedChanged(QItemSelection const & qis, QItemSelection const &)
208 QModelIndexList il = qis.indexes();
211 selectedChanged(il.front(), QModelIndex());
215 void GuiSelectionManager::selectedChanged(const QModelIndex & idx, const QModelIndex &)
220 selectedHasFocus_ = true;
225 bool GuiSelectionManager::insertRowToSelected(int i,
226 QMap<int, QVariant> const & itemData)
230 if (i > selectedModel->rowCount())
231 i = selectedModel->rowCount();
232 if (!selectedModel->insertRow(i))
234 return selectedModel->setItemData(selectedModel->index(i), itemData);
238 void GuiSelectionManager::addPB_clicked()
240 QModelIndexList selIdx =
241 availableLV->selectionModel()->selectedIndexes();
242 if (selIdx.isEmpty())
245 QModelIndex const idxToAdd = selIdx.first();
246 QModelIndex const idx = selectedLV->currentIndex();
247 int const srows = selectedModel->rowCount();
249 QMap<int, QVariant> qm = availableModel->itemData(idxToAdd);
250 insertRowToSelected(srows, qm);
252 selectionChanged(); //signal
255 selectedLV->setCurrentIndex(idx);
261 void GuiSelectionManager::deletePB_clicked()
263 QModelIndexList selIdx =
264 selectedLV->selectionModel()->selectedIndexes();
265 if (selIdx.isEmpty())
267 QModelIndex idx = selIdx.first();
268 selectedModel->removeRow(idx.row());
269 selectionChanged(); //signal
271 int nrows = selectedLV->model()->rowCount();
272 if (idx.row() == nrows) //was last item on list
273 idx = idx.sibling(idx.row() - 1, idx.column());
276 selectedLV->setCurrentIndex(idx);
278 selectedLV->setCurrentIndex(selectedLV->model()->index(0, 0));
279 selectedHasFocus_ = (nrows > 0);
284 void GuiSelectionManager::upPB_clicked()
286 QModelIndexList selIdx =
287 selectedLV->selectionModel()->selectedIndexes();
288 if (selIdx.isEmpty())
290 QModelIndex idx = selIdx.first();
292 int const pos = idx.row();
296 QMap<int, QVariant> qm = selectedModel->itemData(idx);
298 selectedModel->removeRow(pos);
299 insertRowToSelected(pos - 1, qm);
301 selectionChanged(); //signal
303 selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column()));
304 selectedHasFocus_ = true;
309 void GuiSelectionManager::downPB_clicked()
311 QModelIndexList selIdx =
312 selectedLV->selectionModel()->selectedIndexes();
313 if (selIdx.isEmpty())
315 QModelIndex idx = selIdx.first();
317 int const pos = idx.row();
318 if (pos >= selectedModel->rowCount() - 1)
321 QMap<int, QVariant> qm = selectedModel->itemData(idx);
323 selectedModel->removeRow(pos);
324 insertRowToSelected(pos + 1, qm);
326 selectionChanged(); //signal
328 selectedLV->setCurrentIndex(idx.sibling(idx.row() + 1, idx.column()));
329 selectedHasFocus_ = true;
334 void GuiSelectionManager::availableLV_doubleClicked(const QModelIndex & idx)
336 if (isSelected(idx) || !addPB->isEnabled())
340 selectedHasFocus_ = false;
342 //updateHook() will be emitted there
346 bool GuiSelectionManager::eventFilter(QObject * obj, QEvent * event)
348 QEvent::Type etype = event->type();
349 if (obj == availableLV) {
350 if (etype == QEvent::KeyPress) {
351 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
352 int const keyPressed = keyEvent->key();
353 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
354 // Enter key without modifier will add current item.
355 // Ctrl-Enter will add it and close the dialog.
356 // This is designed to work both with the main enter key
357 // and the one on the numeric keypad.
358 if (keyPressed == Qt::Key_Enter || keyPressed == Qt::Key_Return) {
361 else if (keyModifiers == Qt::ControlModifier ||
362 keyModifiers == Qt::KeypadModifier ||
363 keyModifiers == (Qt::ControlModifier | Qt::KeypadModifier)) {
364 if (addPB->isEnabled()) {
372 } else if (etype == QEvent::FocusIn) {
373 if (selectedHasFocus_) {
374 selectedHasFocus_ = false;
380 } else if (obj == selectedLV) {
381 if (etype == QEvent::KeyPress) {
382 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
383 int const keyPressed = keyEvent->key();
384 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
385 // Delete or backspace key will delete current item
386 // ...with control modifier will clear the list
387 if (keyPressed == Qt::Key_Delete || keyPressed == Qt::Key_Backspace) {
388 if (keyModifiers == Qt::NoModifier && deletePB->isEnabled()) {
391 } else if (keyModifiers == Qt::ControlModifier) {
392 selectedModel->removeRows(0, selectedModel->rowCount());
395 return QObject::eventFilter(obj, event);
397 // Ctrl-Up activates upPB
398 else if (keyPressed == Qt::Key_Up) {
399 if (keyModifiers == Qt::ControlModifier) {
400 if (upPB->isEnabled())
406 // Ctrl-Down activates downPB
407 else if (keyPressed == Qt::Key_Down) {
408 if (keyModifiers == Qt::ControlModifier) {
409 if (downPB->isEnabled())
415 } else if (etype == QEvent::FocusIn) {
416 if (!selectedHasFocus_) {
417 selectedHasFocus_ = true;
424 return QObject::eventFilter(obj, event);
427 } // namespace frontend
430 #include "moc_GuiSelectionManager.cpp"