X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2FGuiSelectionManager.cpp;h=eeba9372f0ef73d4205863e7ed0399884722fed1;hb=a0ce37147cffa39b1a5c8859eb001dd2194b22a1;hp=a762aad26babbb4de3f32be93e489bbc8bb32613;hpb=78cc57cd5a7e4e7d60f0313d132e362e6b3f037c;p=lyx.git diff --git a/src/frontends/qt4/GuiSelectionManager.cpp b/src/frontends/qt4/GuiSelectionManager.cpp index a762aad26b..eeba9372f0 100644 --- a/src/frontends/qt4/GuiSelectionManager.cpp +++ b/src/frontends/qt4/GuiSelectionManager.cpp @@ -13,55 +13,80 @@ */ #include + #include "GuiSelectionManager.h" +#include "qt_helpers.h" + +#include "support/debug.h" + +#include +#include +#include +#include +#include +#include + +#ifdef KeyPress +#undef KeyPress +#endif + +#ifdef ControlModifier +#undef ControlModifier +#endif + +#ifdef FocusIn +#undef FocusIn +#endif namespace lyx { namespace frontend { -GuiSelectionManager::GuiSelectionManager( - QListView * avail, - QListView * sel, - QPushButton * add, - QPushButton * del, - QPushButton * up, - QPushButton * down, - QStringListModel * amod, - QStringListModel * smod) - { - availableLV = avail; - selectedLV = sel; - addPB = add; - deletePB = del; - upPB = up; - downPB = down; - availableModel = amod; - selectedModel = smod; - +GuiSelectionManager::GuiSelectionManager(QObject * parent, + QAbstractItemView * avail, + QAbstractItemView * sel, + QPushButton * add, + QPushButton * del, + QPushButton * up, + QPushButton * down, + QAbstractListModel * amod, + QAbstractItemModel * smod, + int const main_sel_col) +: QObject(parent), availableLV(avail), selectedLV(sel), + addPB(add), deletePB(del), upPB(up), downPB(down), + availableModel(amod), selectedModel(smod), + selectedHasFocus_(false), main_sel_col_(main_sel_col) +{ selectedLV->setModel(smod); availableLV->setModel(amod); - + selectedLV->setSelectionBehavior(QAbstractItemView::SelectRows); + selectedLV->setSelectionMode(QAbstractItemView::SingleSelection); + + connect(availableLV->selectionModel(), + SIGNAL(currentChanged(QModelIndex, QModelIndex)), + this, SLOT(availableChanged(QModelIndex, QModelIndex))); + connect(selectedLV->selectionModel(), + SIGNAL(currentChanged(QModelIndex, QModelIndex)), + this, SLOT(selectedChanged(QModelIndex, QModelIndex))); connect(availableLV->selectionModel(), - SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), - this, SLOT(availableChanged(const QModelIndex &, const QModelIndex &))); + SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(availableChanged(QItemSelection, QItemSelection))); connect(selectedLV->selectionModel(), - SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), - this, SLOT(selectedChanged(const QModelIndex &, const QModelIndex &))); - connect(addPB, SIGNAL(clicked()), + SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(selectedChanged(QItemSelection, QItemSelection))); + connect(selectedLV->itemDelegate(), SIGNAL(commitData(QWidget*)), + this, SLOT(selectedEdited())); + connect(addPB, SIGNAL(clicked()), this, SLOT(addPB_clicked())); - connect(deletePB, SIGNAL(clicked()), + connect(deletePB, SIGNAL(clicked()), this, SLOT(deletePB_clicked())); - connect(upPB, SIGNAL(clicked()), + connect(upPB, SIGNAL(clicked()), this, SLOT(upPB_clicked())); - connect(downPB, SIGNAL(clicked()), + connect(downPB, SIGNAL(clicked()), this, SLOT(downPB_clicked())); - connect(availableLV, SIGNAL(clicked(const QModelIndex &)), - this, SLOT(availableLV_clicked(const QModelIndex &))); - connect(availableLV, SIGNAL(doubleClicked(const QModelIndex &)), - this, SLOT(availableLV_doubleClicked(const QModelIndex &))); - connect(selectedLV, SIGNAL(clicked(const QModelIndex &)), - this, SLOT(selectedLV_clicked(const QModelIndex &))); - + connect(availableLV, SIGNAL(doubleClicked(QModelIndex)), + this, SLOT(availableLV_doubleClicked(QModelIndex))); + availableLV->installEventFilter(this); selectedLV->installEventFilter(this); } @@ -76,9 +101,32 @@ void GuiSelectionManager::update() } +QModelIndex GuiSelectionManager::getSelectedIndex(int const c) const +{ + QModelIndexList avail = availableLV->selectionModel()->selectedIndexes(); + QModelIndexList sel = selectedLV->selectionModel()->selectedRows(c); + bool const have_avl = !avail.isEmpty(); + bool const have_sel = !sel.isEmpty(); + + if (selectedFocused()) { + if (have_sel) + return sel.front(); + if (have_avl) + return avail.front(); + } + else { // available has focus + if (have_avl) + return avail.front(); + if (have_sel) + return sel.front(); + } + return QModelIndex(); +} + + void GuiSelectionManager::updateAddPB() { - int const arows = availableLV->model()->rowCount(); + int const arows = availableModel->rowCount(); QModelIndexList const availSels = availableLV->selectionModel()->selectedIndexes(); addPB->setEnabled(arows > 0 && @@ -89,49 +137,65 @@ void GuiSelectionManager::updateAddPB() void GuiSelectionManager::updateDelPB() { - int const srows = selectedLV->model()->rowCount(); + int const srows = selectedModel->rowCount(); if (srows == 0) { deletePB->setEnabled(false); return; } QModelIndexList const selSels = selectedLV->selectionModel()->selectedIndexes(); - int const sel_nr = selSels.empty() ? -1 : selSels.first().row(); + int const sel_nr = selSels.empty() ? -1 : selSels.first().row(); deletePB->setEnabled(sel_nr >= 0); } void GuiSelectionManager::updateUpPB() { - int const srows = selectedLV->model()->rowCount(); + int const srows = selectedModel->rowCount(); if (srows == 0) { upPB->setEnabled(false); return; } QModelIndexList const selSels = selectedLV->selectionModel()->selectedIndexes(); - int const sel_nr = selSels.empty() ? -1 : selSels.first().row(); + int const sel_nr = selSels.empty() ? -1 : selSels.first().row(); upPB->setEnabled(sel_nr > 0); } void GuiSelectionManager::updateDownPB() { - int const srows = selectedLV->model()->rowCount(); + int const srows = selectedModel->rowCount(); if (srows == 0) { downPB->setEnabled(false); return; } QModelIndexList const selSels = selectedLV->selectionModel()->selectedIndexes(); - int const sel_nr = selSels.empty() ? -1 : selSels.first().row(); + int const sel_nr = selSels.empty() ? -1 : selSels.first().row(); downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1); } + bool GuiSelectionManager::isSelected(const QModelIndex & idx) { - QString const str = idx.data().toString(); - return selectedModel->stringList().contains(str); + if (selectedModel->rowCount() == 0) + return false; + QVariant const & str = availableModel->data(idx, Qt::DisplayRole); + QModelIndexList qmil = + selectedModel->match(selectedModel->index(0, main_sel_col_), + Qt::DisplayRole, str, 1, + Qt::MatchFlags(Qt::MatchExactly | Qt::MatchWrap)); + return !qmil.empty(); +} + + +void GuiSelectionManager::availableChanged(QItemSelection const & qis, QItemSelection const &) +{ + QModelIndexList il = qis.indexes(); + if (il.empty()) + return; + availableChanged(il.front(), QModelIndex()); } @@ -139,70 +203,107 @@ void GuiSelectionManager::availableChanged(const QModelIndex & idx, const QModel { if (!idx.isValid()) return; - + selectedHasFocus_ = false; updateHook(); } +void GuiSelectionManager::selectedChanged(QItemSelection const & qis, QItemSelection const &) +{ + QModelIndexList il = qis.indexes(); + if (il.empty()) + return; + selectedChanged(il.front(), QModelIndex()); +} + + void GuiSelectionManager::selectedChanged(const QModelIndex & idx, const QModelIndex &) { if (!idx.isValid()) return; - + selectedHasFocus_ = true; updateHook(); } -static QModelIndex getSelectedIndex(QListView * lv) +void GuiSelectionManager::selectedEdited() { - QModelIndex retval = QModelIndex(); - QModelIndexList selIdx = - lv->selectionModel()->selectedIndexes(); - if (!selIdx.empty()) - retval = selIdx.first(); - return retval; + selectionChanged(); +} + + +bool GuiSelectionManager::insertRowToSelected(int i, + QMap const & itemData) +{ + if (i <= -1) + i = 0; + if (i > selectedModel->rowCount()) + i = selectedModel->rowCount(); + if (!selectedModel->insertRow(i)) + return false; + return selectedModel->setItemData(selectedModel->index(i, main_sel_col_), itemData); +} + + +bool GuiSelectionManager::insertRowToSelected(int i, QMap> & qms) +{ + if (i <= -1) + i = 0; + if (i > selectedModel->rowCount()) + i = selectedModel->rowCount(); + if (!selectedModel->insertRow(i)) + return false; + bool res = true; + QMap>::const_iterator it = qms.constBegin(); + for (; it != qms.constEnd(); ++it) + res &= selectedModel->setItemData(selectedModel->index(i, it.key()), it.value()); + return res; } void GuiSelectionManager::addPB_clicked() { - QModelIndex const idxToAdd = getSelectedIndex(availableLV); - if (!idxToAdd.isValid()) + QModelIndexList selIdx = + availableLV->selectionModel()->selectedIndexes(); + if (selIdx.isEmpty()) return; - QModelIndex idx = selectedLV->currentIndex(); - - QStringList keys = selectedModel->stringList(); - keys.append(idxToAdd.data().toString()); - selectedModel->setStringList(keys); + + QModelIndex const idxToAdd = selIdx.first(); + QModelIndex const idx = selectedLV->currentIndex(); + int const srows = selectedModel->rowCount(); + + QMap qm = availableModel->itemData(idxToAdd); + insertRowToSelected(srows, qm); + selectionChanged(); //signal - + if (idx.isValid()) selectedLV->setCurrentIndex(idx); + updateHook(); } void GuiSelectionManager::deletePB_clicked() { - QModelIndex idx = getSelectedIndex(selectedLV); - if (!idx.isValid()) + QModelIndexList selIdx = + selectedLV->selectionModel()->selectedIndexes(); + if (selIdx.isEmpty()) return; - - QStringList keys = selectedModel->stringList(); - keys.removeAt(idx.row()); - selectedModel->setStringList(keys); + QModelIndex idx = selIdx.first(); + selectedModel->removeRow(idx.row()); selectionChanged(); //signal - + int nrows = selectedLV->model()->rowCount(); if (idx.row() == nrows) //was last item on list idx = idx.sibling(idx.row() - 1, idx.column()); - + if (nrows > 1) selectedLV->setCurrentIndex(idx); else if (nrows == 1) - selectedLV->setCurrentIndex(selectedLV->model()->index(0,0)); + selectedLV->setCurrentIndex(selectedLV->model()->index(0, 0)); selectedHasFocus_ = (nrows > 0); updateHook(); } @@ -210,14 +311,26 @@ void GuiSelectionManager::deletePB_clicked() void GuiSelectionManager::upPB_clicked() { - QModelIndex idx = selectedLV->currentIndex(); - + QModelIndexList selIdx = + selectedLV->selectionModel()->selectedIndexes(); + if (selIdx.isEmpty()) + return; + QModelIndex idx = selIdx.first(); + int const pos = idx.row(); - QStringList keys = selectedModel->stringList(); - keys.swap(pos, pos - 1); - selectedModel->setStringList(keys); + if (pos <= 0) + return; + + QMap> qms; + QList::const_iterator it = selIdx.constBegin(); + for (; it != selIdx.constEnd(); ++it) + qms[it->column()] = selectedModel->itemData(*it); + + selectedModel->removeRow(pos); + insertRowToSelected(pos - 1, qms); + selectionChanged(); //signal - + selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column())); selectedHasFocus_ = true; updateHook(); @@ -226,36 +339,37 @@ void GuiSelectionManager::upPB_clicked() void GuiSelectionManager::downPB_clicked() { - QModelIndex idx = selectedLV->currentIndex(); - + QModelIndexList selIdx = + selectedLV->selectionModel()->selectedIndexes(); + if (selIdx.isEmpty()) + return; + QModelIndex idx = selIdx.first(); + int const pos = idx.row(); - QStringList keys = selectedModel->stringList(); - keys.swap(pos, pos + 1); - selectedModel->setStringList(keys); + if (pos >= selectedModel->rowCount() - 1) + return; + + QMap> qms; + QList::const_iterator it = selIdx.constBegin(); + for (; it != selIdx.constEnd(); ++it) + qms[it->column()] = selectedModel->itemData(*it); + + selectedModel->removeRow(pos); + insertRowToSelected(pos + 1, qms); + selectionChanged(); //signal - + selectedLV->setCurrentIndex(idx.sibling(idx.row() + 1, idx.column())); selectedHasFocus_ = true; updateHook(); } -//FIXME These slots do not really do what they need to do, since focus -//can enter the QListView in other ways. But there are no signals sent -//in that case. We need to reimplement focusInEvent() to capture those, -//which means subclassing QListView. (rgh) -void GuiSelectionManager::availableLV_clicked(const QModelIndex &) -{ - selectedHasFocus_ = false; - updateHook(); -} - - void GuiSelectionManager::availableLV_doubleClicked(const QModelIndex & idx) { if (isSelected(idx) || !addPB->isEnabled()) return; - + if (idx.isValid()) selectedHasFocus_ = false; addPB_clicked(); @@ -263,63 +377,91 @@ void GuiSelectionManager::availableLV_doubleClicked(const QModelIndex & idx) } -void GuiSelectionManager::selectedLV_clicked(const QModelIndex &) -{ - selectedHasFocus_ = true; - updateHook(); -} - - bool GuiSelectionManager::eventFilter(QObject * obj, QEvent * event) { + QEvent::Type etype = event->type(); if (obj == availableLV) { - if (event->type() != QEvent::KeyPress) - return QObject::eventFilter(obj, event); - QKeyEvent * keyEvent = static_cast(event); - int const keyPressed = keyEvent->key(); - Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers(); - //Enter key without modifier will add current item. - //Ctrl-Enter will add it and close the dialog. - //This is designed to work both with the main enter key - //and the one on the numeric keypad. - if ((keyPressed == Qt::Key_Enter || keyPressed == Qt::Key_Return) && - //We want one or both of Control and Keypad, and nothing else - //(KeypadModifier is what you get if you use the Enter key on the - //numeric keypad.) - (!keyModifiers || - (keyModifiers == Qt::ControlModifier) || - (keyModifiers == Qt::KeypadModifier) || - (keyModifiers == (Qt::ControlModifier | Qt::KeypadModifier)) - ) - ) { - if (addPB->isEnabled()) { - addPB_clicked(); - okHook(); //signal + if (etype == QEvent::KeyPress) { + QKeyEvent * keyEvent = static_cast(event); + int const keyPressed = keyEvent->key(); + Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers(); + // Enter key without modifier will add current item. + // Ctrl-Enter will add it and close the dialog. + // This is designed to work both with the main enter key + // and the one on the numeric keypad. + if (keyPressed == Qt::Key_Enter || keyPressed == Qt::Key_Return) { + if (!keyModifiers || + keyModifiers == Qt::ControlModifier || + keyModifiers == Qt::KeypadModifier || + keyModifiers == (Qt::ControlModifier + | Qt::KeypadModifier)) { + if (addPB->isEnabled()) { + addPB_clicked(); + } + if (keyModifiers) + okHook(); //signal + } + event->accept(); + return true; } - event->accept(); - return true; - } - } else if (obj == selectedLV) { - //Delete or backspace key will delete current item - //...with control modifier will clear the list - if (event->type() != QEvent::KeyPress) - return QObject::eventFilter(obj, event); - QKeyEvent * keyEvent = static_cast(event); - int const keyPressed = keyEvent->key(); - Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers(); - if (keyPressed == Qt::Key_Delete || keyPressed == Qt::Key_Backspace) { - if (keyModifiers == Qt::NoModifier && deletePB->isEnabled()) - deletePB_clicked(); - else if (keyModifiers == Qt::ControlModifier) { - QStringList list = selectedModel->stringList(); - list.clear(); - selectedModel->setStringList(list); + else if (keyPressed == Qt::Key_Right) { + focusAndHighlight(selectedLV); + event->accept(); + return true; + } + } else if (etype == QEvent::FocusIn) { + if (selectedHasFocus_) { + selectedHasFocus_ = false; updateHook(); - } else - //ignore it otherwise - return QObject::eventFilter(obj, event); + } + return false; + } + } else if (obj == selectedLV) { + if (etype == QEvent::KeyPress) { + QKeyEvent * keyEvent = static_cast(event); + int const keyPressed = keyEvent->key(); + Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers(); + // Delete or backspace key will delete current item + // ...with control modifier will clear the list + if (keyPressed == Qt::Key_Delete || keyPressed == Qt::Key_Backspace) { + if (keyModifiers == Qt::NoModifier && deletePB->isEnabled()) { + deletePB_clicked(); + updateHook(); + } else if (keyModifiers == Qt::ControlModifier) { + selectedModel->removeRows(0, selectedModel->rowCount()); + updateHook(); + } else + return QObject::eventFilter(obj, event); + } + // Ctrl-Up activates upPB + else if (keyPressed == Qt::Key_Up) { + if (keyModifiers == Qt::ControlModifier) { + if (upPB->isEnabled()) + upPB_clicked(); + event->accept(); + return true; + } + } + // Ctrl-Down activates downPB + else if (keyPressed == Qt::Key_Down) { + if (keyModifiers == Qt::ControlModifier) { + if (downPB->isEnabled()) + downPB_clicked(); + event->accept(); + return true; + } + } + else if (keyPressed == Qt::Key_Left) { + focusAndHighlight(availableLV); event->accept(); return true; + } + } else if (etype == QEvent::FocusIn) { + if (!selectedHasFocus_) { + selectedHasFocus_ = true; + updateHook(); + } + return false; } } return QObject::eventFilter(obj, event); @@ -328,4 +470,4 @@ bool GuiSelectionManager::eventFilter(QObject * obj, QEvent * event) } // namespace frontend } // namespace lyx -#include "GuiSelectionManager_moc.cpp" +#include "moc_GuiSelectionManager.cpp"