/* $Id: Mango.cpp,v 1.57 2003/09/18 11:59:04 rjesse Exp $
 *
 * Copyright (c) 2000-2003, Roland Jesse
 * All rights reserved.
 *
 * This file is part of the Mango recipe management distribution.
 * For license and copyright information see the file COPYRIGHT or 
 * <http://www.opensource.org/licenses/bsd-license.html>.
 */

#include "Mango.h"
#include "AboutForm.h"
#include "BusyWidget.h"
#include "CreateRecipeWindow.h"
#include "DocManager.h"
#include "Importer.h"
#include "ManageCookbooksForm.h"
#include "OrganiseRecipesForm.h"
#include "PasteRawTextForm.h"
#include "Printer.h"
#include "PrintPreviewForm.h"
#include "PreferencesDialog.h"
#include "QuickSearchForm.h"
#include "RecipeModel.h"
#include "RecipeView.h"
#include "RecipeListDialog.h"
#include "Repository.h"
#include "StartupDialog.h"
#include "TodoDialog.h"
#include "resources.h"

#include <qaction.h>
#include <qapplication.h>
#include <qfiledialog.h>
#include <qdragobject.h>
#include <qiconset.h>
#include <qlabel.h>
#include <qmenubar.h>
#include <qmessagebox.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <qpopupmenu.h>
#include <qsettings.h>
#ifdef NO_KDE2
# include <qstatusbar.h>
#else
# include <kstatusbar.h>
#endif
#include <qstring.h>
#include <qtoolbar.h>
#include <qtoolbutton.h>
#include <qvbox.h>
#include <qwhatsthis.h>
#include <qworkspace.h>

#include <qcdestyle.h>
#include <qmotifstyle.h>
#include <qmotifplusstyle.h>
#include <qplatinumstyle.h>
#include <qsgistyle.h>
#include <qwindowsstyle.h>

#include <assert.h>

/*
#include "copy.xpm"
#include "find.xpm"
#include "open.xpm"
#include "new.xpm"
#include "paste.xpm"
#include "print.xpm"
#include "redo.xpm"
#include "save.xpm"
#include "undo.xpm"
*/

const char* importText = "Import recipes from a file.";
const char* preferencesText = "Open the preferences dialog.";

/*! Instanciate the singleton instance. */
Mango* Mango::m_instance = 0;

/*! Singleton access. */
Mango*
Mango::getInstance() {
   if (m_instance == 0) {
      m_instance = new Mango();
      m_instance->slotLoadPreferences();
      m_instance->showStartupDialog();
   }
   return m_instance;
}

/*! Delete the singleton instance. Destructor is protected for a reason. */
void
Mango::deleteInstance() {
   if (m_instance != 0) {
	  m_instance->slotSavePreferences();
      delete m_instance;
      m_instance = 0;
   }
}

/*!
 * Constructor. Don't use directly but access the object instance
 * using getInstance().
 */
//Mango::Mango() : MangoForm( 0) {
Mango::Mango() : QextMdiMainFrm( 0) {
   QString cap;
   cap.append( tr( "Mango"));
   cap.append( " ");
   cap.append( MANGO_VERSION_STRING);
   setCaption( cap);
   initGuiActions();
   initMenuBar();
   initToolbars();
//   connect( Printer::getInstance(), SIGNAL( message( const QString&, int)),
//			statusBar(), SLOT( message( const QString&,
//			int)));
   statusBar()->message( STATUS_DEFAULT, 3000);
}

/**
 * Destructor. Don't use directly but delete the object instance using
 * deleteInstance().
 */
Mango::~Mango() {
   DocManager::deleteInstance();
   Printer::deleteInstance();
   Repository::deleteInstance();
}

/*!
  Synchronise position of MDI control buttons in main menu bar.
*/
void
Mango::resizeEvent( QResizeEvent* e)
{
   inherited::resizeEvent( e);
   setSysButtonsAtMenuPosition();
}

/*!  This is the application's main widget. If it is closed, we quit.
  Ask user whether (s)he is sure to quit.
*/
void
Mango::closeEvent( QCloseEvent*)
{
   slotQuit();
}

