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.
16 #include "GuiSelectionManager.h"
17 #include "GuiDocument.h"
19 #include "support/debug.h"
27 GuiSelectionManager::GuiSelectionManager(
34 QAbstractListModel * amod,
35 QAbstractListModel * smod)
43 availableModel = amod;
46 selectedLV->setModel(smod);
47 availableLV->setModel(amod);
49 connect(availableLV->selectionModel(),
50 SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
51 this, SLOT(availableChanged(const QModelIndex &, const QModelIndex &)));
52 connect(selectedLV->selectionModel(),
53 SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
54 this, SLOT(selectedChanged(const QModelIndex &, const QModelIndex &)));
55 connect(addPB, SIGNAL(clicked()),
56 this, SLOT(addPB_clicked()));
57 connect(deletePB, SIGNAL(clicked()),
58 this, SLOT(deletePB_clicked()));
59 connect(upPB, SIGNAL(clicked()),
60 this, SLOT(upPB_clicked()));
61 connect(downPB, SIGNAL(clicked()),
62 this, SLOT(downPB_clicked()));
63 connect(availableLV, SIGNAL(clicked(const QModelIndex &)),
64 this, SLOT(availableLV_clicked(const QModelIndex &)));
65 connect(availableLV, SIGNAL(doubleClicked(const QModelIndex &)),
66 this, SLOT(availableLV_doubleClicked(const QModelIndex &)));
67 connect(selectedLV, SIGNAL(clicked(const QModelIndex &)),
68 this, SLOT(selectedLV_clicked(const QModelIndex &)));
70 availableLV->installEventFilter(this);
71 selectedLV->installEventFilter(this);
75 void GuiSelectionManager::update()
84 void GuiSelectionManager::updateAddPB()
86 int const arows = availableModel->rowCount();
87 QModelIndexList const availSels =
88 availableLV->selectionModel()->selectedIndexes();
89 addPB->setEnabled(arows > 0 &&
90 !availSels.isEmpty() &&
91 !isSelected(availSels.first()));
95 void GuiSelectionManager::updateDelPB()
97 int const srows = selectedModel->rowCount();
99 deletePB->setEnabled(false);
102 QModelIndexList const selSels =
103 selectedLV->selectionModel()->selectedIndexes();
104 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
105 deletePB->setEnabled(sel_nr >= 0);
109 void GuiSelectionManager::updateUpPB()
111 int const srows = selectedModel->rowCount();
113 upPB->setEnabled(false);
116 QModelIndexList const selSels =
117 selectedLV->selectionModel()->selectedIndexes();
118 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
119 upPB->setEnabled(sel_nr > 0);
123 void GuiSelectionManager::updateDownPB()
125 int const srows = selectedModel->rowCount();
127 downPB->setEnabled(false);
130 QModelIndexList const selSels =
131 selectedLV->selectionModel()->selectedIndexes();
132 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
133 downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
137 bool GuiSelectionManager::isSelected(const QModelIndex & idx)
139 if (selectedModel->rowCount() == 0)
141 QVariant const & str = availableModel->data(idx, Qt::DisplayRole);
142 QModelIndexList qmil =
143 selectedModel->match(selectedModel->index(0),
144 Qt::DisplayRole, str,
145 Qt::MatchExactly | Qt::MatchWrap);
146 return !qmil.empty();
150 void GuiSelectionManager::availableChanged(const QModelIndex & idx, const QModelIndex &)
155 selectedHasFocus_ = false;
160 void GuiSelectionManager::selectedChanged(const QModelIndex & idx, const QModelIndex &)
165 selectedHasFocus_ = true;
170 bool GuiSelectionManager::insertRowToSelected(int i,
171 QMap<int, QVariant> const & itemData)
173 if (i <= -1 || i > selectedModel->rowCount())
175 if (!selectedModel->insertRow(i))
177 return selectedModel->setItemData(selectedModel->index(i), itemData);
181 void GuiSelectionManager::addPB_clicked()
183 QModelIndex const idxToAdd = getSelectedIndex(availableLV);
184 if (!idxToAdd.isValid())
186 QModelIndex const idx = selectedLV->currentIndex();
187 int const srows = selectedModel->rowCount();
189 QMap<int, QVariant> qm = availableModel->itemData(idxToAdd);
190 insertRowToSelected(srows, qm);
192 selectionChanged(); //signal
195 selectedLV->setCurrentIndex(idx);
201 void GuiSelectionManager::deletePB_clicked()
203 QModelIndex idx = getSelectedIndex(selectedLV);
207 selectedModel->removeRow(idx.row());
208 selectionChanged(); //signal
210 int nrows = selectedLV->model()->rowCount();
211 if (idx.row() == nrows) //was last item on list
212 idx = idx.sibling(idx.row() - 1, idx.column());
215 selectedLV->setCurrentIndex(idx);
217 selectedLV->setCurrentIndex(selectedLV->model()->index(0,0));
218 selectedHasFocus_ = (nrows > 0);
223 void GuiSelectionManager::upPB_clicked()
225 QModelIndex idx = selectedLV->currentIndex();
227 int const pos = idx.row();
231 QMap<int, QVariant> qm = selectedModel->itemData(idx);
233 selectedModel->removeRow(pos);
234 insertRowToSelected(pos - 1, qm);
236 selectionChanged(); //signal
238 selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column()));
239 selectedHasFocus_ = true;
244 void GuiSelectionManager::downPB_clicked()
246 QModelIndex idx = selectedLV->currentIndex();
248 int const pos = idx.row();
249 if (pos >= selectedModel->rowCount() - 1)
252 QMap<int, QVariant> qm = selectedModel->itemData(idx);
254 selectedModel->removeRow(pos);
255 insertRowToSelected(pos + 1, qm);
257 selectionChanged(); //signal
259 selectedLV->setCurrentIndex(idx.sibling(idx.row() + 1, idx.column()));
260 selectedHasFocus_ = true;
265 // FIXME These slots do not really do what they need to do, since focus
266 // can enter the QListView in other ways. But there are no signals sent
267 // in that case. We need to reimplement focusInEvent() to capture those,
268 // which means subclassing QListView. (rgh)
269 void GuiSelectionManager::availableLV_clicked(const QModelIndex &)
271 selectedHasFocus_ = false;
276 void GuiSelectionManager::availableLV_doubleClicked(const QModelIndex & idx)
278 if (isSelected(idx) || !addPB->isEnabled())
282 selectedHasFocus_ = false;
284 //updateHook() will be emitted there
288 void GuiSelectionManager::selectedLV_clicked(const QModelIndex &)
290 selectedHasFocus_ = true;
295 bool GuiSelectionManager::eventFilter(QObject * obj, QEvent * event)
297 if (obj == availableLV) {
298 if (event->type() != QEvent::KeyPress)
299 return QObject::eventFilter(obj, event);
300 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
301 int const keyPressed = keyEvent->key();
302 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
303 // Enter key without modifier will add current item.
304 // Ctrl-Enter will add it and close the dialog.
305 // This is designed to work both with the main enter key
306 // and the one on the numeric keypad.
307 if (keyPressed == Qt::Key_Enter || keyPressed == Qt::Key_Return) {
310 else if ((keyModifiers == Qt::ControlModifier) ||
311 (keyModifiers == Qt::KeypadModifier) ||
312 (keyModifiers == (Qt::ControlModifier | Qt::KeypadModifier))
314 if (addPB->isEnabled()) {
322 } else if (obj == selectedLV) {
323 if (event->type() != QEvent::KeyPress)
324 return QObject::eventFilter(obj, event);
325 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
326 int const keyPressed = keyEvent->key();
327 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
328 // Delete or backspace key will delete current item
329 // ...with control modifier will clear the list
330 if (keyPressed == Qt::Key_Delete || keyPressed == Qt::Key_Backspace) {
331 if (keyModifiers == Qt::NoModifier && deletePB->isEnabled()) {
334 } else if (keyModifiers == Qt::ControlModifier) {
335 selectedModel->removeRows(0, selectedModel->rowCount());
338 return QObject::eventFilter(obj, event);
340 // Ctrl-Up activates upPB
341 else if (keyPressed == Qt::Key_Up) {
342 if (keyModifiers == Qt::ControlModifier) {
343 if (upPB->isEnabled())
349 // Ctrl-Down activates downPB
350 else if (keyPressed == Qt::Key_Down) {
351 if (keyModifiers == Qt::ControlModifier) {
352 if (downPB->isEnabled())
359 return QObject::eventFilter(obj, event);
362 } // namespace frontend
365 #include "GuiSelectionManager_moc.cpp"