/* ====================================================================
 * Copyright (c) 2003-2009  Martin Hauner
 *                          http://subcommander.tigris.org
 *
 * Subcommander is licensed as described in the file doc/COPYING, which
 * you should have received as part of this distribution.
 * ====================================================================
 */

// sc
#include "config.h"
#include "ListWidget.h"
#include "ScModel.h"
#include "Controller.h"
#include "WcView.h"
#include "WcViewModel.h"
#include "RpView.h"
#include "RpViewModel.h"
#include "LogViewModel.h"
#include "BlameViewModel.h"
#include "LogGraphViewModel.h"
#include "BookmarkProperties.h"
#include "Bookmark.h"
#include "BookmarkView.h"
#include "BookmarkViewModel.h"
#include "WcViewLogWidget.h"
#include "WcViewCmdProgress.h"
#include "Project.h"
#include "ProjectWizard.h"
#include "Actions.h"
#include "TextWindow.h"
#include "UpdateDialog.h"
#include "ExportDialog.h"
#include "MkdirDialog.h"
#include "CopyDialog.h"
#include "LockDialog.h"
#include "UnlockDialog.h"
#include "RemoveDialog.h"
#include "CommitDialog.h"
#include "DiffDialog.h"
#include "MergeDialog.h"
#include "CheckoutDialog.h"
#include "SwitchDialog.h"
#include "DiffViewModel.h"
#include "MergeViewModel.h"
#include "LogDialog2.h"
#include "LogGraphDialog.h"
#include "BlameDialog.h"
#include "PropertiesDialog2.h"
#include "CreateRepositoryDialog.h"
#include "ExternProviderImpl.h"
#include "ErrorSupport.h"
#include "Settings.h"
#include "settings/FontSettings.h"
#include "commands/ExportParam.h"
#include "commands/UpdateParam.h"
#include "commands/CopyParam.h"
#include "commands/LockParam.h"
#include "commands/UnlockParam.h"
#include "commands/CommitParam.h"
#include "commands/CheckoutParam.h"
#include "commands/SwitchParam.h"
#include "events/CustomEvents.h"
#include "sublib/ActionStorage.h"
#include "sublib/MessageBox.h"
#include "sublib/Splitter.h"
#include "sublib/Utility.h"
#include "sublib/settings/LayoutSettings.h"
#include "svn/Path.h"
#include "svn/Admin.h"

// qt
#include <QtGui/QLayout>
#include <QtGui/QTextEdit>
#include <QtGui/QMessageBox>
#include <QtGui/QApplication>
#include <QtGui/QAction>
#include <Qt3Support/Q3WidgetStack>

// sys
#include <assert.h>



////////////////////////////////////////////////////////////////////////

