VCS: Add 'Check/Uncheck' all context menu to submit file list.

Update 'Commit' button to show number of files to be committed.
Task-number: QTCREATORBUG-2090
This commit is contained in:
Friedemann Kleint
2010-08-19 10:04:21 +02:00
parent e3f7a4024b
commit 817d4370d5
7 changed files with 105 additions and 21 deletions

View File

@@ -34,6 +34,7 @@
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QPointer> #include <QtCore/QPointer>
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtCore/QScopedPointer>
#include <QtGui/QPushButton> #include <QtGui/QPushButton>
#include <QtGui/QMenu> #include <QtGui/QMenu>
@@ -44,6 +45,8 @@
enum { debug = 0 }; enum { debug = 0 };
enum { defaultLineWidth = 72 }; enum { defaultLineWidth = 72 };
enum { checkableColumn = 0 };
namespace Utils { namespace Utils {
// QActionPushButton: A push button tied to an action // QActionPushButton: A push button tied to an action
@@ -68,10 +71,27 @@ QActionPushButton::QActionPushButton(QAction *a) :
void QActionPushButton::actionChanged() void QActionPushButton::actionChanged()
{ {
if (const QAction *a = qobject_cast<QAction*>(sender())) if (const QAction *a = qobject_cast<QAction*>(sender())) {
setEnabled(a->isEnabled()); setEnabled(a->isEnabled());
setText(a->text());
}
} }
// A helper parented on a QAction,
// making QAction::setText() a slot (which it currently is not).
class QActionSetTextSlotHelper : public QObject
{
Q_OBJECT
public:
explicit QActionSetTextSlotHelper(QAction *a) : QObject(a) {}
public slots:
void setText(const QString &t) {
if (QAction *action = qobject_cast<QAction *>(parent()))
action->setText(t);
}
};
// Helpers to retrieve model data // Helpers to retrieve model data
static inline bool listModelChecked(const QAbstractItemModel *model, int row, int column = 0) static inline bool listModelChecked(const QAbstractItemModel *model, int row, int column = 0)
{ {
@@ -79,22 +99,22 @@ static inline bool listModelChecked(const QAbstractItemModel *model, int row, in
return model->data(checkableIndex, Qt::CheckStateRole).toInt() == Qt::Checked; return model->data(checkableIndex, Qt::CheckStateRole).toInt() == Qt::Checked;
} }
static void setListModelChecked(QAbstractItemModel *model, bool checked, int column = 0)
{
const QVariant data = QVariant(int(checked ? Qt::Checked : Qt::Unchecked));
const int count = model->rowCount();
for (int i = 0; i < count; i++) {
const QModelIndex checkableIndex = model->index(i, column, QModelIndex());
model->setData(checkableIndex, data, Qt::CheckStateRole);
}
}
static inline QString listModelText(const QAbstractItemModel *model, int row, int column) static inline QString listModelText(const QAbstractItemModel *model, int row, int column)
{ {
const QModelIndex index = model->index(row, column, QModelIndex()); const QModelIndex index = model->index(row, column, QModelIndex());
return model->data(index, Qt::DisplayRole).toString(); return model->data(index, Qt::DisplayRole).toString();
} }
// Find a check item in a model
static bool listModelContainsCheckedItem(const QAbstractItemModel *model)
{
const int count = model->rowCount();
for (int i = 0; i < count; i++)
if (listModelChecked(model, i, 0))
return true;
return false;
}
// Convenience to extract a list of selected indexes // Convenience to extract a list of selected indexes
QList<int> selectedRows(const QAbstractItemView *view) QList<int> selectedRows(const QAbstractItemView *view)
{ {
@@ -151,6 +171,9 @@ SubmitEditorWidget::SubmitEditorWidget(QWidget *parent) :
this, SLOT(editorCustomContextMenuRequested(QPoint))); this, SLOT(editorCustomContextMenuRequested(QPoint)));
// File List // File List
m_d->m_ui.fileView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_d->m_ui.fileView, SIGNAL(customContextMenuRequested(QPoint)),
this, SLOT(fileListCustomContextMenuRequested(QPoint)));
m_d->m_ui.fileView->setSelectionMode(QAbstractItemView::ExtendedSelection); m_d->m_ui.fileView->setSelectionMode(QAbstractItemView::ExtendedSelection);
m_d->m_ui.fileView->setRootIsDecorated(false); m_d->m_ui.fileView->setRootIsDecorated(false);
connect(m_d->m_ui.fileView, SIGNAL(doubleClicked(QModelIndex)), connect(m_d->m_ui.fileView, SIGNAL(doubleClicked(QModelIndex)),
@@ -188,6 +211,11 @@ void SubmitEditorWidget::registerActions(QAction *editorUndoAction, QAction *edi
} }
submitAction->setEnabled(m_d->m_filesChecked); submitAction->setEnabled(m_d->m_filesChecked);
connect(this, SIGNAL(fileCheckStateChanged(bool)), submitAction, SLOT(setEnabled(bool))); connect(this, SIGNAL(fileCheckStateChanged(bool)), submitAction, SLOT(setEnabled(bool)));
// Wire setText via QActionSetTextSlotHelper.
QActionSetTextSlotHelper *actionSlotHelper = submitAction->findChild<QActionSetTextSlotHelper *>();
if (!actionSlotHelper)
actionSlotHelper = new QActionSetTextSlotHelper(submitAction);
connect(this, SIGNAL(submitActionTextChanged(QString)), actionSlotHelper, SLOT(setText(QString)));
m_d->m_ui.buttonLayout->addWidget(new QActionPushButton(submitAction)); m_d->m_ui.buttonLayout->addWidget(new QActionPushButton(submitAction));
} }
if (diffAction) { if (diffAction) {
@@ -212,8 +240,11 @@ void SubmitEditorWidget::unregisterActions(QAction *editorUndoAction, QAction *
disconnect(editorRedoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(redo())); disconnect(editorRedoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(redo()));
} }
if (submitAction) if (submitAction) {
disconnect(this, SIGNAL(fileCheckStateChanged(bool)), submitAction, SLOT(setEnabled(bool))); disconnect(this, SIGNAL(fileCheckStateChanged(bool)), submitAction, SLOT(setEnabled(bool)));
// Just deactivate the QActionSetTextSlotHelper on the action
disconnect(this, SIGNAL(submitActionTextChanged(QString)), 0, 0);
}
if (diffAction) { if (diffAction) {
disconnect(this, SIGNAL(fileSelectionChanged(bool)), diffAction, SLOT(setEnabled(bool))); disconnect(this, SIGNAL(fileSelectionChanged(bool)), diffAction, SLOT(setEnabled(bool)));
@@ -374,7 +405,7 @@ QStringList SubmitEditorWidget::checkedFiles() const
return rc; return rc;
const int count = model->rowCount(); const int count = model->rowCount();
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
if (listModelChecked(model, i, 0)) if (listModelChecked(model, i, checkableColumn))
rc.push_back(listModelText(model, i, fileNameColumn())); rc.push_back(listModelText(model, i, fileNameColumn()));
return rc; return rc;
} }
@@ -414,11 +445,19 @@ void SubmitEditorWidget::updateActions()
// Enable submit depending on having checked files // Enable submit depending on having checked files
void SubmitEditorWidget::updateSubmitAction() void SubmitEditorWidget::updateSubmitAction()
{ {
const bool newFilesCheckedState = hasCheckedFiles(); const unsigned checkedCount = checkedFilesCount();
const bool newFilesCheckedState = checkedCount;
// Emit signal to update action
if (m_d->m_filesChecked != newFilesCheckedState) { if (m_d->m_filesChecked != newFilesCheckedState) {
m_d->m_filesChecked = newFilesCheckedState; m_d->m_filesChecked = newFilesCheckedState;
emit fileCheckStateChanged(m_d->m_filesChecked); emit fileCheckStateChanged(m_d->m_filesChecked);
} }
// Update button text.
const int fileCount = m_d->m_ui.fileView->model()->rowCount();
const QString msg = checkedCount ?
tr("Commit %1/%2 Files").arg(checkedCount).arg(fileCount) :
tr("Commit");
emit submitActionTextChanged(msg);
} }
// Enable diff depending on selected files // Enable diff depending on selected files
@@ -439,11 +478,16 @@ bool SubmitEditorWidget::hasSelection() const
return false; return false;
} }
bool SubmitEditorWidget::hasCheckedFiles() const unsigned SubmitEditorWidget::checkedFilesCount() const
{ {
if (const QAbstractItemModel *model = m_d->m_ui.fileView->model()) unsigned checkedCount = 0;
return listModelContainsCheckedItem(model); if (const QAbstractItemModel *model = m_d->m_ui.fileView->model()) {
return false; const int count = model->rowCount();
for (int i = 0; i < count; i++)
if (listModelChecked(model, i, checkableColumn))
checkedCount++;
}
return checkedCount;
} }
void SubmitEditorWidget::changeEvent(QEvent *e) void SubmitEditorWidget::changeEvent(QEvent *e)
@@ -496,7 +540,7 @@ void SubmitEditorWidget::insertDescriptionEditContextMenuAction(int pos, QAction
void SubmitEditorWidget::editorCustomContextMenuRequested(const QPoint &pos) void SubmitEditorWidget::editorCustomContextMenuRequested(const QPoint &pos)
{ {
QMenu *menu = m_d->m_ui.description->createStandardContextMenu(); QScopedPointer<QMenu> menu(m_d->m_ui.description->createStandardContextMenu());
// Extend // Extend
foreach (const SubmitEditorWidgetPrivate::AdditionalContextMenuAction &a, m_d->descriptionEditContextMenuActions) { foreach (const SubmitEditorWidgetPrivate::AdditionalContextMenuAction &a, m_d->descriptionEditContextMenuActions) {
if (a.second) { if (a.second) {
@@ -508,7 +552,33 @@ void SubmitEditorWidget::editorCustomContextMenuRequested(const QPoint &pos)
} }
} }
menu->exec(m_d->m_ui.description->mapToGlobal(pos)); menu->exec(m_d->m_ui.description->mapToGlobal(pos));
delete menu; }
void SubmitEditorWidget::checkAll()
{
setListModelChecked(m_d->m_ui.fileView->model(), true, checkableColumn);
}
void SubmitEditorWidget::uncheckAll()
{
setListModelChecked(m_d->m_ui.fileView->model(), false, checkableColumn);
}
void SubmitEditorWidget::fileListCustomContextMenuRequested(const QPoint & pos)
{
// Execute menu offering to check/uncheck all
QMenu menu;
QAction *checkAllAction = menu.addAction(tr("Check All"));
QAction *uncheckAllAction = menu.addAction(tr("Uncheck All"));
QAction *action = menu.exec(m_d->m_ui.fileView->mapToGlobal(pos));
if (action == checkAllAction) {
checkAll();
return;
}
if (action == uncheckAllAction) {
uncheckAll();
return;
}
} }
} // namespace Utils } // namespace Utils