/** Initialize gui actions. */
void
Mango::initGuiActions()
{
   m_manageCookbooksAction = new QAction( this);
	 m_manageCookbooksAction->setText( tr( "Manage Cookbooks..."));
	 m_manageCookbooksAction->setMenuText( tr( "&Manage Cookbooks..."));
	 m_manageCookbooksAction->setAccel( tr( "Ctrl+M", "File|Manage Cookbooks"));
	 m_manageCookbooksAction->setToolTip( tr( "Manage Cookbooks..."));
	 m_manageCookbooksAction->setWhatsThis( tr( "Load, Save, Delete cookbooks"));
	 connect( m_manageCookbooksAction, SIGNAL( activated()), 
			  this, SLOT(slotManageCookbooks()));

   m_organiseRecipesAction = new QAction( this);
     m_organiseRecipesAction->setText( tr( "Organise Recipes"));
     m_organiseRecipesAction->setMenuText( tr( "O&rganise Recipes"));
     m_organiseRecipesAction->setAccel( tr( "Ctrl+R", "File|Organise Recipes"));
     m_organiseRecipesAction->setWhatsThis( tr( "Move recipes between cookbooks."));
     connect( m_organiseRecipesAction, SIGNAL( activated()),
              this, SLOT( slotOrganiseRecipes()));
         
   m_newAction = new QAction( this);
	 m_newAction->setText( tr( "New"));
    QPixmap image_new = fromMimeSource( "new.xpm");
	 m_newAction->setIconSet( QIconSet( image_new));
	 m_newAction->setMenuText( tr( "&New"));
	 m_newAction->setToolTip( tr( "Create a new recipe."));
	 m_newAction->setStatusTip( tr( "New"));
	 m_newAction->setWhatsThis( tr( "Create a new recipe."));
	 m_newAction->setAccel( tr( "Ctrl+N", "File|New"));
	 connect( m_newAction, SIGNAL( activated()), this, SLOT( slotNew()));

   m_openAction = new QAction( this);
    QPixmap image_open = fromMimeSource( "open.xpm");
	 m_openAction->setIconSet( QIconSet( image_open));
	 m_openAction->setText( tr( "Open"));
	 m_openAction->setMenuText( tr( "&Open..."));
	 m_openAction->setAccel( tr( "Ctrl+O", "File|Open"));
	 connect( m_openAction, SIGNAL( activated()), this, SLOT( slotOpen()));

   m_saveAction = new QAction( this);
	 QPixmap image_save = fromMimeSource( "save.xpm");
	 m_saveAction->setIconSet( QIconSet( image_save));
	 m_saveAction->setText( tr( "Save"));
	 m_saveAction->setMenuText( tr( "&Save..."));
	 m_saveAction->setAccel( tr( "Ctrl+S", "File|Save"));

   m_saveAsAction = new QAction( this);
	 m_saveAsAction->setText( tr( "Save As"));
	 m_saveAsAction->setMenuText( tr( "Save &as..."));
	 m_saveAsAction->setAccel( tr( "Ctrl+A", "File|Save as..."));
	 
   m_printAction = new QAction( this);
	 QPixmap image_print = fromMimeSource( "print.xpm");
	 m_printAction->setIconSet( QIconSet( image_print));
	 m_printAction->setText( tr( "Print"));
	 m_printAction->setMenuText( tr( "&Print..."));
	 m_printAction->setAccel( tr( "Ctrl+P", "File|Print"));
	 connect( m_printAction, SIGNAL( activated()), this, SLOT( slotPrint()));

   m_quitAction = new QAction( this);
	 m_quitAction->setText( tr( "Quit"));
	 m_quitAction->setMenuText( tr( "&Quit"));
	 m_quitAction->setAccel( tr( "Ctrl+Q", "File|Quit"));
	 connect( m_quitAction, SIGNAL( activated()), this, SLOT( slotQuit()));

   m_undoAction = new QAction( this);
	 QPixmap image_undo = fromMimeSource( "undo.xpm");
	 m_undoAction->setIconSet( QIconSet( image_undo));
	 m_undoAction->setText( tr( "Undo"));
	 m_undoAction->setMenuText( tr( "&Undo..."));
	 m_undoAction->setAccel( tr( "Ctrl+U", "Edit|Undo"));
         m_undoAction->setEnabled( false);

   m_redoAction = new QAction( this);
	 QPixmap image_redo = fromMimeSource( "redo.xpm");
	 m_redoAction->setIconSet( QIconSet( image_redo));
	 m_redoAction->setText( tr( "Redo"));
	 m_redoAction->setMenuText( tr( "&Redo..."));
	 m_redoAction->setAccel( CTRL+Key_U);
         m_redoAction->setEnabled( false);

   m_copyAction = new QAction( this);
	 QPixmap image_copy = fromMimeSource( "copy.xpm");
	 m_copyAction->setIconSet( QIconSet( image_copy));
	 m_copyAction->setText( tr( "Copy"));
	 m_copyAction->setMenuText( tr( "&Copy..."));
	 m_copyAction->setAccel( tr( "Ctrl+C", "Edit|Copy"));

   m_pasteAction = new QAction( this);
	 QPixmap image_paste = fromMimeSource( "paste.xpm");
	 m_pasteAction->setIconSet( QIconSet( image_paste));
	 m_pasteAction->setText( tr( "Paste"));
	 m_pasteAction->setMenuText( tr( "Paste..."));
	 m_pasteAction->setAccel( tr( "Ctrl+V", "Edit|Paste"));
	 // Not elegant but works for now.
	 connect( m_pasteAction, SIGNAL( activated()), this, SLOT( slotImportRaw()));

   m_findAction = new QAction( this);
	 QPixmap image_find = fromMimeSource( "find.pxm");
	 m_findAction->setIconSet( QIconSet( image_find));
	 m_findAction->setText( tr( "Find"));
	 m_findAction->setMenuText( tr( "&Find..."));
	 m_findAction->setAccel( tr( "Ctrl+F", "Edit|Find"));
	 connect( m_findAction, SIGNAL( activated()), this, SLOT( slotFind()));

   m_helpContentsAction = new QAction( this);
     m_helpContentsAction->setText( "Contents");
     m_helpContentsAction->setAccel( tr( "F1", "Help|Contents"));
     connect( m_helpContentsAction, SIGNAL( activated()), this, SLOT( slotHelpContents()));         
     /*
       Don't provide the online help for Qt versions < 3.1.0 as assistant
       will not provide sufficient methods to add custom content.
     */
     if (QT_VERSION < 0x030100)
        m_helpContentsAction->setEnabled( false);
     
   m_aboutAction = new QAction( this);
     m_aboutAction->setText( tr( "About"));
     m_aboutAction->setAccel( tr( "Ctrl+F1", "Help|About"));
     connect( m_aboutAction, SIGNAL( activated()), this, SLOT( slotAbout()));

   m_aboutQtAction = new QAction( this);
	 m_aboutQtAction->setText( tr( "About Qt"));
	 connect( m_aboutQtAction, SIGNAL( activated()), this, SLOT( slotAboutQt()));

   m_whatsThisAction = new QAction( this, "whatsThisAction");
     m_whatsThisAction->setText( trUtf8( "What's this?", ""));
	 m_whatsThisAction->setAccel( tr( "Shift+F1", "Help|What's this?"));
	 connect( m_whatsThisAction, SIGNAL( activated()),
			  this, SLOT( whatsThis()));
} // initGuiActions()