static QString StartupText(
"<qt>"
"<b>** NOTICE **</b>"
"<br><br>"
"This is a BETA version of the next major Subcommander release. It is a"
" snapshot of ongoing development. It is usable but still unpolished at"
" various places.<br>"
"If there is an issue you like to get addressed please let me know and "
"send your comments to dev@subcommander.tigris.org. Escpecially ideas "
"to improve the usability are welcome.<br>"
"Thanks for using Subcommander, Martin :-)"
"<br><br>"
"<b>** CHANGES 2.0.0 b5 **</b>"
"<br><br>"
"* new: move & copy multiple items at once. Droping on a file will move"
" or copy the dragged items to the parent folder of that file.<br>"
//"* new: open new working copy tab from any sub folder.<br>"
"* new: animated bookmark icon to show running commands.<br>"
"* new: text status filter.<br>"
"* improved working copy display speed.<br>"
"* various bug fixes and code improvements.<br>" 
"<br><br>"
"<b>** CHANGES 2.0.0 **</b>"
"<br><br>"
"Here is a short overview of the new features:<br>"
"* new: simultaneous flat and tree view for working copies (tabs)<br>"
"* new: automatic refresh after wc operations like add, revert, "
"rename etc.<br>"
"* new: reload will (recursively) refresh only the selected folder and"
" not the whole working copy.<br>"
"* new: deep status info in tree view (a folders has a '*' in the ds "
"(deep status) column if anything below it is changed)<br>"
"* new: back/forward navigation<br>"
"* new: switch display options without reload<br>"
"* new: toolbar buttons for common operations<br>"
"* new: project setup wizard<br>"
"* new: ported to qt 4.3+<br>"
"<br><br>"
"<br>"
"<b>repository & working copy navigation</b>"
"<p>"
"* the project bookmark view shows the repository and working copy "
" bookmarks of your project. All bookmark details are displayed in a"
" repository or a working copy (flat or tree) view.<br>"
"* double clicking a folder in the repository or working copy view "
"makes the current folder the new root item. <br>"
"</p>"
"<b>help</b>"
"<p>"
"* pressing SHIFT-F1 in the working copy view will display a detailed"
"description of the the columns and their possible values."
"</p>"
"<b>internationalization (i18n)</b>"
"<p>"
"* Subcommander is internationalized (using the GNU gettext package)."
" If you like to run subcommander in your native language you can "
"help creating a translation."
"</p>"
"<b>tips/notes</b>"
"<p>"
"* you can simply drop an url from a web browser or a path from a file"
" browser on a project to add it to the project.<br>"
"* you don't have to follow the typical trunk/branches/tags layout in "
"your repository to use subcommanders branch and tag feature. You can "
"set any repository folder as branch or tag folder. subcommander needs"
" only to know WHERE you keep your branches and tags. It does NOT "
"require that they are named 'branches' or 'tags'."
"</p>"
"</qt>"
);


ListWidget::ListWidget( Controller* controller, ActionStorage* as,
  QWidget *parentw )
: super(parentw,NULL), _model(controller->getScModel()),
  _controller(controller), _actions(as)
{
  setName( "mainview" );
  QGridLayout* mwl = new QGridLayout( this, 1, 1, 0, 0 );
  {
    _splith = new Splitter( this, Qt::Horizontal, Splitter::First );

    mwl->addWidget(_splith,0,0);
    mwl->setRowStretch(0,1);
    {
      _bookmarkView = new BookmarkView(
        _controller->getBookmarkViewModel(),as,_splith);

      connect(
        _bookmarkView, SIGNAL(onItem(const QString&)),
        parent(),      SLOT(onBookmarkItem(const QString&)) );

      _splitv = new Splitter( _splith, Qt::Vertical, Splitter::Last );
      {
        _stackFiles = new Q3WidgetStack(_splitv);
        {
          QTextEdit* text = new QTextEdit(_stackFiles);
          text->setText( StartupText );

          _stackFiles->addWidget( text, 0 );
          _stackFiles->raiseWidget(0);
        }

        _log = new WcViewLogWidget(_splitv);
      }
    }
  }
  _model->setProgressCallback( new WcViewCmdProgress(_log) );


  connect( _controller, SIGNAL(newView(ID,WcViewModel*)), this, SLOT(newView(ID,WcViewModel*)) );
  connect( _controller, SIGNAL(newView(ID,RpViewModel*)), this, SLOT(newView(ID,RpViewModel*)) );
  connect( _controller, SIGNAL(delView(ID)), this, SLOT(delView(ID)) );
  connect( _controller, SIGNAL(showView(ID)), this, SLOT(showView(ID)) );
  
  connect(
    _controller, SIGNAL(showCommit(bool,WcViewModel*)),
    this, SLOT(showCommit(bool,WcViewModel*)) );
  connect(
    _controller, SIGNAL(showProps(WcViewModel*)),
    this, SLOT(showProps(WcViewModel*)) );
  connect(
    _controller, SIGNAL(showLog(LogViewModel*)),
    this, SLOT(showLog(LogViewModel*)) );
  connect(
    _controller, SIGNAL(showLogGraph(LogGraphViewModel*)),
    this, SLOT(showLogGraph(LogGraphViewModel*)) );
  connect(
    _controller, SIGNAL(showBlame(BlameViewModel*)),
    this, SLOT(showBlame(BlameViewModel*)) );
  connect(
    _controller, SIGNAL(confirmAutoUpdate(bool&)),
    this, SLOT(confirmAutoUpdate(bool&)) );
  connect(
    _controller, SIGNAL(confirmCreateRepository(bool&)),
    this, SLOT(confirmCreateRepository(bool&)) );

  _controller->initBookmarks();


  BookmarkViewModel* bmModel = _controller->getBookmarkViewModel();

  // possibly move handling to BookmarkView!?!?
  connect(
    bmModel, SIGNAL(showNewProjectBookmark(Project*,bool&)),
    this, SLOT(showNewProjectBookmark(Project*,bool&)) );
  connect(
    bmModel, SIGNAL(showEditBookmark(Bookmark*,bool&)),
    this, SLOT(showEditBookmark(Bookmark*,bool&)) );
  connect(
    bmModel, SIGNAL(showRemoveBookmark(Bookmark*,bool&)),
    this, SLOT(showRemoveBookmark(Bookmark*,bool&)) );

  Settings s;
  _splith->restoreState( s.layout().getByteArray(
    objectName() + ".hsplitter.state", QByteArray() ) );
  _splitv->restoreState( s.layout().getByteArray(
    objectName() + ".vsplitter.state", QByteArray() ) );
}