View File

@@ -80,6 +80,9 @@ public:
explicit SubmitEditorWidget(QWidget *parent = 0); explicit SubmitEditorWidget(QWidget *parent = 0);
virtual ~SubmitEditorWidget(); virtual ~SubmitEditorWidget();
// Register/Unregister actions that are managed by ActionManager with this widget.
// The submit action should have Core::Command::CA_UpdateText set as its text will
// be updated.
void registerActions(QAction *editorUndoAction, QAction *editorRedoAction, void registerActions(QAction *editorUndoAction, QAction *editorRedoAction,
QAction *submitAction = 0, QAction *diffAction = 0); QAction *submitAction = 0, QAction *diffAction = 0);
void unregisterActions(QAction *editorUndoAction, QAction *editorRedoAction, void unregisterActions(QAction *editorUndoAction, QAction *editorRedoAction,
@@ -121,6 +124,11 @@ signals:
void diffSelected(const QStringList &); void diffSelected(const QStringList &);
void fileSelectionChanged(bool someFileSelected); void fileSelectionChanged(bool someFileSelected);
void fileCheckStateChanged(bool someFileChecked); void fileCheckStateChanged(bool someFileChecked);
void submitActionTextChanged(const QString &);
public slots:
void checkAll();
void uncheckAll();
protected: protected:
virtual void changeEvent(QEvent *e); virtual void changeEvent(QEvent *e);
@@ -134,10 +142,11 @@ private slots:
void updateSubmitAction(); void updateSubmitAction();
void updateDiffAction(); void updateDiffAction();
void editorCustomContextMenuRequested(const QPoint &); void editorCustomContextMenuRequested(const QPoint &);
void fileListCustomContextMenuRequested(const QPoint & pos);
private: private:
bool hasSelection() const; bool hasSelection() const;
bool hasCheckedFiles() const; unsigned checkedFilesCount() const;
SubmitEditorWidgetPrivate *m_d; SubmitEditorWidgetPrivate *m_d;
}; };

