bazaarplugin.cpp 26.1 KB
Newer Older
cerf's avatar
cerf committed
1 2 3 4 5 6
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Hugues Delorme
**
hjk's avatar
hjk committed
7
** Contact: Nokia Corporation (info@qt.nokia.com)
cerf's avatar
cerf committed
8 9 10 11
**
**
** GNU Lesser General Public License Usage
**
hjk's avatar
hjk committed
12 13 14 15 16 17
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
cerf's avatar
cerf committed
18 19
**
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
cerf's avatar
cerf committed
21 22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23 24 25 26 27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
cerf's avatar
cerf committed
28
** If you have questions regarding the use of this file, please contact
Tobias Hunger's avatar
Tobias Hunger committed
29
** Nokia at info@qt.nokia.com.
cerf's avatar
cerf committed
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
**
**************************************************************************/

#include "bazaarplugin.h"
#include "constants.h"
#include "bazaarclient.h"
#include "bazaarcontrol.h"
#include "optionspage.h"
#include "bazaarcommitwidget.h"
#include "bazaareditor.h"
#include "pullorpushdialog.h"
#include "commiteditor.h"
#include "clonewizard.h"

#include "ui_revertdialog.h"

#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/command.h>
49
#include <coreplugin/id.h>
cerf's avatar
cerf committed
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
#include <coreplugin/vcsmanager.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h>
#include <coreplugin/filemanager.h>
#include <coreplugin/editormanager/editormanager.h>

#include <locator/commandlocator.h>

#include <utils/parameteraction.h>
#include <utils/qtcassert.h>

#include <vcsbase/basevcseditorfactory.h>
#include <vcsbase/basevcssubmiteditorfactory.h>
#include <vcsbase/vcsbasesubmiteditor.h>
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/vcsbaseoutputwindow.h>

#include <QtCore/QtPlugin>
#include <QtGui/QAction>
#include <QtGui/QMenu>
#include <QtGui/QMainWindow>
#include <QtCore/QtDebug>
#include <QtCore/QtGlobal>
#include <QtCore/QDir>
#include <QtGui/QDialog>
#include <QtGui/QFileDialog>
#include <QtCore/QTemporaryFile>


using namespace Bazaar::Internal;
using namespace Bazaar;

static const VCSBase::VCSBaseEditorParameters editorParameters[] = {
    {
        VCSBase::RegularCommandOutput, //type
        Constants::COMMANDLOG_ID, // id
        Constants::COMMANDLOG_DISPLAY_NAME, // display name
        Constants::COMMANDLOG, // context
        Constants::COMMANDAPP, // mime type
        Constants::COMMANDEXT}, //extension

    {   VCSBase::LogOutput,
        Constants::FILELOG_ID,
        Constants::FILELOG_DISPLAY_NAME,
        Constants::FILELOG,
        Constants::LOGAPP,
        Constants::LOGEXT},

    {    VCSBase::AnnotateOutput,
         Constants::ANNOTATELOG_ID,
         Constants::ANNOTATELOG_DISPLAY_NAME,
         Constants::ANNOTATELOG,
         Constants::ANNOTATEAPP,
         Constants::ANNOTATEEXT},

    {   VCSBase::DiffOutput,
        Constants::DIFFLOG_ID,
        Constants::DIFFLOG_DISPLAY_NAME,
        Constants::DIFFLOG,
        Constants::DIFFAPP,
        Constants::DIFFEXT}
};

static const VCSBase::VCSBaseSubmitEditorParameters submitEditorParameters = {
    Constants::COMMITMIMETYPE,
    Constants::COMMIT_ID,
    Constants::COMMIT_DISPLAY_NAME,
    Constants::COMMIT_ID
};


BazaarPlugin *BazaarPlugin::m_instance = 0;