ListWidget::~ListWidget()
{
  Settings s;
  s.layout().setByteArray( objectName() + ".hsplitter.state",
    _splith->saveState() );
  s.layout().setByteArray( objectName() + ".vsplitter.state",
    _splitv->saveState() );

  delete _bookmarkView;
}

void ListWidget::installChildEventFilter( const QObject* filter )
{
  //_subvn->installEventFilter(filter);
}

void ListWidget::showProject()
{
  _stackFiles->setEnabled(false);
}

void ListWidget::showEmptyFiles()
{
  _stackFiles->raiseWidget(0);
}

void ListWidget::customEvent( QEvent* ce )
{
#if 0
  switch( ce->type() )
  {
  default:
    {
      printf( "ListWidget: unknown custom event type %d!\n", ce->type() );
    }
  }
#endif
}

ScModel* ListWidget::getModel() const
{
  return _model;
}

void ListWidget::newView( ID id, WcViewModel* model )
{
  WcView* view = new WcView( id, model, _actions, _stackFiles );
  int wId = _stackFiles->addWidget( view );

  _ids.insert( Ids::value_type(id,wId) );

  connect( 
    model, SIGNAL(showPatch(const QString&,const QString&)),
    this,  SLOT(  showPatch(const QString&,const QString&)) );
  connect(
    model, SIGNAL(confirmRevert(bool&)),
    this, SLOT(confirmRevert(bool&)) );
  connect(
    model, SIGNAL(confirmRemove(bool,bool&,bool&)),
    this, SLOT(confirmRemove(bool,bool&,bool&)) );
  connect(
    model, SIGNAL(confirmUpdate(UpdateParam*,bool&)),
    this,  SLOT(confirmUpdate(UpdateParam*,bool&)) );
  connect(
    model, SIGNAL(confirmExport(ExportParam*,bool&)),
    this,  SLOT(confirmExport(ExportParam*,bool&)) );
  connect(
    model, SIGNAL(confirmMkdir(sc::String&,bool&)),
    this,  SLOT(confirmMkdir(sc::String&,bool&)) );
  connect(
    model, SIGNAL(confirmCopy(CopyParam*,Project*,bool&)),
    this,  SLOT(confirmCopy(CopyParam*,Project*,bool&)) );
  connect(
    model, SIGNAL(confirmLock(LockParam*,bool&)),
    this,  SLOT(confirmLock(LockParam*,bool&)) );
  connect(
    model, SIGNAL(confirmUnlock(UnlockParam*,bool&)),
    this,  SLOT(confirmUnlock(UnlockParam*,bool&)) );
  connect(
    model, SIGNAL(confirmResolved(bool&)),
    this,  SLOT(confirmResolved(bool&)) );
}