View File

@@ -450,6 +450,7 @@ bool CVSPlugin::initialize(const QStringList & /*arguments */, QString *errorMes
m_submitCurrentLogAction = new QAction(VCSBase::VCSBaseSubmitEditor::submitIcon(), tr("Commit"), this); m_submitCurrentLogAction = new QAction(VCSBase::VCSBaseSubmitEditor::submitIcon(), tr("Commit"), this);
command = ami->registerAction(m_submitCurrentLogAction, Constants::SUBMIT_CURRENT, cvscommitcontext); command = ami->registerAction(m_submitCurrentLogAction, Constants::SUBMIT_CURRENT, cvscommitcontext);
command->setAttribute(Core::Command::CA_UpdateText);
connect(m_submitCurrentLogAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog())); connect(m_submitCurrentLogAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog()));
m_submitDiffAction = new QAction(VCSBase::VCSBaseSubmitEditor::diffIcon(), tr("Diff Selected Files"), this); m_submitDiffAction = new QAction(VCSBase::VCSBaseSubmitEditor::diffIcon(), tr("Diff Selected Files"), this);

View File

@@ -500,6 +500,7 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
Core::Context submitContext(Constants::C_GITSUBMITEDITOR); Core::Context submitContext(Constants::C_GITSUBMITEDITOR);
m_submitCurrentAction = new QAction(VCSBase::VCSBaseSubmitEditor::submitIcon(), tr("Commit"), this); m_submitCurrentAction = new QAction(VCSBase::VCSBaseSubmitEditor::submitIcon(), tr("Commit"), this);
Core::Command *command = actionManager->registerAction(m_submitCurrentAction, Constants::SUBMIT_CURRENT, submitContext); Core::Command *command = actionManager->registerAction(m_submitCurrentAction, Constants::SUBMIT_CURRENT, submitContext);
command->setAttribute(Core::Command::CA_UpdateText);
connect(m_submitCurrentAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog())); connect(m_submitCurrentAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog()));
m_diffSelectedFilesAction = new QAction(VCSBase::VCSBaseSubmitEditor::diffIcon(), tr("Diff Selected Files"), this); m_diffSelectedFilesAction = new QAction(VCSBase::VCSBaseSubmitEditor::diffIcon(), tr("Diff Selected Files"), this);