BazaarPlugin::BazaarPlugin() :
    VCSBase::VCSBasePlugin(QLatin1String(Constants::COMMIT_ID)),
    m_optionsPage(0),
    m_client(0),
    m_core(0),
    m_commandLocator(0),
    m_changeLog(0),
    m_addAction(0),
    m_deleteAction(0),
    m_menuAction(0)
{
    m_instance = this;
}

BazaarPlugin::~BazaarPlugin()
{
    if (m_client) {
        delete m_client;
        m_client = 0;
    }

    deleteCommitLog();

    m_instance = 0;
}

149
bool BazaarPlugin::initialize(const QStringList &arguments, QString *errorMessage)
cerf's avatar
cerf committed
150
{
151 152 153
    Q_UNUSED(arguments);
    Q_UNUSED(errorMessage);

cerf's avatar
cerf committed
154 155
    typedef VCSBase::VCSEditorFactory<BazaarEditor> BazaarEditorFactory;

156
    m_client = new BazaarClient(&m_bazaarSettings);
157
    initializeVcs(new BazaarControl(m_client));
cerf's avatar
cerf committed
158 159 160 161 162 163

    m_core = Core::ICore::instance();
    m_actionManager = m_core->actionManager();

    m_optionsPage = new OptionsPage();
    addAutoReleasedObject(m_optionsPage);
164
    m_bazaarSettings.readSettings(m_core->settings());
cerf's avatar
cerf committed
165

166
    connect(m_optionsPage, SIGNAL(settingsChanged()), m_client, SLOT(handleSettingsChanged()));
cerf's avatar
cerf committed
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
    connect(m_client, SIGNAL(changed(QVariant)), versionControl(), SLOT(changed(QVariant)));

    static const char *describeSlot = SLOT(view(QString,QString));
    const int editorCount = sizeof(editorParameters) / sizeof(VCSBase::VCSBaseEditorParameters);
    for (int i = 0; i < editorCount; i++)
        addAutoReleasedObject(new BazaarEditorFactory(editorParameters + i, m_client, describeSlot));

    addAutoReleasedObject(new VCSBase::VCSSubmitEditorFactory<CommitEditor>(&submitEditorParameters));

    addAutoReleasedObject(new CloneWizard);

    const QString prefix = QLatin1String("bzr");
    m_commandLocator = new Locator::CommandLocator(QLatin1String("Bazaar"), prefix, prefix);
    addAutoReleasedObject(m_commandLocator);

    createMenu();

    createSubmitEditorActions();

    return true;
}

BazaarPlugin *BazaarPlugin::instance()
{
    return m_instance;
}

BazaarClient *BazaarPlugin::client() const
{
    return m_client;
}

const BazaarSettings &BazaarPlugin::settings() const
{
    return m_bazaarSettings;
}

void BazaarPlugin::setSettings(const BazaarSettings &settings)
{
    if (settings != m_bazaarSettings) {
cerf's avatar
cerf committed
207 208 209 210
        const bool userIdChanged = !m_bazaarSettings.sameUserId(settings);
        m_bazaarSettings = settings;
        if (userIdChanged)
            client()->synchronousSetUserId();
211
        static_cast<BazaarControl *>(versionControl())->emitConfigurationChanged();
cerf's avatar
cerf committed
212 213 214 215 216 217 218 219 220 221 222 223 224
    }
}

void BazaarPlugin::createMenu()
{
    Core::Context context(Core::Constants::C_GLOBAL);

    // Create menu item for Bazaar
    m_bazaarContainer = m_actionManager->createMenu(Core::Id("Bazaar.BazaarMenu"));
    QMenu *menu = m_bazaarContainer->menu();
    menu->setTitle(tr("Bazaar"));

    createFileActions(context);
225
    createSeparator(context, Core::Id("Bazaar.FileDirSeperator"));
cerf's avatar
cerf committed
226
    createDirectoryActions(context);
227
    createSeparator(context, Core::Id("Bazaar.DirRepoSeperator"));
cerf's avatar
cerf committed
228
    createRepositoryActions(context);
229
    createSeparator(context, Core::Id("Bazaar.Repository Management"));
cerf's avatar
cerf committed
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250

    // Request the Tools menu and add the Bazaar menu to it
    Core::ActionContainer *toolsMenu = m_actionManager->actionContainer(Core::Id(Core::Constants::M_TOOLS));
    toolsMenu->addMenu(m_bazaarContainer);
    m_menuAction = m_bazaarContainer->menu()->menuAction();
}

