/* ====================================================================
 * Copyright (c) 2003-2006, 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/FontSettingsWidget.h"
#include "settings/FontSettingsInfo.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 <qapplication.h>
#include <qmenubar.h>
#include <qtoolbar.h>
#include <qtoolbutton.h>
#include <qlabel.h>
#include <qvbox.h>
#include <qlayout.h>
#include <qpushbutton.h>
#include <qstatusbar.h>
#include <qfiledialog.h>
#include <qpopupmenu.h>
#include <qaction.h>

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



enum MenuIds
{
  pmFile,
  pmiFileSave,
  pmiFileSaveAs,
  pmTools
};


MainWindow::MainWindow( ConfigManager* cfg, QWidget *parent, const char *name )
: super(parent, name, Qt::WStyle_Customize | Qt::WType_TopLevel |
  Qt::WStyle_NormalBorder | Qt::WStyle_Title | Qt::WStyle_SysMenu |
  Qt::WStyle_MinMax | Qt::WResizeNoErase ), _file(0), _config(cfg)
{
  setCaption( _q("subcommander [submerge]") );

  QMenuBar* mb = new QMenuBar( this );
  {
    QPopupMenu* m  = new QPopupMenu( mb );
    mb->insertItem( _q("&File"), m, pmFile );
    _fileMenu = m;
    {
      m->insertItem( _q("&Open file(s)"), this, SLOT(open()), Qt::CTRL+Qt::Key_O );
      m->insertSeparator();
      m->insertItem( _q("&Save merge"), this, SLOT(save()), Qt::CTRL+Qt::Key_S, pmiFileSave );
      m->insertItem( _q("Save merge &As"), this, SLOT(saveAs()), Qt::CTRL+Qt::Key_A, pmiFileSaveAs );
      m->setItemEnabled( pmiFileSave, false );
      m->setItemEnabled( pmiFileSaveAs, false );
      m->insertSeparator();
      m->insertItem( _q("E&xit"),  qApp, SLOT(quit()), Qt::CTRL+Qt::Key_Q );
    }

    QPopupMenu* m1b  = new QPopupMenu( mb );
    mb->insertItem( _q("&Tools"), m1b, pmTools );
    {
      m1b->insertItem( _q("S&ettings"),  this, SLOT(settings()), Qt::CTRL+Qt::Key_E );
    }

    QPopupMenu* m2 = new QPopupMenu( mb );
    mb->insertItem( _q("&Help"), m2 );
    {
      m2->insertItem( _q("A&bout"), this, SLOT(about()), Qt::CTRL+Qt::Key_B );
    }
  }

  QIconSet::setIconSize( QIconSet::Small, QSize(20,20) );
  QIconSet::setIconSize( QIconSet::Large, QSize(32,32) );

  setToolBarsMovable(false);
  setDockMenuEnabled(true);

  QToolBar* tb = new QToolBar( _q("submerge diff tool bar"), this );
  addToolBar(tb);
  {
#ifdef _MACOSX
    
    QFont f = font();
    f.setPixelSizeFloat(10.0);
    tb->setFont(f);
    
    // todo write to ini
    setUsesBigPixmaps(true);
    setUsesTextLabel(true);
    
#else
    
    // todo write to ini
    setUsesBigPixmaps(false);
    setUsesTextLabel(false);
    
#endif // _MACOSX
        
    QIconSet isetNextDiff;
    isetNextDiff.setPixmap( getIconDir() + "NextDiff-Normal.png", QIconSet::Automatic, QIconSet::Normal );
    isetNextDiff.setPixmap( getIconDir() + "NextDiff-Active.png", QIconSet::Automatic, QIconSet::Active );
    isetNextDiff.setPixmap( getIconDir() + "NextDiff-Disabled.png", QIconSet::Automatic, QIconSet::Disabled );
    _next = new QAction( _q("next diff"), _q("Ctrl+N"), this );
    _next->setStatusTip( _q("scroll to next difference") );
    _next->setIconSet( isetNextDiff );
    _next->setEnabled(false);
    _next->addTo(tb);
    connect( _next, SIGNAL(activated()), SLOT(nextDiff()) );

    QIconSet isetPrevDiff;
    isetPrevDiff.setPixmap( getIconDir() + "PrevDiff-Normal.png", QIconSet::Automatic, QIconSet::Normal );
    isetPrevDiff.setPixmap( getIconDir() + "PrevDiff-Active.png", QIconSet::Automatic, QIconSet::Active );
    isetPrevDiff.setPixmap( getIconDir() + "PrevDiff-Disabled.png", QIconSet::Automatic, QIconSet::Disabled );
    _prev = new QAction( _q("prev diff"), _q("Ctrl+P"), this );
    _prev->setStatusTip( _q("scroll to previous difference") );
    _prev->setIconSet( isetPrevDiff );
    _prev->setEnabled(false);
    _prev->addTo(tb);
    connect( _prev, SIGNAL(activated()), SLOT(prevDiff()) );

    QIconSet isetMerge;
    isetMerge.setPixmap( getIconDir() + "Merge-Normal.png", QIconSet::Automatic, QIconSet::Normal );
    isetMerge.setPixmap( getIconDir() + "Merge-Active.png", QIconSet::Automatic, QIconSet::Active );
    isetMerge.setPixmap( getIconDir() + "Merge-Disabled.png", QIconSet::Automatic, QIconSet::Disabled );
    _merge = new QAction( _q("merge"), _q("Ctrl+M"), this );
    _merge->setStatusTip( _q("merge differences") );
    _merge->setIconSet( isetMerge );
    _merge->setEnabled(false);
    _merge->addTo(tb);
    connect( _merge, SIGNAL(activated()), SLOT(merge()) );

    QIconSet isetWhitespace;
    isetWhitespace.setPixmap( getIconDir() + "Whitespace-NormalOn.png", QIconSet::Automatic, QIconSet::Normal, QIconSet::On );
    isetWhitespace.setPixmap( getIconDir() + "Whitespace-NormalOff.png", QIconSet::Automatic, QIconSet::Normal, QIconSet::Off );
    _wspace = new QAction( _q("whitespace"), _q("Ctrl+W"), this );
    _wspace->setStatusTip( _q("show whitespace differences, requires reload after toggling it") );
    _wspace->setIconSet( isetWhitespace );
    _wspace->setToggleAction(true);
    _wspace->setEnabled(true);
    _wspace->addTo(tb);
    connect( _wspace, SIGNAL(toggled(bool)), SLOT(whitespace(bool)) );

    QIconSet isetReload;
    isetReload.setPixmap( getIconDir() + "Reload-Normal.png", QIconSet::Automatic, QIconSet::Normal );
    isetReload.setPixmap( getIconDir() + "Reload-Active.png", QIconSet::Automatic, QIconSet::Active );
    isetReload.setPixmap( getIconDir() + "Reload-Disabled.png", QIconSet::Automatic, QIconSet::Disabled );
    _reload = new QAction( _q("reload"), _q("Ctrl+R"), this );
    _reload->setStatusTip( _q("reload the files") );
    _reload->setIconSet( isetReload );
    _reload->setEnabled(false);
    _reload->addTo(tb);
    connect( _reload, SIGNAL(activated()), SLOT(refresh()) );    
  }

  QWidget*     mw  = new QWidget(this);
  QGridLayout* mwl = new QGridLayout( mw, 1, 1, 0, 2 );
  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);
    {
      _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 );
    }
  }

  // set default size
  setMinimumWidth(500);
  setMinimumHeight(500);

  super::setCentralWidget(mw);
}

MainWindow::~MainWindow()
{
}

bool MainWindow::showDockMenu( const QPoint& globalPos )
{
  // strange, we can't add anything to the default dock menu

  //QPopupMenu* dockMenu = createDockWindowMenu();

  QPopupMenu* menu = new QPopupMenu(this,_q("submerge"));
  menu->setCheckable(true);
  //menu->insertItem( "tool bars", dockMenu );

  menu->insertItem( _q("show label"),  10 );
  menu->setItemChecked(10,usesTextLabel());

  menu->insertItem( _q("large icons"), 20 );
  menu->setItemChecked(20,usesBigPixmaps());

  int result = menu->exec(globalPos);

  switch( result )
  {
  case 10: {
      setUsesTextLabel( ! menu->isItemChecked(10) );
      break;
    }
  case 20: {
      setUsesBigPixmaps( ! menu->isItemChecked(20) );
      break;
    }
  }

  return true;
}

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();

  removeChild(sd);
  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);

  _merge->setEnabled(true);
  _reload->setEnabled(true);
  _wspace->setOn( param->_whitespace );

  showOptions( param->_whitespace );
  setDiffCnt( _diffInfo->getDiffCnt() );
  showEncoding( param->_original->getEncoding() );
  
  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);

  _merge->setEnabled(true);
  _reload->setEnabled(true);
  _wspace->setOn( param->_whitespace );

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

  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->_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->_whitespace = _wspace->isOn();
      diff( p );
      break;
    }
  case FileSelectDialog::rDiff3:
    {
      DiffParamPtr p( new DiffParam() );
      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->_whitespace = _wspace->isOn();
      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() )
  {
    _next->setEnabled(true);
    _prev->setEnabled(true/*false*/);
  }
}

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->enableMerged( true, true );
  _merge->setEnabled(false);

  _fileMenu->setItemEnabled( pmiFileSave, true );
  _fileMenu->setItemEnabled( pmiFileSaveAs, true );
}

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

void MainWindow::refresh()
{
  switch( _lastParam->_type )
  {
  case DiffParam::Diff:
    {
      _lastParam->_whitespace = _wspace->isOn();
      diff( _lastParam );
      break;
    }
  case DiffParam::Diff3:
    {
      _lastParam->_whitespace = _wspace->isOn();
      diff3( _lastParam );
      break;
    }
  }
  _dw->repaint();
}

void MainWindow::diffChanged(int diff)
{
  _next->setEnabled(true/*_diffInfo->hasNextDiff()*/);
  _prev->setEnabled(true/*_diffInfo->hasPrevDiff()*/);
}

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("*") ) );
}


syntax highlighted by Code2HTML, v. 0.9.1