View File

@@ -538,6 +538,7 @@ void MercurialPlugin::createSubmitEditorActions()
editorCommit = new QAction(VCSBase::VCSBaseSubmitEditor::submitIcon(), tr("Commit"), this); editorCommit = new QAction(VCSBase::VCSBaseSubmitEditor::submitIcon(), tr("Commit"), this);
command = actionManager->registerAction(editorCommit, QLatin1String(Constants::COMMIT), context); command = actionManager->registerAction(editorCommit, QLatin1String(Constants::COMMIT), context);
command->setAttribute(Core::Command::CA_UpdateText);
connect(editorCommit, SIGNAL(triggered()), this, SLOT(commitFromEditor())); connect(editorCommit, SIGNAL(triggered()), this, SLOT(commitFromEditor()));
editorDiff = new QAction(VCSBase::VCSBaseSubmitEditor::diffIcon(), tr("Diff Selected Files"), this); editorDiff = new QAction(VCSBase::VCSBaseSubmitEditor::diffIcon(), tr("Diff Selected Files"), this);

View File

@@ -435,6 +435,7 @@ bool PerforcePlugin::initialize(const QStringList & /* arguments */, QString *er
m_submitCurrentLogAction = new QAction(VCSBase::VCSBaseSubmitEditor::submitIcon(), tr("Submit"), this); m_submitCurrentLogAction = new QAction(VCSBase::VCSBaseSubmitEditor::submitIcon(), tr("Submit"), this);
command = am->registerAction(m_submitCurrentLogAction, Constants::SUBMIT_CURRENT, perforcesubmitcontext); command = am->registerAction(m_submitCurrentLogAction, Constants::SUBMIT_CURRENT, perforcesubmitcontext);
command->setAttribute(Core::Command::CA_UpdateText);
connect(m_submitCurrentLogAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog())); connect(m_submitCurrentLogAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog()));
m_diffSelectedFiles = new QAction(VCSBase::VCSBaseSubmitEditor::diffIcon(), tr("Diff Selected Files"), this); m_diffSelectedFiles = new QAction(VCSBase::VCSBaseSubmitEditor::diffIcon(), tr("Diff Selected Files"), this);

View File

@@ -458,6 +458,7 @@ bool SubversionPlugin::initialize(const QStringList & /*arguments */, QString *e
m_submitCurrentLogAction = new QAction(VCSBase::VCSBaseSubmitEditor::submitIcon(), tr("Commit"), this); m_submitCurrentLogAction = new QAction(VCSBase::VCSBaseSubmitEditor::submitIcon(), tr("Commit"), this);
command = ami->registerAction(m_submitCurrentLogAction, Constants::SUBMIT_CURRENT, svncommitcontext); command = ami->registerAction(m_submitCurrentLogAction, Constants::SUBMIT_CURRENT, svncommitcontext);
command->setAttribute(Core::Command::CA_UpdateText);
connect(m_submitCurrentLogAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog())); connect(m_submitCurrentLogAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog()));
m_submitDiffAction = new QAction(VCSBase::VCSBaseSubmitEditor::diffIcon(), tr("Diff Selected Files"), this); m_submitDiffAction = new QAction(VCSBase::VCSBaseSubmitEditor::diffIcon(), tr("Diff Selected Files"), this);