/** Initialize the menubar. */
void
Mango::initMenuBar() {
   int id;
   
   // synchronise positions of MDI control buttons inserted in main menu
   setMenuForSDIModeSysButtons( menuBar());

   // File -> Import
   QPopupMenu* import = new QPopupMenu( this);
     import->insertItem( tr( "Raw"), this, SLOT( slotImportRaw()));
	 import->insertItem( tr( "Dialog"), this, SLOT( slotImportDialog()));
	 import->insertItem( tr( "From file"), this, SLOT( slotImportFile()));

   // File
   QPopupMenu* fileMenu = new QPopupMenu( this);
     m_newAction->addTo( fileMenu);
	 m_openAction->addTo( fileMenu);
	 fileMenu->insertItem( tr( "Close"), this, SLOT( slotClose()), tr( "Ctrl+W", "Close Window"));
	 m_saveAction->addTo( fileMenu);
	 m_saveAsAction->addTo( fileMenu);
	 fileMenu->insertItem( tr( "Print Preview"), this, SLOT( slotPrintPreview()));
	 fileMenu->insertSeparator();
	 id = fileMenu->insertItem( tr( "Import"), import);
     fileMenu->setWhatsThis( id, importText);
	 m_manageCookbooksAction->addTo( fileMenu);
         m_organiseRecipesAction->addTo( fileMenu);
	 fileMenu->insertSeparator();
	 id = fileMenu->insertItem( tr( "Preferences..."), this, SLOT( slotPreferences()));
     fileMenu->setWhatsThis( id, preferencesText);
	 fileMenu->insertSeparator();
	 m_quitAction->addTo( fileMenu);
   
   // Edit
   QPopupMenu* editMenu = new QPopupMenu( this);
     m_undoAction->addTo( editMenu);
	 m_redoAction->addTo( editMenu);
	 editMenu->insertSeparator();
	 m_copyAction->addTo( editMenu);
	 m_pasteAction->addTo( editMenu);
	 editMenu->insertSeparator();
	 m_findAction->addTo( editMenu);

   // Help   
   QPopupMenu* helpMenu = new QPopupMenu( this);
     m_helpContentsAction->addTo( helpMenu);
     m_aboutAction->addTo( helpMenu);
     m_aboutQtAction->addTo( helpMenu);
     m_whatsThisAction->addTo( helpMenu);

   // Final menu bar construction.
   menuBar()->insertItem( tr( "&File"), fileMenu);
   menuBar()->insertItem( tr( "&Edit"), editMenu);
   if (!isFakingSDIApplication())
	  menuBar()->insertItem( tr( "&Window"), windowMenu());
   menuBar()->insertSeparator();
   menuBar()->insertItem( tr( "&Help"), helpMenu);
} // initMenuBar()