void ListWidget::newView( ID id, RpViewModel* model )
{
  RpView* view = new RpView( id, model, _actions, _stackFiles );
  int wId = _stackFiles->addWidget( view );

  _ids.insert( Ids::value_type(id,wId) );

  connect(
    model, SIGNAL(confirmCopy(CopyParam*,Project*,bool&)),
    this,  SLOT(confirmCopy(CopyParam*,Project*,bool&)) );
  connect(
    model, SIGNAL(confirmCheckout(CheckoutParam*,Project*,bool&)),
    this,  SLOT(confirmCheckout(CheckoutParam*,Project*,bool&)) );
  connect(
    model, SIGNAL(confirmSwitch(SwitchParam*,Project*,bool&)),
    this,  SLOT(confirmSwitch(SwitchParam*,Project*,bool&)) );
  connect(
    model, SIGNAL(showDiff(DiffViewModel*)),
    this,  SLOT(showDiff(DiffViewModel*)) );
  connect(
    model, SIGNAL(showMerge(MergeViewModel*)),
    this,  SLOT(showMerge(MergeViewModel*)) );
  connect(
    model, SIGNAL(confirmMkdir(sc::String&,bool&)),
    this,  SLOT(confirmMkdir(sc::String&,bool&)) );
  connect(
    model, SIGNAL(confirmRemove(bool&)),
    this,  SLOT(confirmRemove(bool&)) );
#if 0
  connect(
    model, SIGNAL(confirmExport(ExportParam*,bool&)),
    this,  SLOT(confirmExport(ExportParam*,bool&)) );
#endif
}

void ListWidget::delView( ID id )
{
  Ids::iterator it = _ids.find(id);

  if( it == _ids.end() )
    return;

  QWidget* w = _stackFiles->widget((*it).second);

  _stackFiles->raiseWidget(0);
  _stackFiles->removeWidget(w);
  delete w;
  
  _ids.erase(it);
}

void ListWidget::showView( ID id )
{
  Ids::iterator it = _ids.find(id);
  if( it != _ids.end() )
  {
    _stackFiles->raiseWidget((*it).second);
  }
}

void ListWidget::showPatch(  const QString& source, const QString& patch )
{
  if( patch.isEmpty() )
  {
    return;
  }

  QString title = _q("diff %1").arg(source);

  TextWindow* tw = new TextWindow( title, _model->getFontSettings() );
  tw->loadText(patch);
  tw->show();
}

void ListWidget::showCat( const QString& source, const QString& content )
{
  QFont font = _model->getFontSettings()->getEditorFont();

  QTextEdit* e = new QTextEdit();
  e->setCaption( QString(_q("subcommander:cat (%1)")).arg(source) );
  e->setWordWrapMode( QTextOption::NoWrap );
  e->resize( QSize( 700, 600 ) );
  e->setText( content );
  e->setFont( font );
  e->show();

  // \todo leaked...
}

void ListWidget::showCommit( bool bookmark, WcViewModel* model )
{
  if( model->getBookmark()->isTags() )
  {
    int answer = msgWarning( _q("subcommander:commit"),
      _q("You are going to commit to an URL which is set as a tag.\nProceed anyway?"),
      _q("&Proceed"), _q("&Cancel")
    );

    bool proceed = (answer == QMessageBox::Ok);
    if( !proceed )
      return;
  }

  CommitDialog* dlg = new CommitDialog( true, bookmark, model, _model->getCommitLogHistory(),
    _model->getFontSettings()->getEditorFont(), this );
  dlg->exec();
  delete dlg;
}

void ListWidget::showProps( WcViewModel* model )
{
  svn::WcStatusPtr status = model->getSelection().getSingle();
  PropertiesDialog2* dlg = new PropertiesDialog2( status->getName(), status->isDir(), model );
  dlg->exec();
  delete dlg;
}