void BazaarPlugin::createFileActions(const Core::Context &context)
{
    Core::Command *command;

    m_annotateFile = new Utils::ParameterAction(tr("Annotate Current File"), tr("Annotate \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
    command = m_actionManager->registerAction(m_annotateFile, Core::Id(Constants::ANNOTATE), context);
    command->setAttribute(Core::Command::CA_UpdateText);
    connect(m_annotateFile, SIGNAL(triggered()), this, SLOT(annotateCurrentFile()));
    m_bazaarContainer->addAction(command);
    m_commandLocator->appendCommand(command);

    m_diffFile = new Utils::ParameterAction(tr("Diff Current File"), tr("Diff \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
    command = m_actionManager->registerAction(m_diffFile, Core::Id(Constants::DIFF), context);
    command->setAttribute(Core::Command::CA_UpdateText);
251
    command->setDefaultKeySequence(QKeySequence(tr("ALT+Z,Alt+D")));
cerf's avatar
cerf committed
252 253 254 255 256 257 258
    connect(m_diffFile, SIGNAL(triggered()), this, SLOT(diffCurrentFile()));
    m_bazaarContainer->addAction(command);
    m_commandLocator->appendCommand(command);

    m_logFile = new Utils::ParameterAction(tr("Log Current File"), tr("Log \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
    command = m_actionManager->registerAction(m_logFile, Core::Id(Constants::LOG), context);
    command->setAttribute(Core::Command::CA_UpdateText);
259
    command->setDefaultKeySequence(QKeySequence(tr("ALT+Z,Alt+L")));
cerf's avatar
cerf committed
260 261 262 263 264 265 266
    connect(m_logFile, SIGNAL(triggered()), this, SLOT(logCurrentFile()));
    m_bazaarContainer->addAction(command);
    m_commandLocator->appendCommand(command);

    m_statusFile = new Utils::ParameterAction(tr("Status Current File"), tr("Status \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
    command = m_actionManager->registerAction(m_statusFile, Core::Id(Constants::STATUS), context);
    command->setAttribute(Core::Command::CA_UpdateText);
267
    command->setDefaultKeySequence(QKeySequence(tr("ALT+Z,Alt+S")));
cerf's avatar
cerf committed
268 269 270 271
    connect(m_statusFile, SIGNAL(triggered()), this, SLOT(statusCurrentFile()));
    m_bazaarContainer->addAction(command);
    m_commandLocator->appendCommand(command);

272
    createSeparator(context, Core::Id("Bazaar.FileDirSeperator1"));
cerf's avatar
cerf committed
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298

    m_addAction = new Utils::ParameterAction(tr("Add"), tr("Add \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
    command = m_actionManager->registerAction(m_addAction, Core::Id(Constants::ADD), context);
    command->setAttribute(Core::Command::CA_UpdateText);
    connect(m_addAction, SIGNAL(triggered()), this, SLOT(addCurrentFile()));
    m_bazaarContainer->addAction(command);
    m_commandLocator->appendCommand(command);

    m_deleteAction = new Utils::ParameterAction(tr("Delete..."), tr("Delete \"%1\"..."), Utils::ParameterAction::EnabledWithParameter, this);
    command = m_actionManager->registerAction(m_deleteAction, Core::Id(Constants::DELETE), context);
    command->setAttribute(Core::Command::CA_UpdateText);
    connect(m_deleteAction, SIGNAL(triggered()), this, SLOT(promptToDeleteCurrentFile()));
    m_bazaarContainer->addAction(command);
    m_commandLocator->appendCommand(command);

    m_revertFile = new Utils::ParameterAction(tr("Revert Current File..."), tr("Revert \"%1\"..."), Utils::ParameterAction::EnabledWithParameter, this);
    command = m_actionManager->registerAction(m_revertFile, Core::Id(Constants::REVERT), context);
    command->setAttribute(Core::Command::CA_UpdateText);
    connect(m_revertFile, SIGNAL(triggered()), this, SLOT(revertCurrentFile()));
    m_bazaarContainer->addAction(command);
    m_commandLocator->appendCommand(command);
}

void BazaarPlugin::addCurrentFile()
{
    const VCSBase::VCSBasePluginState state = currentState();
Tobias Hunger's avatar
Tobias Hunger committed
299 300
    QTC_ASSERT(state.hasFile(), return);
    m_client->synchronousAdd(state.currentFileTopLevel(), state.relativeCurrentFile());
cerf's avatar
cerf committed
301 302 303 304 305
}

void BazaarPlugin::annotateCurrentFile()
{
    const VCSBase::VCSBasePluginState state = currentState();
Tobias Hunger's avatar
Tobias Hunger committed
306 307
    QTC_ASSERT(state.hasFile(), return);
    m_client->annotate(state.currentFileTopLevel(), state.relativeCurrentFile());
cerf's avatar
cerf committed
308 309 310 311 312
}

void BazaarPlugin::diffCurrentFile()
{
    const VCSBase::VCSBasePluginState state = currentState();
Tobias Hunger's avatar
Tobias Hunger committed
313 314
    QTC_ASSERT(state.hasFile(), return);
    m_client->diff(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
cerf's avatar
cerf committed
315 316 317 318 319
}

void BazaarPlugin::logCurrentFile()
{
    const VCSBase::VCSBasePluginState state = currentState();
Tobias Hunger's avatar
Tobias Hunger committed
320
    QTC_ASSERT(state.hasFile(), return);
321
    m_client->log(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()),
322
                  QStringList(), true);
cerf's avatar
cerf committed
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
}

void BazaarPlugin::revertCurrentFile()
{
    const VCSBase::VCSBasePluginState state = currentState();
    QTC_ASSERT(state.hasFile(), return);

    QDialog dialog;
    Ui::RevertDialog revertUi;
    revertUi.setupUi(&dialog);
    if (dialog.exec() != QDialog::Accepted)
        return;
    m_client->revertFile(state.currentFileTopLevel(),
                         state.relativeCurrentFile(),
                         revertUi.revisionLineEdit->text());
}

void BazaarPlugin::statusCurrentFile()
{
    const VCSBase::VCSBasePluginState state = currentState();
Tobias Hunger's avatar
Tobias Hunger committed
343 344
    QTC_ASSERT(state.hasFile(), return);
    m_client->status(state.currentFileTopLevel(), state.relativeCurrentFile());
cerf's avatar
cerf committed
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
}

void BazaarPlugin::createDirectoryActions(const Core::Context &context)
{
    QAction *action;
    Core::Command *command;

    action = new QAction(tr("Diff"), this);
    m_repositoryActionList.append(action);
    command = m_actionManager->registerAction(action, Core::Id(Constants::DIFFMULTI), context);
    connect(action, SIGNAL(triggered()), this, SLOT(diffRepository()));
    m_bazaarContainer->addAction(command);
    m_commandLocator->appendCommand(command);

    action = new QAction(tr("Log"), this);
    m_repositoryActionList.append(action);
    command = m_actionManager->registerAction(action, Core::Id(Constants::LOGMULTI), context);
    connect(action, SIGNAL(triggered()), this, SLOT(logRepository()));
    m_bazaarContainer->addAction(command);
    m_commandLocator->appendCommand(command);

    action = new QAction(tr("Revert..."), this);
    m_repositoryActionList.append(action);
    command = m_actionManager->registerAction(action, Core::Id(Constants::REVERTMULTI), context);
    connect(action, SIGNAL(triggered()), this, SLOT(revertAll()));
    m_bazaarContainer->addAction(command);
    m_commandLocator->appendCommand(command);

    action = new QAction(tr("Status"), this);
    m_repositoryActionList.append(action);
    command = m_actionManager->registerAction(action, Core::Id(Constants::STATUSMULTI), context);
    connect(action, SIGNAL(triggered()), this, SLOT(statusMulti()));
    m_bazaarContainer->addAction(command);
    m_commandLocator->appendCommand(command);
}


void BazaarPlugin::diffRepository()
{
    const VCSBase::VCSBasePluginState state = currentState();
Tobias Hunger's avatar
Tobias Hunger committed
385 386
    QTC_ASSERT(state.hasTopLevel(), return);
    m_client->diff(state.topLevel());
cerf's avatar
cerf committed
387 388 389 390 391
}

void BazaarPlugin::logRepository()
{
    const VCSBase::VCSBasePluginState state = currentState();
Tobias Hunger's avatar
Tobias Hunger committed
392
    QTC_ASSERT(state.hasTopLevel(), return);
393 394 395
    QStringList extraOptions;
    extraOptions += QString("--limit=%1").arg(settings().logCount());
    m_client->log(state.topLevel(), QStringList(), extraOptions);
cerf's avatar
cerf committed
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
}

void BazaarPlugin::revertAll()
{
    const VCSBase::VCSBasePluginState state = currentState();
    QTC_ASSERT(state.hasTopLevel(), return);

    QDialog dialog;
    Ui::RevertDialog revertUi;
    revertUi.setupUi(&dialog);
    if (dialog.exec() != QDialog::Accepted)
        return;
    m_client->revertAll(state.topLevel(), revertUi.revisionLineEdit->text());
}

void BazaarPlugin::statusMulti()
{
    const VCSBase::VCSBasePluginState state = currentState();
    QTC_ASSERT(state.hasTopLevel(), return);
    m_client->status(state.topLevel());
}

void BazaarPlugin::createRepositoryActions(const Core::Context &context)
{
    QAction *action = 0;
    Core::Command *command = 0;

    action = new QAction(tr("Pull..."), this);
    m_repositoryActionList.append(action);
    command = m_actionManager->registerAction(action, Core::Id(Constants::PULL), context);
    connect(action, SIGNAL(triggered()), this, SLOT(pull()));
    m_bazaarContainer->addAction(command);
    m_commandLocator->appendCommand(command);

    action = new QAction(tr("Push..."), this);
    m_repositoryActionList.append(action);
    command = m_actionManager->registerAction(action, Core::Id(Constants::PUSH), context);
    connect(action, SIGNAL(triggered()), this, SLOT(push()));
    m_bazaarContainer->addAction(command);
    m_commandLocator->appendCommand(command);

    action = new QAction(tr("Update..."), this);
    m_repositoryActionList.append(action);
    command = m_actionManager->registerAction(action, Core::Id(Constants::UPDATE), context);
    connect(action, SIGNAL(triggered()), this, SLOT(update()));
    m_bazaarContainer->addAction(command);
    m_commandLocator->appendCommand(command);

    action = new QAction(tr("Commit..."), this);
    m_repositoryActionList.append(action);
    command = m_actionManager->registerAction(action, Core::Id(Constants::COMMIT), context);
447
    command->setDefaultKeySequence(QKeySequence(tr("ALT+Z,Alt+C")));
cerf's avatar
cerf committed
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
    connect(action, SIGNAL(triggered()), this, SLOT(commit()));
    m_bazaarContainer->addAction(command);
    m_commandLocator->appendCommand(command);

    QAction* createRepositoryAction = new QAction(tr("Create Repository..."), this);
    command = m_actionManager->registerAction(createRepositoryAction, Core::Id(Constants::CREATE_REPOSITORY), context);
    connect(createRepositoryAction, SIGNAL(triggered()), this, SLOT(createRepository()));
    m_bazaarContainer->addAction(command);
}

void BazaarPlugin::pull()
{
    const VCSBase::VCSBasePluginState state = currentState();
    QTC_ASSERT(state.hasTopLevel(), return);

    PullOrPushDialog dialog(PullOrPushDialog::PullMode);
    if (dialog.exec() != QDialog::Accepted)
        return;
466 467 468 469 470 471 472 473 474
    QStringList extraOptions;
    if (dialog.isRememberOptionEnabled())
        extraOptions += QLatin1String("--remember");
    if (dialog.isOverwriteOptionEnabled())
        extraOptions += QLatin1String("--overwrite");
    if (dialog.isLocalOptionEnabled())
        extraOptions += QLatin1String("--local");
    if (!dialog.revision().isEmpty())
        extraOptions << QLatin1String("-r") << dialog.revision();
cerf's avatar
cerf committed
475 476 477 478 479 480 481 482 483 484 485
    m_client->synchronousPull(state.topLevel(), dialog.branchLocation(), extraOptions);
}

void BazaarPlugin::push()
{
    const VCSBase::VCSBasePluginState state = currentState();
    QTC_ASSERT(state.hasTopLevel(), return);

    PullOrPushDialog dialog(PullOrPushDialog::PushMode);
    if (dialog.exec() != QDialog::Accepted)
        return;
486 487 488 489 490 491 492 493 494 495 496
    QStringList extraOptions;
    if (dialog.isRememberOptionEnabled())
        extraOptions += QLatin1String("--remember");
    if (dialog.isOverwriteOptionEnabled())
        extraOptions += QLatin1String("--overwrite");
    if (dialog.isUseExistingDirectoryOptionEnabled())
        extraOptions += QLatin1String("--use-existing-dir");
    if (dialog.isCreatePrefixOptionEnabled())
        extraOptions += QLatin1String("--create-prefix");
    if (!dialog.revision().isEmpty())
        extraOptions << QLatin1String("-r") << dialog.revision();
cerf's avatar
cerf committed
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
    m_client->synchronousPush(state.topLevel(), dialog.branchLocation(), extraOptions);
}

void BazaarPlugin::update()
{
    const VCSBase::VCSBasePluginState state = currentState();
    QTC_ASSERT(state.hasTopLevel(), return);

    QDialog dialog;
    Ui::RevertDialog revertUi;
    revertUi.setupUi(&dialog);
    dialog.setWindowTitle(tr("Update"));
    if (dialog.exec() != QDialog::Accepted)
        return;
    m_client->update(state.topLevel(), revertUi.revisionLineEdit->text());
}

void BazaarPlugin::createSubmitEditorActions()
{
    Core::Context context(Constants::COMMIT_ID);
    Core::Command *command;

    m_editorCommit = new QAction(VCSBase::VCSBaseSubmitEditor::submitIcon(), tr("Commit"), this);
    command = m_actionManager->registerAction(m_editorCommit, Core::Id(Constants::COMMIT), context);
    command->setAttribute(Core::Command::CA_UpdateText);
    connect(m_editorCommit, SIGNAL(triggered()), this, SLOT(commitFromEditor()));

524
    m_editorDiff = new QAction(VCSBase::VCSBaseSubmitEditor::diffIcon(), tr("Diff &Selected Files"), this);
cerf's avatar
cerf committed
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
    command = m_actionManager->registerAction(m_editorDiff, Core::Id(Constants::DIFFEDITOR), context);

    m_editorUndo = new QAction(tr("&Undo"), this);
    command = m_actionManager->registerAction(m_editorUndo, Core::Id(Core::Constants::UNDO), context);

    m_editorRedo = new QAction(tr("&Redo"), this);
    command = m_actionManager->registerAction(m_editorRedo, Core::Id(Core::Constants::REDO), context);
}

void BazaarPlugin::commit()
{
    if (VCSBase::VCSBaseSubmitEditor::raiseSubmitEditor())
        return;

    const VCSBase::VCSBasePluginState state = currentState();
    QTC_ASSERT(state.hasTopLevel(), return);

    m_submitRepository = state.topLevel();

544 545
    connect(m_client, SIGNAL(parsedStatus(QList<VCSBase::VCSBaseClient::StatusItem>)),
            this, SLOT(showCommitWidget(QList<VCSBase::VCSBaseClient::StatusItem>)));
546 547
    // The "--short" option allows to easily parse status output
    m_client->emitParsedStatus(m_submitRepository, QStringList(QLatin1String("--short")));
cerf's avatar
cerf committed
548 549
}

550
void BazaarPlugin::showCommitWidget(const QList<VCSBase::VCSBaseClient::StatusItem> &status)
cerf's avatar
cerf committed
551 552 553
{
    VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
    //Once we receive our data release the connection so it can be reused elsewhere
554 555
    disconnect(m_client, SIGNAL(parsedStatus(QList<VCSBase::VCSBaseClient::StatusItem>)),
               this, SLOT(showCommitWidget(QList<VCSBase::VCSBaseClient::StatusItem>)));
cerf's avatar
cerf committed
556 557 558 559 560 561 562 563 564 565 566 567 568

    if (status.isEmpty()) {
        outputWindow->appendError(tr("There are no changes to commit."));
        return;
    }

    deleteCommitLog();

    // Open commit log
    QString m_changeLogPattern = QDir::tempPath();
    if (!m_changeLogPattern.endsWith(QLatin1Char('/')))
        m_changeLogPattern += QLatin1Char('/');
    m_changeLogPattern += QLatin1String("qtcreator-bzr-XXXXXX.msg");
cerf's avatar
cerf committed
569
    m_changeLog = new QTemporaryFile(m_changeLogPattern, this);
cerf's avatar
cerf committed
570 571 572 573 574 575
    if (!m_changeLog->open()) {
        outputWindow->appendError(tr("Unable to generate a temporary file for the commit editor."));
        return;
    }

    Core::IEditor *editor = m_core->editorManager()->openEditor(m_changeLog->fileName(),
hjk's avatar
hjk committed
576
                                                                Constants::COMMIT_ID,
cerf's avatar
cerf committed
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
                                                                Core::EditorManager::ModeSwitch);
    if (!editor) {
        outputWindow->appendError(tr("Unable to create an editor for the commit."));
        return;
    }

    CommitEditor *commitEditor = qobject_cast<CommitEditor *>(editor);

    if (!commitEditor) {
        outputWindow->appendError(tr("Unable to create a commit editor."));
        return;
    }

    const QString msg = tr("Commit changes for \"%1\".").
            arg(QDir::toNativeSeparators(m_submitRepository));
    commitEditor->setDisplayName(msg);

    const BranchInfo branch = m_client->synchronousBranchQuery(m_submitRepository);
    commitEditor->setFields(branch, m_bazaarSettings.userName(),
                            m_bazaarSettings.email(), status);

    commitEditor->registerActions(m_editorUndo, m_editorRedo, m_editorCommit, m_editorDiff);
    connect(commitEditor, SIGNAL(diffSelectedFiles(QStringList)),
            this, SLOT(diffFromEditorSelected(QStringList)));
    commitEditor->setCheckScriptWorkingDirectory(m_submitRepository);
}

void BazaarPlugin::diffFromEditorSelected(const QStringList &files)
{
    m_client->diff(m_submitRepository, files);
}

void BazaarPlugin::commitFromEditor()
{
    if (!m_changeLog)
        return;

    //use the same functionality than if the user closes the file without completing the commit
    m_core->editorManager()->closeEditors(m_core->editorManager()->editorsForFileName(m_changeLog->fileName()));
}

bool BazaarPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor)
{
    if (!m_changeLog)
        return true;
    Core::IFile *editorFile = submitEditor->file();
    const CommitEditor *commitEditor = qobject_cast<const CommitEditor *>(submitEditor);
    if (!editorFile || !commitEditor)
        return true;

    bool dummyPrompt = m_bazaarSettings.prompt();
    const VCSBase::VCSBaseSubmitEditor::PromptSubmitResult response =
            commitEditor->promptSubmit(tr("Close Commit Editor"), tr("Do you want to commit the changes?"),
                                       tr("Message check failed. Do you want to proceed?"),
                                       &dummyPrompt, m_bazaarSettings.prompt());

    switch (response) {
    case VCSBase::VCSBaseSubmitEditor::SubmitCanceled:
        return false;
    case VCSBase::VCSBaseSubmitEditor::SubmitDiscarded:
        deleteCommitLog();
        return true;
    default:
        break;
    }

643
    QStringList files = commitEditor->checkedFiles();
cerf's avatar
cerf committed
644 645
    if (!files.empty()) {
        //save the commit message
646 647
        if (!m_core->fileManager()->saveFile(editorFile))
            return false;
cerf's avatar
cerf committed
648

649 650 651 652 653 654 655 656
        //rewrite entries of the form 'file => newfile' to 'newfile' because
        //this would mess the commit command
        for (QStringList::iterator iFile = files.begin(); iFile != files.end(); ++iFile) {
            const QStringList parts = iFile->split(" => ", QString::SkipEmptyParts);
            if (!parts.isEmpty())
                *iFile = parts.last();
        }

cerf's avatar
cerf committed
657
        const BazaarCommitWidget* commitWidget = commitEditor->commitWidget();
658 659 660 661 662 663 664 665 666 667 668 669
        QStringList extraOptions;
        // Author
        if (!commitWidget->committer().isEmpty())
            extraOptions.append(QLatin1String("--author=") + commitWidget->committer());
        // Fixed bugs
        foreach (const QString &fix, commitWidget->fixedBugs()) {
            if (!fix.isEmpty())
                extraOptions << QLatin1String("--fixes") << fix;
        }
        // Whether local commit or not
        if (commitWidget->isLocalOptionEnabled())
            extraOptions += QLatin1String("--local");
cerf's avatar
cerf committed
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
        m_client->commit(m_submitRepository, files, editorFile->fileName(), extraOptions);
    }
    return true;
}

void BazaarPlugin::deleteCommitLog()
{
    if (m_changeLog) {
        delete m_changeLog;
        m_changeLog = 0;
    }
}

void BazaarPlugin::createSeparator(const Core::Context &context, const Core::Id &id)
{
    QAction *action = new QAction(this);
    action->setSeparator(true);
    m_bazaarContainer->addAction(m_actionManager->registerAction(action, id, context));
}

void BazaarPlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
{
    if (!enableMenuAction(as, m_menuAction)) {
        m_commandLocator->setEnabled(false);
        return;
    }
    const QString filename = currentState().currentFileName();
    const bool repoEnabled = currentState().hasTopLevel();
    m_commandLocator->setEnabled(repoEnabled);

    m_annotateFile->setParameter(filename);
    m_diffFile->setParameter(filename);
    m_logFile->setParameter(filename);
    m_addAction->setParameter(filename);
    m_deleteAction->setParameter(filename);
    m_revertFile->setParameter(filename);
    m_statusFile->setParameter(filename);

    foreach (QAction *repoAction, m_repositoryActionList)
        repoAction->setEnabled(repoEnabled);
}

Q_EXPORT_PLUGIN(BazaarPlugin)