2 * \file QSelectionManager.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 * QCitationDialog.cpp.
12 * Full author contact details are available in file CREDITS.
16 #include "QSelectionManager.h"
22 QSelectionManager::QSelectionManager(
29 QStringListModel * amod,
30 QStringListModel * smod)
38 availableModel = amod;
41 selectedLV->setModel(smod);
42 availableLV->setModel(amod);
44 connect(availableLV->selectionModel(),
45 SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
46 this, SLOT(availableChanged(const QModelIndex &, const QModelIndex &)));
47 connect(selectedLV->selectionModel(),
48 SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
49 this, SLOT(selectedChanged(const QModelIndex &, const QModelIndex &)));
50 connect(addPB, SIGNAL(clicked()),
51 this, SLOT(addPB_clicked()));
52 connect(deletePB, SIGNAL(clicked()),
53 this, SLOT(deletePB_clicked()));
54 connect(upPB, SIGNAL(clicked()),
55 this, SLOT(upPB_clicked()));
56 connect(downPB, SIGNAL(clicked()),
57 this, SLOT(downPB_clicked()));
58 connect(availableLV, SIGNAL(clicked(const QModelIndex &)),
59 this, SLOT(availableLV_clicked(const QModelIndex &)));
60 connect(availableLV, SIGNAL(doubleClicked(const QModelIndex &)),
61 this, SLOT(availableLV_doubleClicked(const QModelIndex &)));
62 connect(selectedLV, SIGNAL(clicked(const QModelIndex &)),
63 this, SLOT(selectedLV_clicked(const QModelIndex &)));
65 availableLV->installEventFilter(this);
66 selectedLV->installEventFilter(this);
70 void QSelectionManager::update() {
71 int const arows = availableLV->model()->rowCount();
72 QModelIndexList const availSels =
73 availableLV->selectionModel()->selectedIndexes();
74 addPB->setEnabled(arows > 0 &&
75 !availSels.isEmpty() &&
76 !isSelected(availSels.first()));
78 int const srows = selectedLV->model()->rowCount();
79 QModelIndexList const selSels =
80 selectedLV->selectionModel()->selectedIndexes();
81 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
82 deletePB->setEnabled(sel_nr >= 0);
83 upPB->setEnabled(sel_nr > 0);
84 downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
88 bool QSelectionManager::isSelected(const QModelIndex & idx)
90 QString const str = idx.data().toString();
91 return selectedModel->stringList().contains(str);
95 void QSelectionManager::availableChanged(const QModelIndex & idx, const QModelIndex &)
100 selectedHasFocus_ = false;
105 void QSelectionManager::selectedChanged(const QModelIndex & idx, const QModelIndex &)
110 selectedHasFocus_ = true;
116 //helper function for next two
117 QModelIndex getSelectedIndex(QListView * lv) {
118 //Encourage compiler to use NRVO
119 QModelIndex retval = QModelIndex();
120 QModelIndexList selIdx =
121 lv->selectionModel()->selectedIndexes();
123 retval = selIdx.first();
126 }//anonymous namespace
129 void QSelectionManager::addPB_clicked()
131 QModelIndex const idxToAdd = getSelectedIndex(availableLV);
132 if (!idxToAdd.isValid())
134 QModelIndex idx = selectedLV->currentIndex();
136 QStringList keys = selectedModel->stringList();
137 keys.append(idxToAdd.data().toString());
138 selectedModel->setStringList(keys);
139 selectionChanged(); //signal
142 selectedLV->setCurrentIndex(idx);
147 void QSelectionManager::deletePB_clicked()
149 QModelIndex idx = getSelectedIndex(selectedLV);
153 QStringList keys = selectedModel->stringList();
154 keys.removeAt(idx.row());
155 selectedModel->setStringList(keys);
156 selectionChanged(); //signal
158 int nrows = selectedLV->model()->rowCount();
159 if (idx.row() == nrows) //was last item on list
160 idx = idx.sibling(idx.row() - 1, idx.column());
163 selectedLV->setCurrentIndex(idx);
165 selectedLV->setCurrentIndex(selectedLV->model()->index(0,0));
166 selectedHasFocus_ = (nrows > 0);
171 void QSelectionManager::upPB_clicked()
173 QModelIndex idx = selectedLV->currentIndex();
175 int const pos = idx.row();
176 QStringList keys = selectedModel->stringList();
177 keys.swap(pos, pos - 1);
178 selectedModel->setStringList(keys);
179 selectionChanged(); //signal
181 selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column()));
182 selectedHasFocus_ = true;
187 void QSelectionManager::downPB_clicked()
189 QModelIndex idx = selectedLV->currentIndex();
191 int const pos = idx.row();
192 QStringList keys = selectedModel->stringList();
193 keys.swap(pos, pos + 1);
194 selectedModel->setStringList(keys);
195 selectionChanged(); //signal
197 selectedLV->setCurrentIndex(idx.sibling(idx.row() + 1, idx.column()));
198 selectedHasFocus_ = true;
203 //FIXME These slots do not really do what they need to do, since focus
204 //can enter the QListView in other ways. But there are no signals sent
205 //in that case. We need to reimplement focusInEvent() to capture those,
206 //which means subclassing QListView. (rgh)
207 void QSelectionManager::availableLV_clicked(const QModelIndex &)
209 selectedHasFocus_ = false;
214 void QSelectionManager::availableLV_doubleClicked(const QModelIndex & idx)
220 selectedHasFocus_ = false;
222 //updateHook() will be emitted there
226 void QSelectionManager::selectedLV_clicked(const QModelIndex &)
228 selectedHasFocus_ = true;
233 bool QSelectionManager::eventFilter(QObject * obj, QEvent * event)
235 if (obj == availableLV) {
236 if (event->type() != QEvent::KeyPress)
237 return QObject::eventFilter(obj, event);
238 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
239 int const keyPressed = keyEvent->key();
240 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
241 //Enter key without modifier will add current item.
242 //Ctrl-Enter will add it and close the dialog.
243 //This is designed to work both with the main enter key
244 //and the one on the numeric keypad.
245 if ((keyPressed == Qt::Key_Enter || keyPressed == Qt::Key_Return) &&
246 //We want one or both of Control and Keypad, and nothing else
247 //(KeypadModifier is what you get if you use the Enter key on the
250 (keyModifiers == Qt::ControlModifier) ||
251 (keyModifiers == Qt::KeypadModifier) ||
252 (keyModifiers == (Qt::ControlModifier | Qt::KeypadModifier))
255 if (addPB->isEnabled()) {
262 } else if (obj == selectedLV) {
263 //Delete or backspace key will delete current item
264 //...with control modifier will clear the list
265 if (event->type() != QEvent::KeyPress)
266 return QObject::eventFilter(obj, event);
267 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
268 int const keyPressed = keyEvent->key();
269 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
270 if (keyPressed == Qt::Key_Delete || keyPressed == Qt::Key_Backspace) {
271 if (keyModifiers == Qt::NoModifier && deletePB->isEnabled())
273 else if (keyModifiers == Qt::ControlModifier) {
274 QStringList list = selectedModel->stringList();
276 selectedModel->setStringList(list);
279 //ignore it otherwise
280 return QObject::eventFilter(obj, event);
285 return QObject::eventFilter(obj, event);
288 }//namespace frontend
291 #include "QSelectionManager_moc.cpp"