void ListWidget::showLog( LogViewModel* model )
{
  connect( 
    model, SIGNAL(showPatch(const QString&,const QString&)),
    this,  SLOT(  showPatch(const QString&,const QString&)) );

  connect( 
    model, SIGNAL(showCat(const QString&,const QString&)),
    this,  SLOT(  showCat(const QString&,const QString&)) );

  LogDialog2* dlg = new LogDialog2( model, _model->getFontSettings()->getEditorFont() );

  connect( 
    dlg, SIGNAL(showDiff(DiffViewModel*)),
    this,  SLOT(showDiff(DiffViewModel*)) );
  connect( 
    dlg, SIGNAL(showMerge(MergeViewModel*)),
    this,  SLOT(showMerge(MergeViewModel*)) );

  dlg->show();
}

void ListWidget::showLogGraph( LogGraphViewModel* model )
{
  LogGraphDialog* dlg = new LogGraphDialog(model);

  connect( 
    dlg, SIGNAL(showDiff(DiffViewModel*)),
    this,  SLOT(showDiff(DiffViewModel*)) );

  dlg->show();
  dlg->run();
}

void ListWidget::showBlame( BlameViewModel* model )
{
  BlameDialog* dlg = new BlameDialog( model, _model->getFontSettings()->getEditorFont() );
  dlg->show();
}

void ListWidget::showDiff( DiffViewModel* model )
{
  connect( 
    model, SIGNAL(showPatch(const QString&,const QString&)),
    this,  SLOT(  showPatch(const QString&,const QString&)) );

  DiffDialog* dlg = new DiffDialog( model, new ExternProviderImpl(_model) );
  dlg->show();
}

void ListWidget::showMerge( MergeViewModel* model )
{
  MergeDialog* dlg = new MergeDialog( model, new ExternProviderImpl(_model) );
  dlg->show();
}

void ListWidget::confirmRevert( bool& proceed )
{
  // \todo add recurse checkmark

  int answer = msgInformation( _q("subcommander:revert"),
    _q("Reverting modified files or folders will permanently remove your changes.\nRevert anyway?"),
    _q("&Ok"), _q("&Cancel")
  );

  proceed = (answer == QMessageBox::Ok);
}

void ListWidget::confirmRemove( bool unversioned, bool& force, bool& proceed )
{
  RemoveDialog* dlg = new RemoveDialog( this, force, unversioned );

  int answer = dlg->exec();

  force   = dlg->getForce();
  proceed = (answer == QDialog::Accepted);
}

void ListWidget::confirmRemove( bool& proceed )
{
  int answer = msgInformation( _q("subcommander:remove"),
    _q("Remove the selected items?"),
    _q("&Ok"), _q("&Cancel")
  );

  proceed = (answer == QMessageBox::Ok);
}

void ListWidget::confirmUpdate( UpdateParam* param, bool& proceed )
{
  ExternProviderImpl externProvider(_model);

  boost::shared_ptr<UpdateDialog> dlg(
    new UpdateDialog( &externProvider, param->getRecurse(), this ) );

  QString qpath = QString::fromUtf8(param->getPath());
  dlg->setWorkingCopyPath(qpath);

  int answer = dlg->exec();
  proceed = (answer == QDialog::Accepted);

  if( ! proceed )
    return;

  param->setPath( sc::String(dlg->getWorkingCopyPath().utf8()) );
  param->setRevision( svn::RevisionPtr(dlg->getRevision()) );
  param->setRecurse( dlg->isRecursive() );
}

void ListWidget::confirmExport( ExportParam* param, bool& proceed )
{
  ExternProviderImpl externProvider(_model);

  ExportDialog* dlg = new ExportDialog( &externProvider,
    param->getForce(), this );

  QString qpath = QString::fromUtf8(param->getSrcPathOrUrl());
  dlg->initSrcPath(qpath);

  int answer = dlg->exec();
  proceed = (answer == QDialog::Accepted);

  if( ! proceed )
    return;

  param->setSrcPathOrUrl( sc::String(dlg->getSrcPathOrUrl().utf8()) );
  param->setPath( sc::String(dlg->getDstPath().utf8()) );
  param->setRevision( svn::RevisionPtr(dlg->getRevision()) );
  param->setForce( dlg->getForce() );
  param->setEol( sc::String(dlg->getEol().utf8()) );
}

