/* ====================================================================
 * Copyright (c) 2003-2008  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 "MainWindow.h"
#include "Diff3Widget.h"
#include "Diff.h"
#include "Diff3.h"
#include "DiffInfoModel.h"
#include "FileSelectDialog.h"
#include "ConfigManager.h"
#include "Settings.h"
#include "settings/FontSettingsWidget.h"
#include "settings/FontSettingsInfo.h"
#include "sublib/IconFactory.h"
#include "sublib/ActionStorage.h"
#include "sublib/SettingsDialog.h"
#include "sublib/AboutDialog.h"
#include "sublib/NullTextModel.h"
#include "sublib/Line.h"
#include "sublib/Utility.h"
#include "sublib/MessageBox.h"
#include "sublib/DebugSettingsInfo.h"
#include "sublib/DebugSettingsWidget.h"
#include "sublib/settings/ColorSettingsInfo.h"
#include "sublib/settings/ColorSettingsWidget.h"
#include "svn/Error.h"
#include "util/Error.h"
#include "util/utf.h"
#include "util/FileData.h"
#include "util/iconvstream.h"

// qt
#include <QtGui/QApplication>
#include <QtGui/QMenuBar>
#include <QtGui/QToolButton>
#include <QtGui/QLabel>
#include <QtGui/QLayout>
#include <QtGui/QPushButton>
#include <QtGui/QStatusBar>
#include <QtGui/QFileDialog>
#include <QtGui/QToolBar>
#include <QtGui/QAction>
#include <QtGui/QMenu>

// sys
#include <string>
#include <fstream>


enum Actions
{
  ActionOpen,
  ActionSave,
  ActionSaveAs,
  ActionQuit,
  ActionNextDiff,
  ActionPrevDiff,
  ActionMerge,
  ActionWhitespace,
  ActionReload
};

  
MainWindow::MainWindow( ConfigManager* cfg, QWidget *parent )
: super(parent), _file(0), _config(cfg)
{
  setObjectName( "main" );
  setCaption( _q("submerge") );

  // setup actions
  _actions = new ActionStorage();

  QAction* action;

  // menus
  action = new QAction( _q("&Open file(s)"), this );
  action->setShortcut(  _q("Ctrl+O") );
  //action->setStatusTip( _q("") );
  //action->setIcon( IconFactory::createIcon("") );
  //action->setEnabled(false);
  _actions->addAction( ActionOpen, action );
  connect( action, SIGNAL(triggered()), this, SLOT(open()) );

  action = new QAction( _q("&Save merge"), this );
  action->setShortcut(  _q("Ctrl+S") );
  //action->setStatusTip( _q("") );
  //action->setIcon( IconFactory::createIcon("") );
  action->setEnabled(false);
  _actions->addAction( ActionSave, action );
  connect( action, SIGNAL(triggered()), this, SLOT(save()) );

  action = new QAction( _q("Save merge &As"), this );
  action->setShortcut(  _q("Ctrl+A") );
  //action->setStatusTip( _q("") );
  //action->setIcon( IconFactory::createIcon("") );
  action->setEnabled(false);
  _actions->addAction( ActionSaveAs, action );
  connect( action, SIGNAL(triggered()), this, SLOT(saveAs()) );

  action = new QAction( _q("E&xit"), this );
  action->setShortcut(  _q("Ctrl+Q") );
  //action->setStatusTip( _q("") );
  //action->setIcon( IconFactory::createIcon("") );
  _actions->addAction( ActionQuit, action );
  connect( action, SIGNAL(triggered()), this, SLOT(close()) );

  action = new QAction( _q("next diff"), this );
  action->setShortcut(  _q("Ctrl+N") );
  action->setStatusTip( _q("scroll to next difference") );
  action->setIcon( IconFactory::createIcon("NextDiff-Normal.png") );
  action->setEnabled(false);
  _actions->addAction( ActionNextDiff, action );
  connect( action, SIGNAL(triggered()), this, SLOT(nextDiff()) );

  action = new QAction( _q("prev diff"), this );
  action->setShortcut(  _q("Ctrl+P") );
  action->setStatusTip( _q("scroll to previous difference") );
  action->setIcon( IconFactory::createIcon("PrevDiff-Normal.png") );
  action->setEnabled(false);
  _actions->addAction( ActionPrevDiff, action );
  connect( action, SIGNAL(triggered()), this, SLOT(prevDiff()) );

  action = new QAction( _q("merge"), this );
  action->setShortcut(  _q("Ctrl+M") );
  action->setStatusTip( _q("merge differences") );
  action->setIcon( IconFactory::createIcon("MergeFile-Normal.png") );
  action->setEnabled(false);
  _actions->addAction( ActionMerge, action );
  connect( action, SIGNAL(triggered()), this, SLOT(merge()) );

  action = new QAction( _q("whitespace"), this );
  action->setShortcut(  _q("Ctrl+W") );
  action->setStatusTip( _q("show whitespace differences, requires reload after toggling it") );
  action->setIcon( IconFactory::createToggleIcon("Whitespace-NormalOff.png", "ToggleOn.png") );
  action->setToggleAction(true);
  action->setEnabled(true);
  _actions->addAction( ActionWhitespace, action );
  connect( action, SIGNAL(toggled(bool)), this, SLOT(whitespace(bool)) );

  action = new QAction( _q("reload"), this );
  action->setShortcut(  _q("Ctrl+R") );
  action->setStatusTip( _q("reload the files") );
  action->setIcon( IconFactory::createIcon("Reload-Normal.png") );
  action->setEnabled(false);
  _actions->addAction( ActionReload, action );
  connect( action, SIGNAL(triggered()), this, SLOT(refresh()) );


  QMenuBar* mb = menuBar();
  {
    QMenu* fileMenu = mb->addMenu( _q("&File") );
    fileMenu->addAction( _actions->getAction(ActionOpen) );
    fileMenu->insertSeparator();
    fileMenu->addAction( _actions->getAction(ActionSave) );
    fileMenu->addAction( _actions->getAction(ActionSaveAs) );
    fileMenu->insertSeparator();
    fileMenu->addAction( _actions->getAction(ActionQuit) );

    QMenu* toolsMenu = mb->addMenu( _q("&Tools") ); 
    toolsMenu->addAction( _q("S&ettings"),  this, SLOT(settings()), Qt::CTRL+Qt::Key_E );

    QMenu* helpMenu = mb->addMenu( _q("&Help") );
    helpMenu->addAction( _q("A&bout"), this, SLOT(about()), Qt::CTRL+Qt::Key_B );
  }

  setIconSize( QSize(20,20) );
  setUnifiedTitleAndToolBarOnMac(true);

  QToolBar* tb = new QToolBar(this);
  tb->setMovable(false);
  addToolBar(tb);
  {
    tb->addAction( _actions->getAction(ActionNextDiff) );
    tb->addAction( _actions->getAction(ActionPrevDiff) );
    tb->addAction( _actions->getAction(ActionMerge) );
    tb->addAction( _actions->getAction(ActionWhitespace) );
    tb->addAction( _actions->getAction(ActionReload) );
  }

  QWidget*     mw  = new QWidget(this);
  mw->setContentsMargins(0,0,0,0);
  QGridLayout* mwl = new QGridLayout( mw, 1, 1, 0, 2 );
  mwl->setMargin(0);
  mwl->setSpacing(1);
  {
    _dw = new Diff3Widget(_config,mw);
    mwl->addWidget(_dw,0,0);
    connect( _dw, SIGNAL(diffChanged(int)), SLOT(diffChanged(int)) );
    _dw->connectOriginalDrop( this, SLOT(oDropped(const QString&)) );
    _dw->connectModifiedDrop( this, SLOT(mDropped(const QString&)) );
    _dw->connectLatestDrop  ( this, SLOT(lDropped(const QString&)) );

    // status bars
    statusBar()->setSizeGripEnabled(true);
    statusBar()->setStyleSheet( "QStatusBar::item {border: none}" );
    {
      _sbarDiffCnt = new QLabel(this);
      _sbarWhitespace = new QLabel(this);
      _sbarEncoding = new QLabel(this);
      //_sbar4 = new QLabel(this);

      //statusBar()->addWidget( _sbar4, 4, false );
      statusBar()->addWidget( _sbarEncoding, 0, true );
      statusBar()->addWidget( _sbarWhitespace, 0, true );
      statusBar()->addWidget( _sbarDiffCnt, 0, true );
    }
  }

  super::setCentralWidget(mw);

  Settings s;
  bool success = restoreGeometry( s.layout().getByteArray(
    objectName() + ".geometry", QByteArray() ) );

  if(!success)
    setGeometry( 100,100,700,600 );
}

MainWindow::~MainWindow()
{
  delete _actions;
}

void MainWindow::showEvent( QShowEvent* e )
{ 
}

void MainWindow::closeEvent( QCloseEvent* e )
{
  Settings s;
  s.layout().setByteArray( objectName() + ".geometry", saveGeometry() );
}

Diff3Widget* MainWindow::getDiffWidget() const
{
  return _dw;
}

void MainWindow::showError( const sc::Error* error )
{
  if( error == sc::Success )
  {
    return;
  }

  QString msg = QString(
    "<qt>"
     "<center>"
      "<table width=\"500\">"
       "<tr>"
        "<td>" "%1" "</td>"
       "</tr>"
    ).arg( (const char*)error->getMessage() );

  const sc::Error* nested = error->getNested();
  while( nested != sc::Success )
  {
    QString nmsg = QString(
      "<tr>"
       "<td>" "%1" "</td>"
      "</tr>"
      ).arg( (const char*)nested->getMessage() );

    msg   += nmsg;
    nested = nested->getNested();
  }

  msg += 
      "<table>"
     "</center>"
    "</qt>";

  msgCritical( _q("submerge:error"), msg, _q("&Ok") );
}

void MainWindow::settings()
{
  SettingsDialog* sd = new SettingsDialog( _q("submerge:settings"), this );

  // font settings
  sd->addSettingsWidget( _q("Font Settings"), new FontSettingsWidget() );
  sd->addSettingsInfo( new FontSettingsInfo( _q("Fonts"), _q("Font Settings"), _config, 1 ) );

  // color settings
  sd->addSettingsWidget( _q("Color Settings"), new ColorSettingsWidget() );
  sd->addSettingsInfo( new ColorSettingsInfo( _q("Colors"), _q("Color Settings"), _config, 2 ) );

  // debug settings
  sd->addSettingsWidget( "Debug Settings", new DebugSettingsWidget(DebugSettingsWidget::L10n) );
  sd->addSettingsInfo( new DebugSettingsInfo( "Debug", "Debug Settings", _config, 3 ) );

  sd->exec();

  delete sd;
}

const sc::Error* MainWindow::diff( const DiffParamPtr param )
{
  // remember parameters
  _lastParam = param;
 
  const sc::Error* error;
  
  // prepare original file
  error = param->_original->read();
  showError(error);
  SC_ERR(error);

  error = param->_original->xlate();
  if( error != sc::Success )
  {
    error = param->_original->xlateBinary();
  }
  showError(error);
  SC_ERR(error);


  // prepare modified file
  error = param->_modified->read();
  showError(error);
  SC_ERR(error);

  error = param->_modified->xlate();
  if( error != sc::Success )
  {
    error = param->_modified->xlateBinary();
  }
  showError(error);
  SC_ERR(error);


  // run the diff..
  Diff diff( param->_original, param->_modified );
  error = diff.diff( !param->_whitespace );
  showError(error);
  SC_ERR(error);

  // ... and show it.
  _diffInfo = DiffInfoModelPtr(diff.getDiffInfo());
  _dw->setModel( _diffInfo.get() );

  _dw->setModel( 
    new NullTextModel(),
    _diffInfo->getModel(DiffInfoModel::dmOriginal),
    _diffInfo->getModel(DiffInfoModel::dmModified) );
  _dw->setMergeModel(
    _diffInfo->getModel(DiffInfoModel::dmMerged) );

  _dw->setCenterLabel( param->_originalLabel );
  _dw->setRightLabel( param->_modifiedLabel );

  // hide split handles..
  _dw->enableOriginal(false,false);
  _dw->enableMerged(false,false);

  _actions->enableAction( ActionMerge, true );
  _actions->enableAction( ActionReload, true );
  _actions->getAction( ActionWhitespace )->setOn( param->_whitespace );

  showOptions( param->_whitespace );
  showEncoding( param->_original->getEncoding() );
  setDiffCnt( _diffInfo->getDiffCnt() );

  if( param->_activeDiff > 0 && param->_activeDiff <= _diffInfo->getDiffCnt() )
    _diffInfo->setActiveDiff(param->_activeDiff);
  
  return sc::Success;
}

const sc::Error* MainWindow::diff3( const DiffParamPtr param )
{
  // remember parameters
  _lastParam = param;

  const sc::Error* error;
  
  // prepare original file
  error = param->_original->read();
  showError(error);
  SC_ERR(error);

  error = param->_original->xlate();
  if( error != sc::Success )
  {
    error = param->_original->xlateBinary();
  }
  showError(error);
  SC_ERR(error);


  // prepare modified file
  error = param->_modified->read();
  showError(error);
  SC_ERR(error);

  error = param->_modified->xlate();
  if( error != sc::Success )
  {
    error = param->_modified->xlateBinary();
  }
  showError(error);
  SC_ERR(error);


  // prepare latest file
  error = param->_latest->read();
  showError(error);
  SC_ERR(error);

  error = param->_latest->xlate();
  if( error != sc::Success )
  {
    error = param->_latest->xlateBinary();
  }
  showError(error);
  SC_ERR(error);


  // run the diff...
  Diff3 diff( param->_original, param->_modified, param->_latest, param->_merged );
  error = diff.diff3( !param->_whitespace );
  showError(error);
  SC_ERR(error);

  // ... and show it.
  _diffInfo = DiffInfoModelPtr(diff.getDiffInfo());

  _dw->setModel( _diffInfo.get() );
  _dw->setModel( 
    _diffInfo->getModel( DiffInfoModel::dmOriginal ),
    _diffInfo->getModel( DiffInfoModel::dmModified ),
    _diffInfo->getModel( DiffInfoModel::dmLatest ) );
  _dw->setMergeModel(
    _diffInfo->getModel( DiffInfoModel::dmMerged ) );

  _dw->setLeftLabel( param->_originalLabel );
  _dw->setCenterLabel( param->_modifiedLabel );
  _dw->setRightLabel( param->_latestLabel );

  // show split handles
  _dw->enableOriginal(true,false);
  _dw->enableMerged(false,false);

  _actions->enableAction( ActionMerge, true );
  _actions->enableAction( ActionReload, true );
  _actions->getAction( ActionWhitespace )->setOn( param->_whitespace );

  showOptions( param->_whitespace );
  showEncoding( param->_original->getEncoding() );
  setDiffCnt( _diffInfo->getDiffCnt() );

  if( param->_activeDiff > 0 && param->_activeDiff <= _diffInfo->getDiffCnt() )
    _diffInfo->setActiveDiff(param->_activeDiff);

  return sc::Success;
}

const sc::Error* MainWindow::save( const char* file )
{
  TextModel* merged = _diffInfo->getModel( DiffInfoModel::dmMerged );

  size_t lines   = merged->getLineCnt();
  size_t columns = merged->getColumnCnt();

  apr::Pool pool;
  size_t size  = lines*columns*2;
  char* tmpBuf = (char*)apr_palloc( pool, size );
  char* tmpDst = tmpBuf; 
  sc::Size tmpLen = 0;

  FileDataPtr ptrModFile = _lastParam->_modified;

  for( size_t i = 0; i < lines; i++ )
  {
    const Line& l = merged->getLine(i);

    if( l.isEmpty() )
    {
      continue;
    }

    memcpy( tmpDst, l.getStr(), l.getBytes() );
    tmpDst += l.getBytes();
    tmpLen += l.getBytes();
  }

  {
    apr_status_t status;
    apr_xlate_t* xlate;

    const char* dstEncoding = ptrModFile->getEncoding();

    if( *dstEncoding == '*' )
      dstEncoding = APR_LOCALE_CHARSET;

    status = apr_xlate_open( &xlate, dstEncoding, "utf-8", pool );
    APR_ERR(status);

    apr_size_t size = tmpLen * 2;
  
    while(true)
    {
      apr::Pool pool;

      const char* xSrcBuf = (const char*)tmpBuf;
      apr_size_t  xSrcLen = tmpLen;
      apr_size_t  xDstLen = size;
      char*       xDstBuf = (char*)apr_palloc( pool, xDstLen );

      status = apr_xlate_conv_buffer( xlate, xSrcBuf, &xSrcLen, xDstBuf, &xDstLen );

      // buffer to small?
      if( status == APR_SUCCESS && xSrcLen > 0 )
      {
        size *= 2;
        continue;
      }
      // everything translated?
      else if( status == APR_SUCCESS && xSrcLen == 0 )
      {
        // then write to disk..
        apr_file_t* aprFile = NULL;
        status = apr_file_open( &aprFile, file,
          APR_WRITE|APR_CREATE|APR_TRUNCATE|APR_BINARY, APR_OS_DEFAULT, pool );
        APR_ERR(status);

        apr_size_t xWriteSize = size-xDstLen;
        status = apr_file_write( aprFile, xDstBuf, &xWriteSize );
        APR_ERR(status);

        status = apr_file_close(aprFile);
        APR_ERR(status);

        // we are done
        break;
      }
      else
      {
        APR_ERR(status);
      }
    }

    status = apr_xlate_close(xlate);
    APR_ERR(status);
  }

  return sc::Success;
}

void MainWindow::open()
{
  if( ! _file )
  {
    // prepare file dialog, we always want to use the same dialog
    // so we don't loose previous file selections.
    _file = new FileSelectDialog(this);
  }
  FileSelectDialog::Result result = (FileSelectDialog::Result)_file->exec();

  switch( result )
  {
  case FileSelectDialog::rDiff2:
    {
      DiffParamPtr p( new DiffParam() );
      p->_type = DiffParam::Diff;
      
      p->_original = FileDataPtr( new FileData( sc::String(_file->getOriginal().utf8()),
        sc::String(_file->getEncoding().utf8()) ) );
      p->_modified = FileDataPtr( new FileData( sc::String(_file->getModified().utf8()),
        sc::String(_file->getEncoding().utf8()) ) );
      p->_encoding = _file->getEncoding();
      p->_whitespace = _actions->getAction( ActionWhitespace )->isOn();
      p->_activeDiff = 0;
      diff( p );
      break;
    }
  case FileSelectDialog::rDiff3:
    {
      DiffParamPtr p( new DiffParam() );
      p->_type = DiffParam::Diff3;

      p->_original = FileDataPtr( new FileData( sc::String(_file->getOriginal().utf8()),
        sc::String(_file->getEncoding().utf8()) ) );
      p->_modified = FileDataPtr( new FileData( sc::String(_file->getModified().utf8()),
        sc::String(_file->getEncoding().utf8()) ) );
      p->_latest   = FileDataPtr( new FileData( sc::String(_file->getLatest().utf8()),
        sc::String(_file->getEncoding().utf8()) ) );
      p->_encoding = _file->getEncoding();
      p->_whitespace = _actions->getAction( ActionWhitespace )->isOn();
      p->_activeDiff = 0;
      diff3( p );
      break;
    }
  }
}

void MainWindow::save()
{
  QString s( _diffInfo->getModel(DiffInfoModel::dmMerged)->getSourceName().getStr() );
  //s += ".merged";

  save( s );
}

void MainWindow::saveAs()
{
  QString s( _diffInfo->getModel(DiffInfoModel::dmMerged)->getSourceName().getStr() );

  QString sel = QFileDialog::getSaveFileName( s, "", this, "", _q("save as...") );

  if( ! sel.isNull() )
  {
    save( sel );
  }
}

void MainWindow::about()
{
  AboutDialog* ab = new AboutDialog( this );

  ab->exec();

  //this->removeChild(ab);
  delete ab;
}

void MainWindow::showOptions( bool whitespaces )
{
  if( whitespaces )
  {
    _sbarWhitespace->setText( "w+" );
  }
  else
  {
    _sbarWhitespace->setText( "w-" );
  }

  _config->setOptWhitespace(whitespaces);
  _config->save();
}

void MainWindow::setDiffCnt( int cnt )
{
  _sbarDiffCnt->setText( _q("differences: %1").arg( _diffInfo->getDiffCnt() ) );

  if( _diffInfo->getDiffCnt() )
  {
    _actions->enableAction( ActionNextDiff, true );
    _actions->enableAction( ActionPrevDiff, true );
  }
}

void MainWindow::showEncoding( const sc::String& encoding )
{
  if( encoding == sc::String("*") )
  {
    QString encdg = QString("* (%1)").arg((const char*)apr::getLocaleEncoding());
    _sbarEncoding->setText(encdg);
  }
  else
  {
    QString encdg(encoding);
    _sbarEncoding->setText(encdg);
  }
}

void MainWindow::nextDiff()
{
  int next = _diffInfo->nextDiff();
  int act  = _diffInfo->getActiveDiff();
  
  _dw->jumpToBlock( next );
  _dw->setActiveDiff( act );

  diffChanged( act );
}

void MainWindow::prevDiff()
{
  int prev = _diffInfo->prevDiff();
  int act  = _diffInfo->getActiveDiff();

  _dw->jumpToBlock( prev );
  _dw->setActiveDiff( act );

  diffChanged( act );
}

void MainWindow::nextConflict()
{
}

void MainWindow::prevConflict()
{
}

void MainWindow::merge()
{
  _dw->enableOriginal( true, false );
  _dw->enableMerged( true, true );
  _actions->enableAction( ActionMerge, false );
  _actions->enableAction( ActionSave, true );
  _actions->enableAction( ActionSaveAs, true );
}

void MainWindow::whitespace( bool b )
{
  showOptions(b);
}

void MainWindow::refresh()
{
  switch( _lastParam->_type )
  {
  case DiffParam::Diff:
    {
      _lastParam->_whitespace = _actions->getAction( ActionWhitespace )->isOn();
      _lastParam->_activeDiff = _diffInfo->getActiveDiff();
      diff( _lastParam );
      break;
    }
  case DiffParam::Diff3:
    {
      _lastParam->_whitespace = _actions->getAction( ActionWhitespace )->isOn();
      _lastParam->_activeDiff = _diffInfo->getActiveDiff();
      diff3( _lastParam );
      break;
    }
  }
  _dw->repaint();
}

void MainWindow::diffChanged(int diff)
{
  _actions->enableAction( ActionNextDiff, true );
  _actions->enableAction( ActionPrevDiff, true );
}

void MainWindow::oDropped( const QString& f )
{
  if( ! _lastParam )
  {
    _lastParam = DiffParamPtr( new DiffParam() );
    _lastParam->_modified = getEmptyFile();
    _lastParam->_latest = getEmptyFile();
    _lastParam->_modifiedLabel = _s("empty");
    _lastParam->_latestLabel = _s("empty");
  }

  _lastParam->_type = DiffParam::Diff3;
  _lastParam->_original = FileDataPtr( new FileData( sc::String(f.utf8()), sc::String("*") ) );
  _lastParam->_originalLabel = "";

  refresh();
}

void MainWindow::mDropped( const QString& f )
{
  if( ! _lastParam )
  {
    // assume diff..
    _lastParam = DiffParamPtr( new DiffParam() );
    _lastParam->_modified = getEmptyFile();
    _lastParam->_latest = getEmptyFile();
    _lastParam->_modifiedLabel = _s("empty");
    _lastParam->_latestLabel = _s("empty");
    _lastParam->_type = DiffParam::Diff;
  }

  // diff
  if( _lastParam->_type == DiffParam::Diff )
  {
    _lastParam->_original = FileDataPtr( new FileData( sc::String(f.utf8()), sc::String("*") ) );
    _lastParam->_originalLabel = "";
  }
  // diff3
  else
  {
    _lastParam->_modified = FileDataPtr( new FileData( sc::String(f.utf8()), sc::String("*") ) );
    _lastParam->_modifiedLabel = "";
  }

  refresh();
}

void MainWindow::lDropped( const QString& f )
{
  if( ! _lastParam )
  {
    _lastParam = DiffParamPtr( new DiffParam() );
    _lastParam->_original = getEmptyFile();
    _lastParam->_modified = getEmptyFile();
    _lastParam->_originalLabel = _s("empty");
    _lastParam->_modifiedLabel = _s("empty");
    _lastParam->_type = DiffParam::Diff;
  }

  // diff
  if( _lastParam->_type == DiffParam::Diff )
  {
    _lastParam->_modified = FileDataPtr( new FileData( sc::String(f.utf8()), sc::String("*") ) );
    _lastParam->_modifiedLabel = "";
  }
  // diff3
  else
  {
    _lastParam->_latest = FileDataPtr( new FileData( sc::String(f.utf8()), sc::String("*") ) );
    _lastParam->_latestLabel = "";
  }

  refresh();
}

FileDataPtr MainWindow::getEmptyFile()
{
  apr::Pool pool;
  apr_status_t status;
  apr_file_t* empty;

  const char* tempdir = NULL;
  status = apr_temp_dir_get( &tempdir, pool );

  char* tempout = apr_pstrcat( pool, tempdir, "/submerge.empty", NULL );
  status = apr_file_open( &empty, tempout,
    APR_CREATE|APR_WRITE|APR_TRUNCATE, APR_OS_DEFAULT, pool );
  status = apr_file_close( empty );

  //char errbuf[200];
  //apr_strerror( status, errbuf, 200 );

  return FileDataPtr( new FileData( sc::String(tempout), sc::String("*") ) );
}