/*!
  Initialise the tool bar(s).
*/
void
Mango::initToolbars()
{
   m_standardToolbar = new QToolBar(this, "standard operations");
//     m_standardToolbar->setLabel( "Standard Tools");
	 m_newAction->addTo( m_standardToolbar);
	 m_openAction->addTo( m_standardToolbar);
	 m_saveAction->addTo( m_standardToolbar);
	 m_printAction->addTo( m_standardToolbar);
 	 m_standardToolbar->addSeparator();
 	 m_undoAction->addTo( m_standardToolbar);
 	 m_redoAction->addTo( m_standardToolbar);
 	 m_copyAction->addTo( m_standardToolbar);
 	 m_pasteAction->addTo( m_standardToolbar);
 	 m_findAction->addTo( m_standardToolbar);
	 m_standardToolbar->addSeparator();
	 QWhatsThis::whatsThisButton( m_standardToolbar);

	 m_busy = new BusyWidget( statusBar(), "busy");
	 statusBar()->addWidget( m_busy, 0, true);
} // initToolbars()

void
Mango::showStartupDialog()
{
   StartupDialog* dlg = new StartupDialog( m_startupTimeout, this);
   dlg->show();
}

void
Mango::slotSavePreferences()	// public
{
   // For UNIX-systems: try to create ~/.mango in case it does not exist.
   QDir home = QDir::home();
   QString path = home.path();
   path.append( "/.mango");
#ifdef Q_OS_UNIX
   if (! home.exists( path))
	  home.mkdir( path);
#endif

   QSettings settings;
   settings.insertSearchPath( QSettings::Unix, path);
   // No search path for Windows as default Registry path is fine.
   settings.writeEntry( "/Mango/StartupDialog/Timeout", m_startupTimeout);

   settings.writeEntry( "/Mango/Geometry/x", x());
   settings.writeEntry( "/Mango/Geometry/y", y());
   settings.writeEntry( "/Mango/Geometry/width", width());
   settings.writeEntry( "/Mango/Geometry/height", height());
   settings.writeEntry( "/Mango/Style", activeStyle());
   settings.writeEntry( "/Mango/MDI/mode", mdiMode());
   settings.writeEntry( "/Mango/MDI/frameHeight", childFrameModeHeight());
   settings.writeEntry( "/Mango/MDI/Maxed Childframes", isInMaximizedChildFrmMode());

   Repository* repo = Repository::getInstance();
   settings.writeEntry( "/Mango/Paths/ExportDirectory", repo->defaultPath( "ExportDirectory"));
   settings.writeEntry( "/Mango/Paths/LoadDirectory", repo->defaultPath( "LoadDirectory"));

   DocManager* docmgr = DocManager::getInstance();
   settings.writeEntry( "/Mango/Paths/DocRootDirectory", docmgr->getRootDirName());

   QStringList fileNames = repo->getCookbookFileNames();
   int curCbCounter = 0;
   for (QStringList::const_iterator cbIt = fileNames.begin(); cbIt != fileNames.end(); cbIt++) {
      // Don't store invalid path to cookbooks.
      if ((*cbIt).isEmpty()) continue;
      
      curCbCounter++;
      QString settingsPath;
      QString s = "/Mango/Paths/Cookbook";
      QTextOStream( &settingsPath) << s << curCbCounter;
      settings.writeEntry( settingsPath, *cbIt);
   }
   settings.writeEntry( "/Mango/Paths/Nr of cookbooks", curCbCounter);
} // slotSavePreferences()