void ListWidget::confirmMkdir( sc::String& dir, bool& proceed )
{
  MkdirDialog* dlg = new MkdirDialog(this);

  int answer = dlg->exec();
  proceed = (answer == QDialog::Accepted);

  if( ! proceed )
    return;

  dir = sc::String(dlg->getFolder().utf8());
}

void ListWidget::confirmCopy( CopyParam* param, Project* prj, bool& proceed )
{
  ExternProviderImpl externProvider(_model);

  boost::shared_ptr<CopyDialog> dlg( new CopyDialog( &externProvider, this ) );
  
  dlg->setSrcPathOrUrl( QString::fromUtf8(param->getSrcPathsOrUrls().front()) );
  dlg->setBranchesUrl( QString::fromUtf8(prj->getBranchesUrl()) );
  dlg->setTagsUrl( QString::fromUtf8(prj->getTagsUrl()) );
  dlg->enableSrc(true);
  dlg->enableDst(false);

  int answer = dlg->exec();
  proceed = (answer == QDialog::Accepted);

  if( ! proceed )
    return;

  svn::Paths paths;
  paths.push_back(sc::String(dlg->getSrcPathOrUrl().utf8()));
  param->setSrcPathsOrUrls(paths);
  param->setDstPathOrUrl(sc::String(dlg->getTargetPathOrUrl().utf8()));
  param->setSrcRevision(svn::RevisionPtr(dlg->getRevision()));
}

void ListWidget::confirmLock( LockParam* param, bool& proceed )
{
  LockDialog* dlg = new LockDialog( _model, this );

  int answer = dlg->exec();
  proceed = (answer == QDialog::Accepted);

  if( ! proceed )
    return;

  param->setComment( sc::String(dlg->getLogMessage().utf8()) );
  param->setStealLocks( dlg->isStealLock() );
}

void ListWidget::confirmUnlock( UnlockParam* param, bool& proceed )
{
  UnlockDialog* dlg = new UnlockDialog( _model, this );

  int answer = dlg->exec();
  proceed = (answer == QDialog::Accepted);

  if( ! proceed )
    return;

  param->setBreakLocks( dlg->isBreakLock() );
}

void ListWidget::confirmResolved( bool& proceed )
{
  int answer = msgInformation( _q("subcommander:resolved"),
    _q("Do you have resolved all conflicts?"),
    _q("&Ok"), _q("&Cancel") );

  proceed = (answer == QMessageBox::Ok);
}

void ListWidget::confirmCheckout( CheckoutParam* param, Project* prj, bool& proceed )
{
  ExternProviderImpl externProvider(_model);

  CheckoutDialog* dlg = new CheckoutDialog( &externProvider,
    param->getRecurse(), true, this );

  QString qurl = QString::fromUtf8(param->getUrl());
  dlg->setRepositoryUrl(qurl); 
  QString qpath = QString::fromUtf8(param->getPath());
  dlg->setWorkingCopyPath(qpath);

  int answer = dlg->exec();
  proceed  = (answer == QDialog::Accepted);

  if( ! proceed )
    return;

  param->setUrl( sc::String(dlg->getRepositoryUrl().utf8()) );
  param->setPath( sc::String(dlg->getWorkingCopyPath().utf8()) );
  param->setRevision( svn::RevisionPtr(dlg->getRevision()) );
  param->setPegRevision( svn::RevisionPtr(dlg->getPegRevision()) ); 
  param->setRecurse( dlg->isRecursive() );

  if( dlg->isAddToProject() )
  {
    Project::Item item = prj->createWorkingCopyItem();
    item.setName( svn::Path::getBaseName(param->getPath()) );
    item.setSource( param->getPath() );
    prj->setItem(item);

    _controller->getBookmarkViewModel()->updateBookmarks(prj);
  }
}

