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 <QAbstractListModel>
20 #include <QItemSelection>
23 #include <QPushButton>
29 #ifdef ControlModifier
30 #undef ControlModifier
41 GuiSelectionManager::GuiSelectionManager(
42 QAbstractItemView * avail,
48 QAbstractListModel * amod,
49 QAbstractListModel * smod)
50 : availableLV(avail), selectedLV(sel), addPB(add), deletePB(del),
51 upPB(up), downPB(down), availableModel(amod), selectedModel(smod),
52 selectedHasFocus_(false)
55 selectedLV->setModel(smod);
56 availableLV->setModel(amod);
58 connect(availableLV->selectionModel(),
59 SIGNAL(currentChanged(QModelIndex, QModelIndex)),
60 this, SLOT(availableChanged(QModelIndex, QModelIndex)));
61 connect(selectedLV->selectionModel(),
62 SIGNAL(currentChanged(QModelIndex, QModelIndex)),
63 this, SLOT(selectedChanged(QModelIndex, QModelIndex)));
64 connect(availableLV->selectionModel(),
65 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
66 this, SLOT(availableChanged(QItemSelection, QItemSelection)));
67 connect(selectedLV->selectionModel(),
68 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
69 this, SLOT(selectedChanged(QItemSelection, QItemSelection)));
70 connect(addPB, SIGNAL(clicked()),
71 this, SLOT(addPB_clicked()));
72 connect(deletePB, SIGNAL(clicked()),
73 this, SLOT(deletePB_clicked()));
74 connect(upPB, SIGNAL(clicked()),
75 this, SLOT(upPB_clicked()));
76 connect(downPB, SIGNAL(clicked()),
77 this, SLOT(downPB_clicked()));
78 connect(availableLV, SIGNAL(doubleClicked(QModelIndex)),
79 this, SLOT(availableLV_doubleClicked(QModelIndex)));
81 availableLV->installEventFilter(this);
82 selectedLV->installEventFilter(this);
86 void GuiSelectionManager::update()
95 QModelIndex GuiSelectionManager::getSelectedIndex() const
97 QModelIndexList avail = availableLV->selectionModel()->selectedIndexes();
98 QModelIndexList sel = selectedLV->selectionModel()->selectedIndexes();
99 bool const have_avl = !avail.isEmpty();
100 bool const have_sel = !sel.isEmpty();
102 if (selectedFocused()) {
106 return avail.front();
108 else { // available has focus
110 return avail.front();
114 return QModelIndex();
118 void GuiSelectionManager::updateAddPB()
120 int const arows = availableModel->rowCount();
121 QModelIndexList const availSels =
122 availableLV->selectionModel()->selectedIndexes();
123 addPB->setEnabled(arows > 0 &&
124 !availSels.isEmpty() &&
125 !isSelected(availSels.first()));
129 void GuiSelectionManager::updateDelPB()
131 int const srows = selectedModel->rowCount();
133 deletePB->setEnabled(false);
136 QModelIndexList const selSels =
137 selectedLV->selectionModel()->selectedIndexes();
138 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
139 deletePB->setEnabled(sel_nr >= 0);
143 void GuiSelectionManager::updateUpPB()
145 int const srows = selectedModel->rowCount();
147 upPB->setEnabled(false);
150 QModelIndexList const selSels =
151 selectedLV->selectionModel()->selectedIndexes();
152 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
153 upPB->setEnabled(sel_nr > 0);
157 void GuiSelectionManager::updateDownPB()
159 int const srows = selectedModel->rowCount();
161 downPB->setEnabled(false);
164 QModelIndexList const selSels =
165 selectedLV->selectionModel()->selectedIndexes();
166 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
167 downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
171 bool GuiSelectionManager::isSelected(const QModelIndex & idx)
173 if (selectedModel->rowCount() == 0)
175 QVariant const & str = availableModel->data(idx, Qt::DisplayRole);
176 QModelIndexList qmil =
177 selectedModel->match(selectedModel->index(0),
178 Qt::DisplayRole, str, 1,
179 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchWrap));
180 return !qmil.empty();
184 void GuiSelectionManager::availableChanged(QItemSelection const & qis, QItemSelection const &)
186 QModelIndexList il = qis.indexes();
189 availableChanged(il.front(), QModelIndex());
193 void GuiSelectionManager::availableChanged(const QModelIndex & idx, const QModelIndex &)
198 selectedHasFocus_ = false;
203 void GuiSelectionManager::selectedChanged(QItemSelection const & qis, QItemSelection const &)
205 QModelIndexList il = qis.indexes();
208 selectedChanged(il.front(), QModelIndex());
212 void GuiSelectionManager::selectedChanged(const QModelIndex & idx, const QModelIndex &)
217 selectedHasFocus_ = true;
222 bool GuiSelectionManager::insertRowToSelected(int i,
223 QMap<int, QVariant> const & itemData)
227 if (i > selectedModel->rowCount())
228 i = selectedModel->rowCount();
229 if (!selectedModel->insertRow(i))
231 return selectedModel->setItemData(selectedModel->index(i), itemData);
235 void GuiSelectionManager::addPB_clicked()
237 QModelIndexList selIdx =
238 availableLV->selectionModel()->selectedIndexes();
239 if (selIdx.isEmpty())
242 QModelIndex const idxToAdd = selIdx.first();
243 QModelIndex const idx = selectedLV->currentIndex();
244 int const srows = selectedModel->rowCount();
246 QMap<int, QVariant> qm = availableModel->itemData(idxToAdd);
247 insertRowToSelected(srows, qm);
249 selectionChanged(); //signal
252 selectedLV->setCurrentIndex(idx);
258 void GuiSelectionManager::deletePB_clicked()
260 QModelIndexList selIdx =
261 selectedLV->selectionModel()->selectedIndexes();
262 if (selIdx.isEmpty())
264 QModelIndex idx = selIdx.first();
265 selectedModel->removeRow(idx.row());
266 selectionChanged(); //signal
268 int nrows = selectedLV->model()->rowCount();
269 if (idx.row() == nrows) //was last item on list
270 idx = idx.sibling(idx.row() - 1, idx.column());
273 selectedLV->setCurrentIndex(idx);
275 selectedLV->setCurrentIndex(selectedLV->model()->index(0, 0));
276 selectedHasFocus_ = (nrows > 0);
281 void GuiSelectionManager::upPB_clicked()
283 QModelIndexList selIdx =
284 selectedLV->selectionModel()->selectedIndexes();
285 if (selIdx.isEmpty())
287 QModelIndex idx = selIdx.first();
289 int const pos = idx.row();
293 QMap<int, QVariant> qm = selectedModel->itemData(idx);
295 selectedModel->removeRow(pos);
296 insertRowToSelected(pos - 1, qm);
298 selectionChanged(); //signal
300 selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column()));
301 selectedHasFocus_ = true;
306 void GuiSelectionManager::downPB_clicked()
308 QModelIndexList selIdx =
309 selectedLV->selectionModel()->selectedIndexes();
310 if (selIdx.isEmpty())
312 QModelIndex idx = selIdx.first();
314 int const pos = idx.row();
315 if (pos >= selectedModel->rowCount() - 1)
318 QMap<int, QVariant> qm = selectedModel->itemData(idx);
320 selectedModel->removeRow(pos);
321 insertRowToSelected(pos + 1, qm);
323 selectionChanged(); //signal
325 selectedLV->setCurrentIndex(idx.sibling(idx.row() + 1, idx.column()));
326 selectedHasFocus_ = true;
331 void GuiSelectionManager::availableLV_doubleClicked(const QModelIndex & idx)
333 if (isSelected(idx) || !addPB->isEnabled())
337 selectedHasFocus_ = false;
339 //updateHook() will be emitted there
343 bool GuiSelectionManager::eventFilter(QObject * obj, QEvent * event)
345 QEvent::Type etype = event->type();
346 if (obj == availableLV) {
347 if (etype == QEvent::KeyPress) {
348 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
349 int const keyPressed = keyEvent->key();
350 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
351 // Enter key without modifier will add current item.
352 // Ctrl-Enter will add it and close the dialog.
353 // This is designed to work both with the main enter key
354 // and the one on the numeric keypad.
355 if (keyPressed == Qt::Key_Enter || keyPressed == Qt::Key_Return) {
356 if (addPB->isEnabled()) {
359 } else if (keyModifiers == Qt::ControlModifier ||
360 keyModifiers == Qt::KeypadModifier ||
361 keyModifiers == (Qt::ControlModifier | Qt::KeypadModifier)) {
369 } else if (etype == QEvent::FocusIn) {
370 if (selectedHasFocus_) {
371 selectedHasFocus_ = false;
377 } else if (obj == selectedLV) {
378 if (etype == QEvent::KeyPress) {
379 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
380 int const keyPressed = keyEvent->key();
381 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
382 // Delete or backspace key will delete current item
383 // ...with control modifier will clear the list
384 if (keyPressed == Qt::Key_Delete || keyPressed == Qt::Key_Backspace) {
385 if (keyModifiers == Qt::NoModifier && deletePB->isEnabled()) {
388 } else if (keyModifiers == Qt::ControlModifier) {
389 selectedModel->removeRows(0, selectedModel->rowCount());
392 return QObject::eventFilter(obj, event);
394 // Ctrl-Up activates upPB
395 else if (keyPressed == Qt::Key_Up) {
396 if (keyModifiers == Qt::ControlModifier) {
397 if (upPB->isEnabled())
403 // Ctrl-Down activates downPB
404 else if (keyPressed == Qt::Key_Down) {
405 if (keyModifiers == Qt::ControlModifier) {
406 if (downPB->isEnabled())
412 } else if (etype == QEvent::FocusIn) {
413 if (!selectedHasFocus_) {
414 selectedHasFocus_ = true;
421 return QObject::eventFilter(obj, event);
424 } // namespace frontend
427 #include "moc_GuiSelectionManager.cpp"