mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-27 14:29:21 +00:00
This is one of a series of patches that will merge the layout modules development in personal/branches/rgheck back into the tree.
Design goal: Allow the use of layout "modules", which are to LaTeX packages as layout files are to LaTeX document classes. Thus, one could have a module that defined certain character styles, environments, commands, or what have you, and include it in various documents, each of which uses a different document class, without having to modify the layout files themselves. For example, a theorems.module could be used with article.layout to provide support for theorem-type environments, without having to modify article.layout itself, and the same module could be used with book.layout, etc. This third patch just re-factors some code presently in QCitation*. (It also incorporates some bug fixes that have been committed separately.) We're going to use essentially the same set of widgets for choosing modules that is used for choosing citation keys, so we pull the controlling logic out into a new class, QSelectionManager. I did not make this a QWidget. That seemed to me to be overkill, and it would have made things much more complicated, I think...and I'm not all that experienced with Qt, anyway. Anyone who wants to do that is of course welcome. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@19860 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
parent
5440aad928
commit
53bc63d95c
@ -103,6 +103,7 @@ SOURCEFILES = \
|
||||
QPrefs.cpp \
|
||||
QRef.cpp \
|
||||
QSearch.cpp \
|
||||
QSelectionManager.cpp \
|
||||
QSendto.cpp \
|
||||
QSetBorder.cpp \
|
||||
QShowFile.cpp \
|
||||
@ -189,6 +190,7 @@ MOCHEADER = \
|
||||
QPrefs.h \
|
||||
QRef.h \
|
||||
QSearch.h \
|
||||
QSelectionManager.h \
|
||||
QSendto.h \
|
||||
QSetBorder.h \
|
||||
QShowFile.h \
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/**
|
||||
* \file QCitation.cpp
|
||||
* This file is part of LyX, the document processor.
|
||||
* Licence details can be found in the file COPYING.
|
||||
@ -6,6 +6,7 @@
|
||||
* \author Angus Leeming
|
||||
* \author Kalle Dalheimer
|
||||
* \author Abdelrazak Younes
|
||||
* \author Richard Heck (adapted to QSelectionManager)
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*/
|
||||
@ -190,36 +191,6 @@ QStringList QCitation::getEntriesAsQStringList() {
|
||||
}
|
||||
|
||||
|
||||
void QCitation::addKey(QModelIndex const & index)
|
||||
{
|
||||
cited_keys_.append(index.data().toString());
|
||||
selected_model_.setStringList(cited_keys_);
|
||||
}
|
||||
|
||||
|
||||
void QCitation::deleteKey(QModelIndex const & index)
|
||||
{
|
||||
cited_keys_.removeAt(index.row());
|
||||
selected_model_.setStringList(cited_keys_);
|
||||
}
|
||||
|
||||
|
||||
void QCitation::upKey(QModelIndex const & index)
|
||||
{
|
||||
int pos = index.row();
|
||||
cited_keys_.swap(pos, pos - 1);
|
||||
selected_model_.setStringList(cited_keys_);
|
||||
}
|
||||
|
||||
|
||||
void QCitation::downKey(QModelIndex const & index)
|
||||
{
|
||||
int pos = index.row();
|
||||
cited_keys_.swap(pos, pos + 1);
|
||||
selected_model_.setStringList(cited_keys_);
|
||||
}
|
||||
|
||||
|
||||
QStringList QCitation::citationStyles(int sel)
|
||||
{
|
||||
docstring const key = qstring_to_ucs4(cited_keys_[sel]);
|
||||
@ -232,6 +203,11 @@ QString QCitation::getKeyInfo(QString const & sel)
|
||||
return toqstr(getInfo(qstring_to_ucs4(sel)));
|
||||
}
|
||||
|
||||
void QCitation::setCitedKeys()
|
||||
{
|
||||
cited_keys_ = selected_model_.stringList();
|
||||
}
|
||||
|
||||
|
||||
} // namespace frontend
|
||||
} // namespace lyx
|
||||
|
@ -7,6 +7,7 @@
|
||||
* \author Angus Leeming
|
||||
* \author Kalle Dalheimer
|
||||
* \author Abdelrazak Younes
|
||||
* \author Richard Heck (adapted to QSelectionManager)
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*/
|
||||
@ -69,24 +70,14 @@ public:
|
||||
bool reset = false //< whether to reset and search all keys
|
||||
);
|
||||
|
||||
/// Add key to selected keys
|
||||
void addKey(QModelIndex const &);
|
||||
|
||||
/// Delete key from selected keys
|
||||
void deleteKey(QModelIndex const &);
|
||||
|
||||
/// Move selected key one place up
|
||||
void upKey(QModelIndex const &);
|
||||
|
||||
/// Move selected key one place down
|
||||
void downKey(QModelIndex const &);
|
||||
|
||||
/// List of example cite strings
|
||||
QStringList citationStyles(int);
|
||||
|
||||
/// Set the Params variable for the Controller.
|
||||
virtual void apply(int const choice, bool const full, bool const force,
|
||||
QString before, QString after);
|
||||
|
||||
void setCitedKeys();
|
||||
|
||||
private:
|
||||
/// available keys.
|
||||
|
@ -7,6 +7,7 @@
|
||||
* \author John Levon
|
||||
* \author Jürgen Spitzmüller
|
||||
* \author Abdelrazak Younes
|
||||
* \author Richard Heck
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*/
|
||||
@ -19,6 +20,7 @@
|
||||
|
||||
#include "frontends/controllers/frontend_helpers.h"
|
||||
#include "frontends/controllers/ControlCitation.h"
|
||||
#include "qt_helpers.h"
|
||||
|
||||
#include "support/docstring.h"
|
||||
|
||||
@ -48,9 +50,6 @@ QCitationDialog::QCitationDialog(Dialog & dialog, QCitation * form)
|
||||
|
||||
setWindowTitle(toqstr("LyX: " + getTitle()));
|
||||
|
||||
selectedLV->setModel(form_->selected());
|
||||
availableLV->setModel(form_->available());
|
||||
|
||||
connect(citationStyleCO, SIGNAL(activated(int)),
|
||||
this, SLOT(changed()));
|
||||
connect(fulllistCB, SIGNAL(clicked()),
|
||||
@ -63,76 +62,24 @@ QCitationDialog::QCitationDialog(Dialog & dialog, QCitation * form)
|
||||
this, SLOT(changed()));
|
||||
connect(clearPB, SIGNAL(clicked()),
|
||||
findLE, SLOT(clear()));
|
||||
connect(availableLV->selectionModel(),
|
||||
SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
|
||||
this, SLOT(availableChanged(const QModelIndex &, const QModelIndex &)));
|
||||
connect(selectedLV->selectionModel(),
|
||||
SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
|
||||
this, SLOT(selectedChanged(const QModelIndex &, const QModelIndex &)));
|
||||
connect(this, SIGNAL(rejected()), this, SLOT(cleanUp()));
|
||||
availableLV->installEventFilter(this);
|
||||
selectedLV->installEventFilter(this);
|
||||
availableFocused_ = true;
|
||||
|
||||
selectionManager =
|
||||
new QSelectionManager(availableLV, selectedLV,
|
||||
addPB, deletePB, upPB, downPB,
|
||||
form_->available(), form_->selected());
|
||||
connect(selectionManager, SIGNAL(selectionChanged()),
|
||||
this, SLOT(setCitedKeys()));
|
||||
connect(selectionManager, SIGNAL(updateHook()),
|
||||
this, SLOT(updateDialog()));
|
||||
connect(selectionManager, SIGNAL(okHook()),
|
||||
this, SLOT(on_okPB_clicked()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
QCitationDialog::~QCitationDialog()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool QCitationDialog::eventFilter(QObject * obj, QEvent * event)
|
||||
{
|
||||
if (obj == availableLV) {
|
||||
if (event->type() != QEvent::KeyPress)
|
||||
return QObject::eventFilter(obj, event);
|
||||
QKeyEvent * keyEvent = static_cast<QKeyEvent *>(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())
|
||||
on_addPB_clicked();
|
||||
if (keyModifiers & Qt::ControlModifier)
|
||||
on_okPB_clicked();
|
||||
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<QKeyEvent *>(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())
|
||||
on_deletePB_clicked();
|
||||
else if (keyModifiers == Qt::ControlModifier) {
|
||||
form_->clearSelection();
|
||||
updateDialog();
|
||||
} else
|
||||
//ignore it otherwise
|
||||
return QObject::eventFilter(obj, event);
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
{}
|
||||
|
||||
|
||||
void QCitationDialog::cleanUp()
|
||||
@ -232,15 +179,17 @@ void QCitationDialog::update()
|
||||
//two methods, though they should be divisible.
|
||||
void QCitationDialog::updateDialog()
|
||||
{
|
||||
if (availableFocused_ ||
|
||||
selectedLV->selectionModel()->selectedIndexes().isEmpty()) {
|
||||
if (availableLV->selectionModel()->selectedIndexes().isEmpty()
|
||||
&& availableLV->model()->rowCount() > 0)
|
||||
availableLV->setCurrentIndex(availableLV->model()->index(0,0));
|
||||
updateInfo(availableLV);
|
||||
} else
|
||||
updateInfo(selectedLV);
|
||||
|
||||
if (selectionManager->selectedFocused()) {
|
||||
if (selectedLV->selectionModel()->selectedIndexes().isEmpty())
|
||||
updateInfo(availableLV->currentIndex());
|
||||
else
|
||||
updateInfo(selectedLV->currentIndex());
|
||||
} else {
|
||||
if (availableLV->selectionModel()->selectedIndexes().isEmpty())
|
||||
updateInfo(QModelIndex());
|
||||
else
|
||||
updateInfo(availableLV->currentIndex());
|
||||
}
|
||||
setButtons();
|
||||
|
||||
textBeforeED->setText(form_->textBefore());
|
||||
@ -376,26 +325,15 @@ bool QCitationDialog::isSelected(const QModelIndex & idx)
|
||||
|
||||
void QCitationDialog::setButtons()
|
||||
{
|
||||
int const arows = availableLV->model()->rowCount();
|
||||
QModelIndexList const availSels =
|
||||
availableLV->selectionModel()->selectedIndexes();
|
||||
addPB->setEnabled(arows > 0 &&
|
||||
!availSels.isEmpty() &&
|
||||
!isSelected(availSels.first()));
|
||||
|
||||
selectionManager->update();
|
||||
int const srows = selectedLV->model()->rowCount();
|
||||
QModelIndexList const selSels =
|
||||
selectedLV->selectionModel()->selectedIndexes();
|
||||
int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
|
||||
deletePB->setEnabled(sel_nr >= 0);
|
||||
upPB->setEnabled(sel_nr > 0);
|
||||
downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
|
||||
applyPB->setEnabled(srows > 0);
|
||||
okPB->setEnabled(srows > 0);
|
||||
}
|
||||
|
||||
|
||||
void QCitationDialog::updateInfo(QListView const * const qlv)
|
||||
void QCitationDialog::updateInfo(QModelIndex const & idx)
|
||||
{
|
||||
QModelIndex idx = qlv->currentIndex();
|
||||
if (idx.isValid()) {
|
||||
QString const keytxt = form_->getKeyInfo(idx.data().toString());
|
||||
infoML->document()->setPlainText(keytxt);
|
||||
@ -404,112 +342,9 @@ void QCitationDialog::updateInfo(QListView const * const qlv)
|
||||
}
|
||||
|
||||
|
||||
void QCitationDialog::on_selectedLV_clicked(const QModelIndex &)
|
||||
void QCitationDialog::setCitedKeys()
|
||||
{
|
||||
availableFocused_ = false;
|
||||
updateDialog();
|
||||
}
|
||||
|
||||
|
||||
void QCitationDialog::selectedChanged(const QModelIndex & idx, const QModelIndex &)
|
||||
{
|
||||
if (!idx.isValid())
|
||||
return;
|
||||
updateDialog();
|
||||
}
|
||||
|
||||
|
||||
void QCitationDialog::on_availableLV_clicked(const QModelIndex &)
|
||||
{
|
||||
availableFocused_ = true;
|
||||
updateDialog();
|
||||
}
|
||||
|
||||
|
||||
void QCitationDialog::availableChanged(const QModelIndex & idx, const QModelIndex &)
|
||||
{
|
||||
if (!idx.isValid())
|
||||
return;
|
||||
availableFocused_ = true;
|
||||
updateDialog();
|
||||
}
|
||||
|
||||
|
||||
void QCitationDialog::on_availableLV_doubleClicked(const QModelIndex & idx)
|
||||
{
|
||||
if (isSelected(idx))
|
||||
return;
|
||||
availableFocused_ = true;
|
||||
on_addPB_clicked();
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
//helper function for next two
|
||||
QModelIndex getSelectedIndex(QListView * lv) {
|
||||
//Encourage compiler to use NRVO
|
||||
QModelIndex retval = QModelIndex();
|
||||
QModelIndexList selIdx =
|
||||
lv->selectionModel()->selectedIndexes();
|
||||
if (!selIdx.empty())
|
||||
retval = selIdx.first();
|
||||
return retval;
|
||||
}
|
||||
}//anonymous namespace
|
||||
|
||||
|
||||
void QCitationDialog::on_addPB_clicked()
|
||||
{
|
||||
QModelIndex const idxToAdd = getSelectedIndex(availableLV);
|
||||
if (!idxToAdd.isValid())
|
||||
return;
|
||||
QModelIndex idx = selectedLV->currentIndex();
|
||||
form_->addKey(idxToAdd);
|
||||
if (idx.isValid())
|
||||
selectedLV->setCurrentIndex(idx);
|
||||
availableFocused_ = true;
|
||||
updateDialog();
|
||||
}
|
||||
|
||||
|
||||
void QCitationDialog::on_deletePB_clicked()
|
||||
{
|
||||
QModelIndex idx = getSelectedIndex(selectedLV);
|
||||
if (!idx.isValid())
|
||||
return;
|
||||
int nrows = selectedLV->model()->rowCount();
|
||||
|
||||
form_->deleteKey(idx);
|
||||
|
||||
if (idx.row() == nrows - 1)
|
||||
idx = idx.sibling(idx.row() - 1, idx.column());
|
||||
|
||||
if (nrows>1)
|
||||
selectedLV->setCurrentIndex(idx);
|
||||
availableFocused_ = true;
|
||||
updateDialog();
|
||||
}
|
||||
|
||||
|
||||
void QCitationDialog::on_upPB_clicked()
|
||||
{
|
||||
QModelIndex idx = selectedLV->currentIndex();
|
||||
form_->upKey(idx);
|
||||
selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column()));
|
||||
availableLV->selectionModel()->reset();
|
||||
availableFocused_ = false;
|
||||
updateDialog();
|
||||
}
|
||||
|
||||
|
||||
void QCitationDialog::on_downPB_clicked()
|
||||
{
|
||||
QModelIndex idx = selectedLV->currentIndex();
|
||||
form_->downKey(idx);
|
||||
selectedLV->setCurrentIndex(idx.sibling(idx.row() + 1, idx.column()));
|
||||
availableLV->selectionModel()->reset();
|
||||
availableFocused_ = false;
|
||||
updateDialog();
|
||||
form_->setCitedKeys();
|
||||
}
|
||||
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
*
|
||||
* \author Kalle Dalheimer
|
||||
* \author Abdelrazak Younes
|
||||
* \author Richard Heck
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*/
|
||||
@ -14,10 +15,13 @@
|
||||
#define QCITATIONDIALOG_H
|
||||
|
||||
#include "Dialog.h"
|
||||
#include "QSelectionManager.h"
|
||||
#include "ui_CitationUi.h"
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QStringList>
|
||||
#include <QStringListModel>
|
||||
|
||||
namespace lyx {
|
||||
namespace frontend {
|
||||
@ -43,14 +47,12 @@ public:
|
||||
/// Create the dialog if necessary, update it and display it.
|
||||
void show();
|
||||
|
||||
/// Update the display of the dialog whilst it is still visible.
|
||||
void update();
|
||||
|
||||
/// \return true if the dialog is visible.
|
||||
bool isVisible() const;
|
||||
|
||||
///
|
||||
bool eventFilter(QObject *, QEvent *);
|
||||
|
||||
public Q_SLOTS:
|
||||
/// Update the display of the dialog whilst it is still visible.
|
||||
void update();
|
||||
|
||||
protected:
|
||||
void closeEvent (QCloseEvent * e);
|
||||
@ -60,7 +62,7 @@ protected:
|
||||
/// check whether key is already selected
|
||||
bool isSelected(const QModelIndex &);
|
||||
/// update the display of BibTeX information
|
||||
void updateInfo(QListView const * const);
|
||||
void updateInfo(QModelIndex const &);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void cleanUp();
|
||||
@ -68,22 +70,17 @@ protected Q_SLOTS:
|
||||
void on_cancelPB_clicked();
|
||||
void on_restorePB_clicked();
|
||||
void on_applyPB_clicked();
|
||||
void on_addPB_clicked();
|
||||
void on_deletePB_clicked();
|
||||
void on_upPB_clicked();
|
||||
void on_downPB_clicked();
|
||||
void on_findLE_textChanged(const QString & text);
|
||||
void on_fieldsCO_currentIndexChanged(int index);
|
||||
void on_entriesCO_currentIndexChanged(int index);
|
||||
void on_caseCB_stateChanged(int);
|
||||
void on_regexCB_stateChanged(int);
|
||||
void on_selectedLV_clicked(const QModelIndex &);
|
||||
void selectedChanged(const QModelIndex &, const QModelIndex &);
|
||||
void on_availableLV_clicked(const QModelIndex &);
|
||||
void on_availableLV_doubleClicked(const QModelIndex &);
|
||||
void availableChanged(const QModelIndex &, const QModelIndex &);
|
||||
virtual void changed();
|
||||
|
||||
///
|
||||
void setCitedKeys();
|
||||
/// performs a limited update, suitable for internal call
|
||||
void updateDialog();
|
||||
|
||||
private:
|
||||
/// enable/disable buttons
|
||||
void setButtons();
|
||||
@ -95,16 +92,12 @@ private:
|
||||
void fillEntries();
|
||||
/// set the styles combo
|
||||
void updateStyle();
|
||||
/// performs a limited update, suitable for internal call
|
||||
void updateDialog();
|
||||
/// last used citation style
|
||||
int style_;
|
||||
/// which of available and selected is "focused", in the sense
|
||||
/// of which one should be used for updating the info via updateInfo().
|
||||
/// true, obviously, if it is availableLV.
|
||||
bool availableFocused_;
|
||||
|
||||
QCitation * form_;
|
||||
|
||||
QSelectionManager * selectionManager;
|
||||
};
|
||||
|
||||
} // namespace frontend
|
||||
|
291
src/frontends/qt4/QSelectionManager.cpp
Normal file
291
src/frontends/qt4/QSelectionManager.cpp
Normal file
@ -0,0 +1,291 @@
|
||||
/**
|
||||
* \file QSelectionManager.cpp
|
||||
* This file is part of LyX, the document processor.
|
||||
* Licence details can be found in the file COPYING.
|
||||
*
|
||||
* \author Richard Heck
|
||||
* \author Et Alia
|
||||
*
|
||||
* Some of the material in this file previously appeared in
|
||||
* QCitationDialog.cpp.
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "QSelectionManager.h"
|
||||
|
||||
|
||||
namespace lyx {
|
||||
namespace frontend {
|
||||
|
||||
QSelectionManager::QSelectionManager(
|
||||
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;
|
||||
|
||||
selectedLV->setModel(smod);
|
||||
availableLV->setModel(amod);
|
||||
|
||||
connect(availableLV->selectionModel(),
|
||||
SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
|
||||
this, SLOT(availableChanged(const QModelIndex &, const QModelIndex &)));
|
||||
connect(selectedLV->selectionModel(),
|
||||
SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
|
||||
this, SLOT(selectedChanged(const QModelIndex &, const QModelIndex &)));
|
||||
connect(addPB, SIGNAL(clicked()),
|
||||
this, SLOT(addPB_clicked()));
|
||||
connect(deletePB, SIGNAL(clicked()),
|
||||
this, SLOT(deletePB_clicked()));
|
||||
connect(upPB, SIGNAL(clicked()),
|
||||
this, SLOT(upPB_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 &)));
|
||||
|
||||
availableLV->installEventFilter(this);
|
||||
selectedLV->installEventFilter(this);
|
||||
}
|
||||
|
||||
|
||||
void QSelectionManager::update() {
|
||||
int const arows = availableLV->model()->rowCount();
|
||||
QModelIndexList const availSels =
|
||||
availableLV->selectionModel()->selectedIndexes();
|
||||
addPB->setEnabled(arows > 0 &&
|
||||
!availSels.isEmpty() &&
|
||||
!isSelected(availSels.first()));
|
||||
|
||||
int const srows = selectedLV->model()->rowCount();
|
||||
QModelIndexList const selSels =
|
||||
selectedLV->selectionModel()->selectedIndexes();
|
||||
int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
|
||||
deletePB->setEnabled(sel_nr >= 0);
|
||||
upPB->setEnabled(sel_nr > 0);
|
||||
downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
|
||||
}
|
||||
|
||||
|
||||
bool QSelectionManager::isSelected(const QModelIndex & idx)
|
||||
{
|
||||
QString const str = idx.data().toString();
|
||||
return selectedModel->stringList().contains(str);
|
||||
}
|
||||
|
||||
|
||||
void QSelectionManager::availableChanged(const QModelIndex & idx, const QModelIndex &)
|
||||
{
|
||||
if (!idx.isValid())
|
||||
return;
|
||||
|
||||
selectedHasFocus_ = false;
|
||||
updateHook();
|
||||
}
|
||||
|
||||
|
||||
void QSelectionManager::selectedChanged(const QModelIndex & idx, const QModelIndex &)
|
||||
{
|
||||
if (!idx.isValid())
|
||||
return;
|
||||
|
||||
selectedHasFocus_ = true;
|
||||
updateHook();
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
//helper function for next two
|
||||
QModelIndex getSelectedIndex(QListView * lv) {
|
||||
//Encourage compiler to use NRVO
|
||||
QModelIndex retval = QModelIndex();
|
||||
QModelIndexList selIdx =
|
||||
lv->selectionModel()->selectedIndexes();
|
||||
if (!selIdx.empty())
|
||||
retval = selIdx.first();
|
||||
return retval;
|
||||
}
|
||||
}//anonymous namespace
|
||||
|
||||
|
||||
void QSelectionManager::addPB_clicked()
|
||||
{
|
||||
QModelIndex const idxToAdd = getSelectedIndex(availableLV);
|
||||
if (!idxToAdd.isValid())
|
||||
return;
|
||||
QModelIndex idx = selectedLV->currentIndex();
|
||||
|
||||
QStringList keys = selectedModel->stringList();
|
||||
keys.append(idxToAdd.data().toString());
|
||||
selectedModel->setStringList(keys);
|
||||
selectionChanged(); //signal
|
||||
|
||||
if (idx.isValid())
|
||||
selectedLV->setCurrentIndex(idx);
|
||||
updateHook();
|
||||
}
|
||||
|
||||
|
||||
void QSelectionManager::deletePB_clicked()
|
||||
{
|
||||
QModelIndex idx = getSelectedIndex(selectedLV);
|
||||
if (!idx.isValid())
|
||||
return;
|
||||
|
||||
QStringList keys = selectedModel->stringList();
|
||||
keys.removeAt(idx.row());
|
||||
selectedModel->setStringList(keys);
|
||||
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));
|
||||
selectedHasFocus_ = (nrows > 0);
|
||||
updateHook();
|
||||
}
|
||||
|
||||
|
||||
void QSelectionManager::upPB_clicked()
|
||||
{
|
||||
QModelIndex idx = selectedLV->currentIndex();
|
||||
|
||||
int const pos = idx.row();
|
||||
QStringList keys = selectedModel->stringList();
|
||||
keys.swap(pos, pos - 1);
|
||||
selectedModel->setStringList(keys);
|
||||
selectionChanged(); //signal
|
||||
|
||||
selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column()));
|
||||
selectedHasFocus_ = true;
|
||||
updateHook();
|
||||
}
|
||||
|
||||
|
||||
void QSelectionManager::downPB_clicked()
|
||||
{
|
||||
QModelIndex idx = selectedLV->currentIndex();
|
||||
|
||||
int const pos = idx.row();
|
||||
QStringList keys = selectedModel->stringList();
|
||||
keys.swap(pos, pos + 1);
|
||||
selectedModel->setStringList(keys);
|
||||
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 QSelectionManager::availableLV_clicked(const QModelIndex &)
|
||||
{
|
||||
selectedHasFocus_ = false;
|
||||
updateHook();
|
||||
}
|
||||
|
||||
|
||||
void QSelectionManager::availableLV_doubleClicked(const QModelIndex & idx)
|
||||
{
|
||||
if (isSelected(idx))
|
||||
return;
|
||||
|
||||
if (idx.isValid())
|
||||
selectedHasFocus_ = false;
|
||||
addPB_clicked();
|
||||
//updateHook() will be emitted there
|
||||
}
|
||||
|
||||
|
||||
void QSelectionManager::selectedLV_clicked(const QModelIndex &)
|
||||
{
|
||||
selectedHasFocus_ = true;
|
||||
updateHook();
|
||||
}
|
||||
|
||||
|
||||
bool QSelectionManager::eventFilter(QObject * obj, QEvent * event)
|
||||
{
|
||||
if (obj == availableLV) {
|
||||
if (event->type() != QEvent::KeyPress)
|
||||
return QObject::eventFilter(obj, event);
|
||||
QKeyEvent * keyEvent = static_cast<QKeyEvent *>(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
|
||||
}
|
||||
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<QKeyEvent *>(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);
|
||||
updateHook();
|
||||
} else
|
||||
//ignore it otherwise
|
||||
return QObject::eventFilter(obj, event);
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
}//namespace frontend
|
||||
}//namespace lyx
|
||||
|
||||
#include "QSelectionManager_moc.cpp"
|
118
src/frontends/qt4/QSelectionManager.h
Normal file
118
src/frontends/qt4/QSelectionManager.h
Normal file
@ -0,0 +1,118 @@
|
||||
/**
|
||||
* \file QSelectionManager.h
|
||||
* This file is part of LyX, the document processor.
|
||||
* Licence details can be found in the file COPYING.
|
||||
*
|
||||
* \author Richard Heck
|
||||
* \author Et Alia
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*/
|
||||
|
||||
#ifndef QSELECTIONMANAGER_H
|
||||
#define QSELECTIONMANAGER_H
|
||||
|
||||
#include "Dialog.h"
|
||||
#include <QObject>
|
||||
#include <QKeyEvent>
|
||||
#include <QStringList>
|
||||
#include <QStringListModel>
|
||||
#include <QListView>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace lyx {
|
||||
namespace frontend {
|
||||
|
||||
/** Class to manage a collection of widgets that allows selection
|
||||
* of items from a list of available items. Adapted from code originally
|
||||
* written for QCitationDialog.
|
||||
* Note that this is a not a QWidget, though it could be converted to
|
||||
* one. Rather, the managed widgets---see constructor for descripton
|
||||
* of them---should be created independently, and then passed to the
|
||||
* constructor.
|
||||
*/
|
||||
class QSelectionManager: public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
///
|
||||
QSelectionManager(
|
||||
QListView * availableLV,
|
||||
QListView * selectedLV,
|
||||
QPushButton * addPB,
|
||||
QPushButton * delPB,
|
||||
QPushButton * upPB,
|
||||
QPushButton * downPB,
|
||||
QStringListModel * availableModel,
|
||||
QStringListModel * selectedModel);
|
||||
/// Sets the state of the various push buttons, depending upon the
|
||||
/// state of the widgets. (E.g., "delete" is enabled only if the
|
||||
/// selection is non-empty.)
|
||||
virtual void update();
|
||||
|
||||
/// Not strictly a matter of focus, which may be elsewhere, but
|
||||
/// whether selectedLV is `more focused' than availableLV. Intended
|
||||
/// to be used, for example, in displaying information about a
|
||||
/// highlighted item: should it be the highlighted available item
|
||||
/// or the highlighted selected item that is displayed?
|
||||
bool selectedFocused() { return selectedHasFocus_; };
|
||||
|
||||
Q_SIGNALS:
|
||||
///Emitted when the list of selected items has changed.
|
||||
void selectionChanged();
|
||||
///Emitted when something has changed that might lead the containing
|
||||
///dialog to want to update---the focused subwidget or selected item.
|
||||
///(Specifically, it is emitted by *_PB_clicked() and *_LV_clicked.)
|
||||
///NOTE: No automatic update of the button state is done here. If you
|
||||
///just want to do that, connect updateHook() to update(). Much of the
|
||||
///time, though, you will want to do a bit more processing first, so
|
||||
///you can connect to some other function that itself calls update().
|
||||
void updateHook();
|
||||
///Emitted on Ctrl-Enter in the availableLV. Intended to be connected
|
||||
///to an "OK" event in the parent dialog.
|
||||
void okHook();
|
||||
|
||||
|
||||
protected:
|
||||
///Given a QModelIndex from availableLV, determines whether it has
|
||||
///been selected (i.e., is also in selectedLV).
|
||||
bool isSelected(const QModelIndex & idx);
|
||||
|
||||
protected Q_SLOTS:
|
||||
///
|
||||
void availableChanged(const QModelIndex & idx, const QModelIndex &);
|
||||
///
|
||||
void selectedChanged(const QModelIndex & idx, const QModelIndex &);
|
||||
///
|
||||
void addPB_clicked();
|
||||
///
|
||||
void deletePB_clicked();
|
||||
///
|
||||
void upPB_clicked();
|
||||
///
|
||||
void downPB_clicked();
|
||||
///
|
||||
void availableLV_clicked(const QModelIndex &);
|
||||
///
|
||||
void availableLV_doubleClicked(const QModelIndex &);
|
||||
///
|
||||
void selectedLV_clicked(const QModelIndex &);
|
||||
///
|
||||
bool eventFilter(QObject *, QEvent *);
|
||||
|
||||
private:
|
||||
QListView * availableLV;
|
||||
QListView * selectedLV;
|
||||
QPushButton * addPB;
|
||||
QPushButton * deletePB;
|
||||
QPushButton * upPB;
|
||||
QPushButton * downPB;
|
||||
QStringListModel * availableModel;
|
||||
QStringListModel * selectedModel;
|
||||
Dialog::View * dialog;
|
||||
|
||||
bool selectedHasFocus_;
|
||||
};
|
||||
}//namespace frontend
|
||||
}//namespace lyx
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user