void ListWidget::confirmSwitch( SwitchParam* param, Project* prj, bool& proceed )
{
  ExternProviderImpl externProvider(_model);

  SwitchDialog* dlg = new SwitchDialog( &externProvider,
    param->getRecurse(), this );

  QString qurl = QString::fromUtf8(param->getUrl());
  dlg->setRepositoryUrl(qurl); 
  QString qpath = QString::fromUtf8(param->getPath());
  dlg->addWorkingCopyPath(qpath);

  Project::Items items;
  prj->getItems(items);

  for( Project::Items::iterator it = items.begin(); it != items.end(); it++ )
  {
    QString path = QString::fromUtf8((*it).getSource());
    if( path != qpath )
    {
      dlg->addWorkingCopyPath(path);
    }
  }

  int answer = dlg->exec();
  proceed  = (answer == QDialog::Accepted);

  if( ! proceed )
    return;

  param->setUrl( sc::String(dlg->getRepositoryUrl().utf8()) );
  param->setPath( sc::String(dlg->getWorkingCopyPath().utf8()) );
  param->setRevision( svn::RevisionPtr(dlg->getRevision()) );
  param->setRecurse( dlg->isRecursive() );
}

void ListWidget::confirmAutoUpdate( bool& proceed )
{
  int answer = msgInformation( _q("subcommander:auto update"),
    _q("run automatic working copy update?"), _q("&Ok"), _q("&Cancel") );

  proceed = (answer == QMessageBox::Ok);
}

void ListWidget::confirmCreateRepository( bool& proceed )
{
  ExternProviderImpl externProvider(_model);

  CreateRepositoryDialog* dlg = new CreateRepositoryDialog( &externProvider, this );

  int answer = dlg->exec();
  proceed  = (answer == QDialog::Accepted);

  if( ! proceed )
    return;

  // todo move to model class.
  svn::Admin admin;
  QString path = dlg->getPath() + "/" + dlg->getName();
  sc::Error* e = admin.createRepository(sc::String(path.utf8()) );

  if( !e )
    msgInformation( _q("create local repository"),
    _q("successfully created local repository:\n") + path, "ok" );
  else
    handleError(e,this);
}

void ListWidget::showEditBookmark( Bookmark* bm, bool& changed )
{
  ExternProviderImpl ep(_model);

  boost::shared_ptr<BookmarkProperties> dlg
  ( new BookmarkProperties(bm, &ep, this) );

  int answer = dlg->exec();
  changed = (answer == QDialog::Accepted);

  if( ! changed )
    return;

  bm->setName( sc::String(dlg->getName().utf8()) );
  bm->setSource( sc::String(dlg->getSource().utf8()) );
  bm->setAutoUpdate(dlg->getAutoUpdate());
}

void ListWidget::showNewProjectBookmark( Project* prj, bool& changed )
{
  ProjectWizard* dlg = new ProjectWizard(this);

  int result = dlg->exec();
  if( result != QDialog::Accepted )
    return;

  changed = true;
  prj->setName( sc::String(dlg->getProjectName().utf8()) );
  prj->setRepositoryName( sc::String(dlg->getTrunkName().utf8()) );
  prj->setRepositoryUrl( sc::String(dlg->getTrunkUrl().utf8()) );
  prj->setBranchesName( sc::String(dlg->getBranchesName().utf8()) );
  prj->setBranchesUrl( sc::String(dlg->getBranchesUrl().utf8()) );
  prj->setTagsName( sc::String(dlg->getTagsName().utf8()) );
  prj->setTagsUrl( sc::String(dlg->getTagsUrl().utf8()) );


  sc::String wcName(dlg->getWcName().utf8());
  sc::String wcSource(dlg->getWcPath().utf8());

  if( wcName.isEmpty() || wcSource.isEmpty() )
    return;

  Project::Item wc = prj->createWorkingCopyItem();
  wc.setName( wcName );
  wc.setSource( wcSource );
  prj->setItem(wc);
}

void ListWidget::showRemoveBookmark( Bookmark* bm, bool& changed )
{
  QString msg;
  msg  = _q("Remove the bookmark '%1' ?").arg( QString::fromUtf8(bm->getName()) );

  int answer = msgInformation( _q("subcommander:remove bookmark"), msg,
    _q("&Ok"), _q("&Cancel") );
  
  if( answer != QMessageBox::Ok )
    return;

  changed = true;
}