void
Mango::slotLoadPreferences()
{
   QSettings settings;
   QDir home = QDir::home();
   QString path = home.path();
   path.append( "/.mango");
   settings.insertSearchPath( QSettings::Unix, path);
   // No search path for Windows as default Registry path is fine.

   m_startupTimeout = settings.readNumEntry( "/Mango/StartupDialog/Timeout", 30);

   Repository* repo = Repository::getInstance();
   path = settings.readEntry( "/Mango/Paths/ExportDirectory", "");
   repo->setDefaultPath( "ExportDirectory", path);
   path = settings.readEntry( "/Mango/Paths/LoadDirectory", "");
   repo->setDefaultPath( "LoadDirectory", path);

   DocManager* docmgr = DocManager::getInstance();
   path = settings.readEntry( "/Mango/Paths/DocRootDirectory", "");
   docmgr->slotSetRootDir( path);
   
   int x = settings.readNumEntry( "/Mango/Geometry/x");
   int y = settings.readNumEntry( "/Mango/Geometry/y");
   int w = settings.readNumEntry( "/Mango/Geometry/width", 640);
   int h = settings.readNumEntry( "/Mango/Geometry/height", 480);
   QPoint pos( x, y);
   QSize size( w, h);
   this->resize( size);
   this->move( pos);

#ifdef NO_KDE2                  // KDE comes with its own style
# ifndef Q_OS_WIN32             // Windows has its own style, too
# ifndef Q_OS_MACX              // dito for Mac OS X
# ifndef Q_OS_MAC9              // and for Mac OS 9
   QString style = settings.readEntry( "/Mango/Style", "platinum");
   setStyle( style);
# endif // no Mac OS 9
# endif // no MAC OS X
# endif	// no WIN32
#endif // NO_KDE2

   // restore MDI mode (toplevel, childframe, tabpage)
   int mdiMode = settings.readNumEntry( "/Mango/MDI/mode", QextMdi::ChildframeMode);
   int childFrameModeHeight = settings.readNumEntry( "/Mango/MDI/frameHeight", height() - 50);
   switch (mdiMode) {
	  case QextMdi::ToplevelMode:
	  {
		 resize( width(), childFrameModeHeight);
		 switchToToplevelMode();
	  }
	  break;
	  case QextMdi::ChildframeMode:
		 break;
	  case QextMdi::TabPageMode:
	  {
		 resize( width(), childFrameModeHeight);
		 switchToTabPageMode();
	  }
	  break;
	  default:
		 break;
   }
   // restore a possibly maximised childframe mode
   bool maxChildFrameMode = settings.readBoolEntry( "/Mango/MDI/Maxed Childframes", true);
   setEnableMaximizedChildFrmMode( maxChildFrameMode);
} // slotLoadPreferences()

void
Mango::setStartupTimeout( const int timeout)
{
   m_startupTimeout = timeout;
}

int
Mango::startupTimeout() const
{
   return m_startupTimeout;
}

