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
43 GuiSelectionManager::GuiSelectionManager(
44 QAbstractItemView * avail,
50 QAbstractListModel * amod,
51 QAbstractListModel * smod)
52 : availableLV(avail), selectedLV(sel), addPB(add), deletePB(del),
53 upPB(up), downPB(down), availableModel(amod), selectedModel(smod),
54 selectedHasFocus_(false)
57 selectedLV->setModel(smod);
58 availableLV->setModel(amod);
60 connect(availableLV->selectionModel(),
61 SIGNAL(currentChanged(QModelIndex, QModelIndex)),
62 this, SLOT(availableChanged(QModelIndex, QModelIndex)));
63 connect(selectedLV->selectionModel(),
64 SIGNAL(currentChanged(QModelIndex, QModelIndex)),
65 this, SLOT(selectedChanged(QModelIndex, QModelIndex)));
66 connect(availableLV->selectionModel(),
67 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
68 this, SLOT(availableChanged(QItemSelection, QItemSelection)));
69 connect(selectedLV->selectionModel(),
70 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
71 this, SLOT(selectedChanged(QItemSelection, QItemSelection)));
72 connect(addPB, SIGNAL(clicked()),
73 this, SLOT(addPB_clicked()));
74 connect(deletePB, SIGNAL(clicked()),
75 this, SLOT(deletePB_clicked()));
76 connect(upPB, SIGNAL(clicked()),
77 this, SLOT(upPB_clicked()));
78 connect(downPB, SIGNAL(clicked()),
79 this, SLOT(downPB_clicked()));
80 connect(availableLV, SIGNAL(doubleClicked(QModelIndex)),
81 this, SLOT(availableLV_doubleClicked(QModelIndex)));
83 availableLV->installEventFilter(this);
84 selectedLV->installEventFilter(this);
88 void GuiSelectionManager::update()
97 QModelIndex GuiSelectionManager::getSelectedIndex() const
99 QModelIndexList avail = availableLV->selectionModel()->selectedIndexes();
100 QModelIndexList sel = selectedLV->selectionModel()->selectedIndexes();
101 bool const have_avl = !avail.isEmpty();
102 bool const have_sel = !sel.isEmpty();
104 if (selectedFocused()) {
108 return avail.front();
110 else { // available has focus
112 return avail.front();
116 return QModelIndex();
120 void GuiSelectionManager::updateAddPB()
122 int const arows = availableModel->rowCount();
123 QModelIndexList const availSels =
124 availableLV->selectionModel()->selectedIndexes();
125 addPB->setEnabled(arows > 0 &&
126 !availSels.isEmpty() &&
127 !isSelected(availSels.first()));
131 void GuiSelectionManager::updateDelPB()
133 int const srows = selectedModel->rowCount();
135 deletePB->setEnabled(false);
138 QModelIndexList const selSels =
139 selectedLV->selectionModel()->selectedIndexes();
140 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
141 deletePB->setEnabled(sel_nr >= 0);
145 void GuiSelectionManager::updateUpPB()
147 int const srows = selectedModel->rowCount();
149 upPB->setEnabled(false);
152 QModelIndexList const selSels =
153 selectedLV->selectionModel()->selectedIndexes();
154 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
155 upPB->setEnabled(sel_nr > 0);
159 void GuiSelectionManager::updateDownPB()
161 int const srows = selectedModel->rowCount();
163 downPB->setEnabled(false);
166 QModelIndexList const selSels =
167 selectedLV->selectionModel()->selectedIndexes();
168 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
169 downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
173 bool GuiSelectionManager::isSelected(const QModelIndex & idx)
175 if (selectedModel->rowCount() == 0)
177 QVariant const & str = availableModel->data(idx, Qt::DisplayRole);
178 QModelIndexList qmil =
179 selectedModel->match(selectedModel->index(0),
180 Qt::DisplayRole, str, 1,
181 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchWrap));
182 return !qmil.empty();
186 void GuiSelectionManager::availableChanged(QItemSelection const & qis, QItemSelection const &)
188 QModelIndexList il = qis.indexes();
191 availableChanged(il.front(), QModelIndex());
195 void GuiSelectionManager::availableChanged(const QModelIndex & idx, const QModelIndex &)
200 selectedHasFocus_ = false;
205 void GuiSelectionManager::selectedChanged(QItemSelection const & qis, QItemSelection const &)
207 QModelIndexList il = qis.indexes();
210 selectedChanged(il.front(), QModelIndex());
214 void GuiSelectionManager::selectedChanged(const QModelIndex & idx, const QModelIndex &)
219 selectedHasFocus_ = true;
224 bool GuiSelectionManager::insertRowToSelected(int i,
225 QMap<int, QVariant> const & itemData)
229 if (i > selectedModel->rowCount())
230 i = selectedModel->rowCount();
231 if (!selectedModel->insertRow(i))
233 return selectedModel->setItemData(selectedModel->index(i), itemData);
237 void GuiSelectionManager::addPB_clicked()
239 QModelIndexList selIdx =
240 availableLV->selectionModel()->selectedIndexes();
241 if (selIdx.isEmpty())
244 QModelIndex const idxToAdd = selIdx.first();
245 QModelIndex const idx = selectedLV->currentIndex();
246 int const srows = selectedModel->rowCount();
248 QMap<int, QVariant> qm = availableModel->itemData(idxToAdd);
249 insertRowToSelected(srows, qm);
251 selectionChanged(); //signal
254 selectedLV->setCurrentIndex(idx);
260 void GuiSelectionManager::deletePB_clicked()
262 QModelIndexList selIdx =
263 selectedLV->selectionModel()->selectedIndexes();
264 if (selIdx.isEmpty())
266 QModelIndex idx = selIdx.first();
267 selectedModel->removeRow(idx.row());
268 selectionChanged(); //signal
270 int nrows = selectedLV->model()->rowCount();
271 if (idx.row() == nrows) //was last item on list
272 idx = idx.sibling(idx.row() - 1, idx.column());
275 selectedLV->setCurrentIndex(idx);
277 selectedLV->setCurrentIndex(selectedLV->model()->index(0, 0));
278 selectedHasFocus_ = (nrows > 0);
283 void GuiSelectionManager::upPB_clicked()
285 QModelIndexList selIdx =
286 selectedLV->selectionModel()->selectedIndexes();
287 if (selIdx.isEmpty())
289 QModelIndex idx = selIdx.first();
291 int const pos = idx.row();
295 QMap<int, QVariant> qm = selectedModel->itemData(idx);
297 selectedModel->removeRow(pos);
298 insertRowToSelected(pos - 1, qm);
300 selectionChanged(); //signal
302 selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column()));
303 selectedHasFocus_ = true;
308 void GuiSelectionManager::downPB_clicked()
310 QModelIndexList selIdx =
311 selectedLV->selectionModel()->selectedIndexes();
312 if (selIdx.isEmpty())
314 QModelIndex idx = selIdx.first();
316 int const pos = idx.row();
317 if (pos >= selectedModel->rowCount() - 1)
320 QMap<int, QVariant> qm = selectedModel->itemData(idx);
322 selectedModel->removeRow(pos);
323 insertRowToSelected(pos + 1, qm);
325 selectionChanged(); //signal
327 selectedLV->setCurrentIndex(idx.sibling(idx.row() + 1, idx.column()));
328 selectedHasFocus_ = true;
333 void GuiSelectionManager::availableLV_doubleClicked(const QModelIndex & idx)
335 if (isSelected(idx) || !addPB->isEnabled())
339 selectedHasFocus_ = false;
341 //updateHook() will be emitted there
345 bool GuiSelectionManager::eventFilter(QObject * obj, QEvent * event)
347 QEvent::Type etype = event->type();
348 if (obj == availableLV) {
349 if (etype == QEvent::KeyPress) {
350 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
351 int const keyPressed = keyEvent->key();
352 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
353 // Enter key without modifier will add current item.
354 // Ctrl-Enter will add it and close the dialog.
355 // This is designed to work both with the main enter key
356 // and the one on the numeric keypad.
357 if (keyPressed == Qt::Key_Enter || keyPressed == Qt::Key_Return) {
360 else if (keyModifiers == Qt::ControlModifier ||
361 keyModifiers == Qt::KeypadModifier ||
362 keyModifiers == (Qt::ControlModifier | Qt::KeypadModifier)) {
363 if (addPB->isEnabled()) {
371 } else if (etype == QEvent::FocusIn) {
372 if (selectedHasFocus_) {
373 selectedHasFocus_ = false;
379 } else if (obj == selectedLV) {
380 if (etype == QEvent::KeyPress) {
381 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
382 int const keyPressed = keyEvent->key();
383 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
384 // Delete or backspace key will delete current item
385 // ...with control modifier will clear the list
386 if (keyPressed == Qt::Key_Delete || keyPressed == Qt::Key_Backspace) {
387 if (keyModifiers == Qt::NoModifier && deletePB->isEnabled()) {
390 } else if (keyModifiers == Qt::ControlModifier) {
391 selectedModel->removeRows(0, selectedModel->rowCount());
394 return QObject::eventFilter(obj, event);
396 // Ctrl-Up activates upPB
397 else if (keyPressed == Qt::Key_Up) {
398 if (keyModifiers == Qt::ControlModifier) {
399 if (upPB->isEnabled())
405 // Ctrl-Down activates downPB
406 else if (keyPressed == Qt::Key_Down) {
407 if (keyModifiers == Qt::ControlModifier) {
408 if (downPB->isEnabled())
414 } else if (etype == QEvent::FocusIn) {
415 if (!selectedHasFocus_) {
416 selectedHasFocus_ = true;
423 return QObject::eventFilter(obj, event);
426 } // namespace frontend
429 #include "moc_GuiSelectionManager.cpp"