void
Mango::setStyle( const QString& s) // public
{
   if (s.isEmpty()) {
      return;
   }
   QFont appFont = QApplication::font();
   qApp->setStyle( s);
   if (s == "platinum") {
      QPalette p( QColor( 239, 239, 239));
      qApp->setPalette( p, true);
   }
   qApp->setFont( appFont, true);
   m_activeStyle = s;
} // setStyle()

QString
Mango::activeStyle() const {
   return m_activeStyle;
}

void
Mango::setBusy( bool busy, const QString& message)
{
   if (busy) {
	  statusBar()->message( message);
	  m_busy->start();
   } else {
	  m_busy->stop();
	  statusBar()->message( message, STATUS_NOTICE_DURATION);
   }
}

void
Mango::slotAbout() {
   AboutForm* dlg = new AboutForm( this);
   dlg->show();
}

void
Mango::slotAboutQt()
{
   QMessageBox::aboutQt( this, tr( "Mango, the recipe management program"));
}

void
Mango::slotNew() {
   statusBar()->message( tr( "Creating new recipe..."));

   CreateRecipeWindow* aWin = new CreateRecipeWindow( this);
   addWindow( aWin);
   /** Make sure the new window is visible. */
   update(); // FIXME: obsolete

   statusBar()->message( STATUS_DEFAULT);
}

void
Mango::slotFind() {
   statusBar()->message( tr( "Searching for a recipe..."));

   QuickSearchForm* win = new QuickSearchForm( this);
   addWindow( win);

   statusBar()->message( STATUS_DEFAULT);
}

void
Mango::slotOpen() {
   QString startDir = Repository::getInstance()->defaultPath( "LoadDirectory");
   QString filter = Importer::getSupportedFileExtensions();
   QString fn = QFileDialog::getOpenFileName( startDir, filter, this);
    if (!fn.isEmpty())
	   slotOpen( fn);
    else
	   statusBar()->message( "Loading aborted", 2000); 
}

void
Mango::slotOpen( const QString& fname)
{
   try {
      RecipeModel* model = Repository::getInstance()->addCookbookFromFile( fname);
      RecipeListDialog* win = new RecipeListDialog( model, this);
      addWindow( win);
   }
   catch (Error& e) {
      QMessageBox::warning( this, tr( "Reading file"),
                            tr( "Error reading file %1: %2")
                            .arg( fname) .arg( e.what()));
   }
}

/*!
 * Open a dialog with all necessary fields for the user to enter a recipe.
 */
void
Mango::slotImportDialog() {
   statusBar()->message( tr( "Please enter a recipe."));
   TodoDialog* d = new TodoDialog( "Import dialog", this);
   d->exec();
   statusBar()->message( STATUS_DEFAULT);
}

/*!
  Import recipes from the file the user has to specify in a dialog.
*/
void
Mango::slotImportFile() {
   statusBar()->message( "Import recipe(s) from file...");
   QString filter = Importer::getSupportedFileExtensions();
   QString fn = QFileDialog::getOpenFileName( 
	  QString::null, "*.mm *.xml", this, "import", filter);
   if (! fn.isNull()) {
      try {
         Repository::getInstance()->addCookbookFromFile( fn);
      }
      catch( Error& e) {
         statusBar()->message( e.what(), STATUS_NOTICE_DURATION);
      }
   }
   else
      statusBar()->message( STATUS_DEFAULT);
}

/*!
  Open a text field where the user can paste raw text into that (hopefully)
  contains a meal master recipe or two...
*/
void
Mango::slotImportRaw() {
   statusBar()->message( 
	  tr( "Please paste the recipe text in Meal-Master format into the dialog."));
   PasteRawTextForm* dlg = new PasteRawTextForm( this);
   addWindow( dlg);
   statusBar()->message( STATUS_DEFAULT);
}

void
Mango::slotManageCookbooks() {
   if (QextMdiChildView* win = findWindow( tr( "Manage Cookbooks")))
	  win->activate();
   else {
	  ManageCookbooksForm* manageWin = new ManageCookbooksForm( this);
	  addWindow( manageWin);
   }
}

void
Mango::slotOrganiseRecipes()
{
   if (QextMdiChildView* win = findWindow( tr( "Organise Recipes")))
      win->activate();
   else {
      OrganiseRecipesForm* orgWin = new OrganiseRecipesForm( this);
      addWindow( orgWin);
   }
} // slotOrganiseRecipes()

/*! Open all cookbooks that where open the last time Mango was used. */
void
Mango::slotContinueFromLastTime()
{
   QSettings settings;
   QDir home = QDir::home();
   QString path = home.path();
   path.append( "/.mango");
   settings.insertSearchPath( QSettings::Unix, path);
   // No search path for Windows as default Registry path is fine.
   int nrOfCookbooks = settings.readNumEntry( "/Mango/Paths/Nr of cookbooks");
   for (int counter = 1; counter <= nrOfCookbooks; counter++) {
	  QString settingsPath;
	  QString s = "/Mango/Paths/Cookbook";
	  QTextOStream( &settingsPath) << s << counter;
	  QString filename = settings.readEntry( settingsPath);
          QFileInfo finfo( filename);
          if (finfo.exists())
             Repository::getInstance()->addCookbookFromFile( filename);
   }
   slotManageCookbooks();
   statusBar()->message( STATUS_DEFAULT);
} // slotContinueFromLastTime()

void
Mango::slotClose()
{
   QextMdiChildView* aw = activeWindow();
   if (aw) aw->close( true);
}

void
Mango::slotQuit() {
   Repository* repo = Repository::getInstance();
   if (repo->hasUnsavedCookbooks()) {
	  int choice = QMessageBox::warning( this, tr( "Unsaved cookbooks..."),
										 tr( "At least one cookbook contains unsaved changes. Save them before exiting?"),
										 QMessageBox::Yes,
										 QMessageBox::No,
										 QMessageBox::Abort);
	  switch (choice) {
		 case QMessageBox::Yes:
			repo->saveAllChanges();
			break;
		 case QMessageBox::No:
			break;
		 case QMessageBox::Abort:
			return;
			break;
		 default:               // Probably, ESC was hit. Just take it as "No".
			break;
	  }
   }

   deleteInstance();
   qApp->quit();
}

void
Mango::slotPrint() {
   Printer* printer = Printer::getInstance();
   printer->setParentWidget( this);

   // FIXME: What about printing whole cookbooks?
   Recipe curRecipe( Repository::getInstance()->currentRecipe());
   if (curRecipe.isValid())
      printer->setRecipe( curRecipe);
   else {
      statusBar()->message( tr( "No recipe active and ready for printing."));
      return;
   }
   
   try {
      printer->apply();
   }
   catch( Error& e) {
      statusBar()->message( e.what(), STATUS_NOTICE_DURATION);
   }
}

void
Mango::slotPrintPreview()
{
   Printer* printer = Printer::getInstance();
   printer->setParentWidget( this);

   // FIXME: What about printing whole cookbooks?
   Recipe curRecipe( Repository::getInstance()->currentRecipe());
   if (curRecipe.isValid())
      printer->setRecipe( curRecipe);
   else {
      statusBar()->message( tr( "No recipe active and ready for printing."));
      return;
   }

   PrintPreviewForm* preview = new PrintPreviewForm( this);
   addWindow( preview);
}

void
Mango::slotPreferences() {
   PreferencesDialog* p = new PreferencesDialog( this);
   p->show();
}

void
Mango::slotHelpContents()
{
   DocManager::getInstance()->slotOpen( "index.html");
}

/*!
   Retrieves the image associated with \a absName, converts it into a pixmap and returns it.
   This is mainly a convenience function as Qt 3.1 introduces QPixmap::fromMimeSource() which
   does basically the same thing. Using this function, we just stay a bit more backward 
   compatible. Not, that it matters much, though.

  In order to add new images, just add them to the IMAGES line in mango.pro.
*/
QPixmap
Mango::fromMimeSource( const QString& absName) const
{
   QPixmap ret;
   const QMimeSource* ms = QMimeSourceFactory::defaultFactory()->data( absName);
   if (!ms) {
      if (QFile::exists( absName)) {
         ret = QPixmap( absName);
      }
   }
   else {
      QImageDrag::decode( ms, ret);
   }
   return ret;
}
