/***************************************************************************
                          FLApplication.cpp
                         -------------------
begin                : Mon Jul 2 2001
copyright            : (C) 2001-2005 by InfoSiAL, S.L.
email                : mail@infosial.com
***************************************************************************/
/***************************************************************************
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; version 2 of the License.               *
 ***************************************************************************/
/***************************************************************************
   Este  programa es software libre. Puede redistribuirlo y/o modificarlo
   bajo  los  términos  de  la  Licencia  Pública General de GNU   en  su
   versión 2, publicada  por  la  Free  Software Foundation.
 ***************************************************************************/

#include <qsworkbench.h>

#include "FLApplication.h"
#include "FLAbout.h"
#include "FLFormDB.h"
#include "FLObjectFactory.h"
#include "FLWidgetAction.h"
#include "FLAction.h"
#include "FLTranslator.h"
#include "FLAccessControlLists.h"
#include "FLSqlDatabase.h"
#include "FLSqlSavePoint.h"
#include "FLSqlConnections.h"
#include "FLDiskCache.h"
#include "FLMemCache.h"
#include "FLTranslations.h"
#include "FLSettings.h"
#include "AQSObjectFactory.h"
#include "AQSWrapperFactory.h"
#include "metatranslator.h"

#ifdef FL_DEBUG
#include "FLFieldMetaData.h"
#include "FLRelationMetaData.h"
#endif

#include "AQConfig.h"

extern bool aqQSARunning;

// Uso interno
class FLWorkspace : public QWorkspace
{
public:

  FLWorkspace(QWidget *parent = 0, const char *name = 0);

protected:

  void paintEvent(QPaintEvent *pe);

private:

  QImage logo;
  QColor fColor, pColor;
};

class FLWidget : public QWidget
{
public:

  FLWidget(QWidget *parent = 0, const char *name = 0,  WFlags f = 0);

protected:

  void paintEvent(QPaintEvent *pe);

private:

  QImage logo;
  QColor fColor, pColor;
};

class FLTimerDbLock : public QTimer
{
public:

  FLTimerDbLock(QObject *parent = 0, const char *name = 0)
    : QTimer(parent, name) {}

  int dbLocksLapsus_;
  int dbLocksChecks_;
  bool dbLocksShowWarn_;
  QString dbLocksMsgWarn_;
  QString dbLocksConn_;
};

class FLPopupWarn : public QWhatsThis
{
public:

  FLPopupWarn(QWidget *widget)
    : QWhatsThis(widget) {}

  bool clicked(const QString &href);
  QMap<QString, QSArgumentList> scriptCalls_;
};

bool FLPopupWarn::clicked(const QString &href)
{
  if (!href.isEmpty()) {
    QString h(href);
    if (href.contains(':'))
      h = href.section(':', 1, 1);
    if (h.contains('.') == 1)
      aqApp->call(h.section('.', 1, 1),  scriptCalls_[href], h.section('.', 0, 0));
    else
      aqApp->call(h, scriptCalls_[href], 0);
  }
  return false;
}

static QTextEdit *abanqTedOutput = 0;
static void (*aq_default_message_handler)(QtMsgType, const char *msg) = 0;

void abanqMessageOutput(QtMsgType type, const char *msg)
{
  if (aq_default_message_handler) {
    aq_default_message_handler(type, msg);
  } else {
    fprintf(stderr, "%s\n", msg);
    fflush(stderr);
  }

  if (abanqTedOutput) {
    if (QStyleSheet::mightBeRichText(msg))
      abanqTedOutput->append(msg);
    else
      abanqTedOutput->append(QStyleSheet::convertFromPlainText(msg));
  }
}

#if !defined(QSDEBUGGER) && !defined(AQ_NEBULA_BUILD_VERBOSE)
void abanqMessageVoidOutput(QtMsgType, const char *)
{
}
#endif

class FLTextEditOuput : public QTextEdit
{
public:
  FLTextEditOuput(QWidget *parent = 0, const char *name = 0)
    : QTextEdit(parent, "abanqTedOutput") {
    setProperty("readOnly", true);
    setProperty("frameShape", "LineEditPanel");
    setProperty("textFormat", "RichText");
    setProperty("undoDepth", 0);
    setProperty("overwriteMode", QVariant(false, 0));
    setProperty("paletteBackgroundColor", Qt::white);
    setProperty("paletteForegroundColor", Qt::black);
    setCaption(tr("Consola de mensajes de Eneboo"));
  }

protected:
  void hideEvent(QHideEvent *e) {
    if (e->spontaneous())
      return;
    aqApp->saveGeometryForm(name(), geometry());
#if !defined(QSDEBUGGER) && !defined(AQ_NEBULA_BUILD_VERBOSE)
    qInstallMsgHandler(abanqMessageVoidOutput);
#else
    if (abanqTedOutput)
      qInstallMsgHandler(0);
#endif
    abanqTedOutput = 0;
    if (::qt_cast<QDockWindow *>(parentWidget()))
      parentWidget()->hide();
  }

  void showEvent(QShowEvent *e) {
    if (e->spontaneous())
      return;
    QRect geo(aqApp->geometryForm(name()));
    if (geo.isNull()) {
      QDesktopWidget *dsk = QApplication::desktop();
      resize(dsk->width() / 2, dsk->height() / 3);
    } else
      setGeometry(geo);
#if !defined(QSDEBUGGER) && !defined(AQ_NEBULA_BUILD_VERBOSE)
    qInstallMsgHandler(0);
#else
    if (abanqTedOutput)
      qInstallMsgHandler(0);
#endif
    abanqTedOutput = this;
    aq_default_message_handler = qInstallMsgHandler(abanqMessageOutput);
  }

  void keyPressEvent(QKeyEvent *e) {
    if (e->key() == Qt::Key_Escape)
      close();
    else
      QTextEdit::keyPressEvent(e);
    e->accept();
  }
};

FLApplication::FLApplication(int &argc, char **argv) :
  AQ_IMPL_APP(argc, argv),
  pWorkspace(0), mainWidget_(0), container(0), toolBox(0),
  toggleBars(0), project_(0), wb_(0), dictMainWidgets(0),
  formAlone_(false), notExit_(false), acl_(0), popupWarn_(0),
  mngLoader_(0), sysTr_(0), initializing_(false), destroying_(false),
  flFactory_(0), opCheckUpdate_(0),
  notifyBeginTransaction_(false),
  notifyEndTransaction_(false),
  notifyRollbackTransaction_(false),
  tedOutput_(0), style(0), timerIdle_(0), initSingleFLLarge_(false)
{
  aqApp = this;

  AQConfig::init(this);
  FLMemCache::init();
  FLDiskCache::init();
  flFactory_ = new FLObjectFactory;
  timeUser_ = QDateTime::currentDateTime();
  multiLangEnabled_ = false;
  multiLangId_ = QString(QTextCodec::locale()).left(2).upper();

  localeSystem_ = QLocale::system();
  double v = 1.1;
  commaSeparator_ = localeSystem_.toString(v, 'f', 1).at(1);

  QObject::setName("aqApp");

  QPixmapCache::setCacheLimit(2048);

#if !defined(QSDEBUGGER) && !defined(AQ_NEBULA_BUILD_VERBOSE)
  qInstallMsgHandler(abanqMessageOutput);
#endif
}

FLApplication::~FLApplication()
{
  destroying_ = true;
  stopTimerIdle();
  checkAndFixTransactionLevel("Application::~Application()");
  FLSqlDatabase *appDb = db();
  if (appDb) {
    appDb->setInteractiveGUI(false);
    appDb->setQsaExceptions(false);
  }
  if (dictMainWidgets) {
    dictMainWidgets->setAutoDelete(true);
    dictMainWidgets->clear();
    dictMainWidgets->setAutoDelete(false);
  }
  clearProject();
  delete project_;
  delete tedOutput_;
  FLSqlConnections::finish();

#ifdef FL_DEBUG
  qWarning("*************************************************");
  qWarning("FLSqlQuery::countRefQuery");
  qWarning("*************************************************");
  qWarning(QString::number(FLSqlQuery::countRefQuery));
  qWarning("*************************************************");
  qWarning("FLSqlQuery::countRefQuery");
  qWarning("*************************************************");

  qWarning("*************************************************");
  qWarning("FLSqlCursor::countRefCursor");
  qWarning("*************************************************");
  qWarning(QString::number(FLSqlCursor::countRefCursor));
  qWarning("*************************************************");
  qWarning("FLSqlCursor::countRefCursor");
  qWarning("*************************************************");
  qWarning("FLTableMetaData::count_ %d", FLTableMetaData::count_);
  qWarning("FLFieldMetaData::count_ %d", FLFieldMetaData::count_);
  qWarning("FLRelationMetaData::count_ %d", FLRelationMetaData::count_);
#endif

  aqApp = 0;
}

bool FLApplication::eventFilter(QObject *obj, QEvent *ev)
{
  if (initializing_ || destroying_)
    return QApplication::eventFilter(obj, ev);

  if (activeModalWidget() || activePopupWidget())
    return QApplication::eventFilter(obj, ev);

  QEvent::Type evt = ev->type();

  if (formAlone_) {
    if (evt == QEvent::Close) {
      generalExit();
      return true;
    }
    return QApplication::eventFilter(obj, ev);
  }

  if (obj != mainWidget_ && !::qt_cast<QMainWindow *>(obj))
    return QApplication::eventFilter(obj, ev);

  QWidget *aw = (pWorkspace ? pWorkspace->activeWindow() : 0);
  if (aw && aw != obj && evt != QEvent::Resize && evt != QEvent::Close) {
    obj->removeEventFilter(this);
    if (evt == QEvent::WindowActivate) {
      if (obj == container)
        activateModule("");
      else
        activateModule(obj->name());
    }
    if (pWorkspace && notify(pWorkspace->activeWindow(), ev)) {
      obj->installEventFilter(this);
      return true;
    }
    obj->installEventFilter(this);
  }
  FLApplicationInterface *ap2 = new FLApplicationInterface(this);
  switch (evt) {
    case QEvent::KeyPress:
      if (obj == container) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(ev);
      }
      if (obj == mainWidget_) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(ev);
        if (ke->key() == Key_Shift && (ke->state() & ControlButton)) {
          activateModule("");
          return true;
        }
        if (ke->key() == Key_Q && (ke->state() & ControlButton)) {
          generalExit();
          return true;
        }
        if (ke->key() == Key_W && (ke->state() & (ControlButton | AltButton))) {
          openQSWorkbench();
          return true;
        }
        if (ke->key() == Key_Escape) {
          static_cast<QWidget *>(obj)->hide();
          return true;
        }
      }
      break;
    case QEvent::Close:
      if (obj == container) {
        generalExit();
        return true;
      } else {
        static_cast<QWidget *>(obj)->hide();
        return true;
      }
      break;
    case QEvent::WindowActivate:
      if (obj == container) {
        activateModule("");
        return true;
      } else {
        activateModule(obj->name());
        return true;
      }
      break;
    case QEvent::MouseButtonPress:
      if (modulesMenu) {
        QMouseEvent *me = static_cast<QMouseEvent *>(ev);
        if (me->button() == RightButton) {
          modulesMenu->popup(QCursor::pos());
          return true;
        } else
          return false;
      } else
        return false;
      break;
  }

  return QApplication::eventFilter(obj, ev);
}

void FLApplication::checkForUpdate()
{
  QSArgument v = call("sys.decryptFromBase64",
                      QSArgumentList("68Su+eg2qjFAItaejAcLlOFBiXPFJUbZKEWeCczeIDU="), 0);
  QString key(v.variant().toString());
  hashUpdate_ = "VOID";

  QString fileName(AQ_DISKCACHE_FILEPATH(key));
  if (fileName.isEmpty()) {
    AQ_DISKCACHE_INS(key, hashUpdate_);
    fileName = AQ_DISKCACHE_FILEPATH(key);
  } else {
    QFileInfo fi(fileName);
    QString now(QDateTime::currentDateTime().toString("ddMMyyyy"));
    if (fi.lastModified().toString("ddMMyyyy") == now)
      return;
    AQ_DISKCACHE_FIND(key, hashUpdate_);
  }

  QFile::remove(fileName);
  v = call("sys.decryptFromBase64",
           QSArgumentList("lKvF+hkDxk2dS6hrf0jVURL4EceyJIFPeigGw6lZAU/3ovk/v0iZfhklru4Q6t6M"), 0);
  opCheckUpdate_ = new QUrlOperator(v.variant().toString());
  opCheckUpdate_->copy(key, "file://" + fileName, false, false);
  connect(opCheckUpdate_, SIGNAL(finished(QNetworkOperation *)),
          this, SLOT(checkForUpdateFinish(QNetworkOperation *)));
}

void FLApplication::checkForUpdateFinish(QNetworkOperation *op)
{
  if (!opCheckUpdate_)
    return;
  if (op->state() != QNetworkProtocol::StDone) {
    opCheckUpdate_->deleteLater();
    opCheckUpdate_ = 0;
    return;
  }

  QSArgument v = call("sys.decryptFromBase64",
                      QSArgumentList("68Su+eg2qjFAItaejAcLlOFBiXPFJUbZKEWeCczeIDU="), 0);
  QString key(v.variant().toString());
  QString newHash;
  AQ_DISKCACHE_FIND(key, newHash);

  if (newHash != hashUpdate_)
    QTimer::singleShot(0, this, SLOT(updateAbanQ()));

  opCheckUpdate_->deleteLater();
  opCheckUpdate_ = 0;
}

void FLApplication::init(const QString &n, const QString &callFunction,
                         const QString &arguments, bool quitAfterCall, bool noMax)
{
  initializing_ = true;

  dictMainWidgets = new QDict <QWidget>(37);
  container = new QMainWindow(0);
  container->setName("container");
  container->setIcon(QPixmap::fromMimeSource("icono_abanq.png"));
  if (db())
    container->setCaption(db()->database());
  else
    container->setCaption("Eneboo " AQ_VERSION);

  FLDiskCache::init(this);
#if 0
  //#ifndef QSDEBUGGER
  AQ_DISKCACHE_CLR();
#endif

  if (n.isEmpty() || (!callFunction.isEmpty() && quitAfterCall)) {
    windowMenu = new QPopupMenu(container, "windowMenu");
    windowCascadeAction = new QAction(tr("Cascada"), tr("Cascada"), QKeySequence(), container);
    windowCascadeAction->setIconSet(QIconSet(QPixmap::fromMimeSource("cascada.png")));
    windowCascadeAction->addTo(windowMenu);
    windowTileAction = new QAction(tr("Mosaico"), tr("Mosaico"), QKeySequence(), container);
    windowTileAction->setIconSet(QIconSet(QPixmap::fromMimeSource("mosaico.png")));
    windowTileAction->addTo(windowMenu);
    windowCloseAction = new QAction(tr("Cerrar"), tr("Cerrar"), QKeySequence(), container);
    windowCloseAction->setIconSet(QIconSet(QPixmap::fromMimeSource("cerrar.png")));
    windowCloseAction->addTo(windowMenu);

    modulesMenu = new QPopupMenu(container, "modulesMenu");
    modulesMenu->setCheckable(false);

    QWidget *w = new QWidget(container, "widgetContainer");
    QVBoxLayout *vL = new QVBoxLayout(w);
    exitButton = new QPushButton(QPixmap::fromMimeSource("exit.png"), tr("Salir"), w, "pbSalir");
    exitButton->setAccel(QKeySequence(tr("Ctrl+Q")));
    exitButton->setFocusPolicy(QWidget::NoFocus);
    QToolTip::add(exitButton, tr("Salir de la aplicación (Ctrl+Q)"));
    QWhatsThis::add(exitButton, tr("Salir de la aplicación (Ctrl+Q)"));
    connect(exitButton, SIGNAL(clicked()), this, SLOT(generalExit()));
    toolBox = new QToolBox(w, "toolBox");
    vL->addWidget(exitButton);
    vL->addWidget(toolBox);
    container->setCentralWidget(w);
  }

  qInitNetworkProtocols();

  //#ifdef QSDEBUGGER
  //  project_ = new QSProject(this, db()->database());
  //#else
  project_ = new QSProject(0, db()->database());
  //#endif

  AQ_SET_MNGLOADER

  db()->manager()->init();
  mngLoader_->init();

  if (n.isEmpty() || (!callFunction.isEmpty() && quitAfterCall)) {
    initStyles();
    initMenuBar();
  }

  db()->manager()->loadTables();
  mngLoader_->loadKeyFiles();
  mngLoader_->loadAllIdModules();
  mngLoader_->loadIdAreas();

  acl_ = new FLAccessControlLists();
  acl_->init();

  loadScripts();
  mngLoader_->setShaLocalFromGlobal();
  loadTranslations();

  QSInterpreter *i = project_->interpreter();
  if (i) {
    i->addObjectFactory(flFactory_);
    i->addObjectFactory(new AQSObjectFactory);
    i->addWrapperFactory(new AQSWrapperFactory);
    i->addObjectFactory(new QSInputDialogFactory);
    i->addObjectFactory(new QSUtilFactory);
#ifdef FL_DEBUGGER
if (FLSettings::readBoolEntry("application/isDebuggerMode"))
    i->setErrorMode( QSInterpreter::AskForDebug );
else
    i->setErrorMode( QSInterpreter::Notify );    
#else
    i->setErrorMode( QSInterpreter::Notify );
#endif
    i->setInteractiveGUI(db()->interactiveGUI());
  } else {
    // Failed loading QSA.
  }

  if (!callFunction.isEmpty()) {

    QStringList argumentList = QStringList::split(':', arguments, false);
    QSArgumentList arglist;
    for (QStringList::Iterator it = argumentList.begin(); it != argumentList.end(); ++it) {
      arglist.append(QSArgument(*it));
    }
    call(callFunction, arglist, 0);
    if (quitAfterCall) {
      if (!db()->driverName().isEmpty())
        FLVar::clean();
      mngLoader_->finish();
      db()->manager()->finish();
      QTimer::singleShot(3000, this, SLOT(quit()));
    }
  }
  

  if (!quitAfterCall) {
    if (n.isEmpty()) {
      call("init", QSArgumentList(), "sys");
      initToolBox();
      readState();
      container->installEventFilter(this);
#if 0
      //#ifndef QSDEBUGGER
      checkForUpdate();
#endif
    } else {
      FLFormDB *f = new FLFormDB(n, 0, (noMax ? 0 : Qt::WStyle_Customize));
      formAlone_ = true;
      if (f) {
        f->installEventFilter(this);
        f->setMainWidget();
        QApplication::setMainWidget(f);
        if (f->mainWidget()) {
          if (noMax) {
            f->show();
          } else {
            f->showMaximized();
          }
        } else {
          f->close();
        }
      }
    }
  }

  AQ_UNSET_MNGLOADER
  initializing_ = false;

  connect(project_, SIGNAL(projectEvaluated()), this, SLOT(evaluatedProject()));
  startTimerIdle();
}


int FLApplication::initfcgi()
{
  initializing_ = true;

  container = new QMainWindow(0);
  container->setName("container");
  container->setCaption("Eneboo " AQ_VERSION);

  FLDiskCache::init(this);
#ifndef QSDEBUGGER
  AQ_DISKCACHE_CLR();
#endif

  qInitNetworkProtocols();

#ifdef QSDEBUGGER
  project_ = new QSProject(this, db()->database());
#else
  project_ = new QSProject(0, db()->database());
#endif

  AQ_SET_MNGLOADER

  db()->manager()->init();
  mngLoader_->init();

  db()->manager()->loadTables();
  mngLoader_->loadKeyFiles();
  mngLoader_->loadAllIdModules();
  mngLoader_->loadIdAreas();

  acl_ = new FLAccessControlLists();
  acl_->init();

  loadScripts();
  mngLoader_->setShaLocalFromGlobal();
  loadTranslations();

  QSInterpreter *i = project_->interpreter();
  if (i) {
    i->addObjectFactory(flFactory_);
    i->addObjectFactory(new AQSObjectFactory);
    i->addWrapperFactory(new AQSWrapperFactory);
    i->addObjectFactory(new QSInputDialogFactory);
    i->addObjectFactory(new QSUtilFactory);
#ifdef FL_DEBUGGER
    i->setErrorMode( QSInterpreter::AskForDebug );
#else
    i->setErrorMode( QSInterpreter::Notify );
#endif
  } else {
    // Failed loading QSA.
  }

/*
    QStringList argumentList = QStringList::split(':', arguments, false);
    QSArgumentList arglist;
    for (QStringList::Iterator it = argumentList.begin(); it != argumentList.end(); ++it) {
      arglist.append(QSArgument(*it));
    }
    call(callFunction, arglist, 0);

  if (!db()->driverName().isEmpty())
    FLVar::clean();
  mngLoader_->finish();
  db()->manager()->finish();
  QTimer::singleShot(3000, this, SLOT(quit()));
  */
  AQ_UNSET_MNGLOADER

  initializing_ = false;
    
}

void FLApplication::addObjectFactory(QSObjectFactory *newObjectFactory) {
	QSInterpreter *i = project_->interpreter();
	if (i) {
		if (newObjectFactory == NULL) {
			qDebug("ERROR: newObjectFactory == NULL!");
			return;
		}
		i->addObjectFactory(newObjectFactory);
	}
}


QString FLApplication::callfcgi(const QString &callFunction, QStringList argumentList) {    
    initializing_ = true;
    AQ_SET_MNGLOADER
    QSArgumentList arglist;
    for (QStringList::Iterator it = argumentList.begin(); it != argumentList.end(); ++it) {
      arglist.append(QSArgument(*it));
    }
    QSArgument ret = call(callFunction, arglist, 0);
    // return ret.typeName();
    QVariant v = ret.variant();
    AQ_UNSET_MNGLOADER
    initializing_ = false;
    return v.asString();        
}

void FLApplication::endfcgi() {    
    initializing_ = true;

  AQ_SET_MNGLOADER
  
  if (!db()->driverName().isEmpty()) FLVar::clean();
  mngLoader_->finish();
  db()->manager()->finish();
  QTimer::singleShot(10, this, SLOT(quit()));
  AQ_UNSET_MNGLOADER
    initializing_ = false;

  
}



void FLApplication::openQSWorkbench()
{
#ifdef QSDEBUGGER
  if (project_) {
    if (!wb_)
      wb_ = new QSWorkbench(project_, 0, db()->database());
    wb_->open();
    wb_->widget()->raise();
    wb_->widget()->showMaximized();
  }
#endif
}


void FLApplication::initMainWidget()
{
  if (!mainWidget_ || !container)
    return;

  QMainWindow *mw = ::qt_cast<QMainWindow *>(mainWidget_);
  if (mw) {
    mw->menuBar()->insertItem(tr("&Ventana"), windowMenu);
    mw->setCentralWidget(0);
  }

  initView();
  initActions();
  initToolBar();
  initStatusBar();

  readStateModule();
}

void FLApplication::showMainWidget(QWidget *w)
{
  if (!container) {
    if (w)
      w->show();
    return;
  }

  QWidget *focusW = focusWidget();

  if (w == container || !w) {
    if (container->isMinimized())
      container->showNormal();
    else if (!container->isVisible()) {
      container->setFont(font());
      container->show();
    }
    if (focusW && focusW->isA("QMainWindow") && focusW != container)
      container->setFocus();
    if (!container->isActiveWindow()) {
      container->raise();
      container->setActiveWindow();
    }
    if (db())
      container->setCaption(db()->database());
    else
      container->setCaption("Eneboo  " AQ_VERSION);
    return;
  }

  if (w->isMinimized())
    w->showNormal();
  else if (!w->isVisible()) {
    w->show();
    w->setFont(font());
  }
  if (focusW && focusW->isA("QMainWindow") && focusW != w)
    w->setFocus();
  if (!w->isActiveWindow()) {
    w->raise();
    w->setActiveWindow();
  }

  QMainWindow *mw = ::qt_cast<QMainWindow *>(w);
  if (mw) {
    QWidget *view_back = mw->centralWidget();
    if (view_back) {
      pWorkspace = static_cast<FLWorkspace *>(view_back->child(mw->name(), "QWorkspace"));
      view_back->show();
    }
  }

  AQ_SET_MNGLOADER

  setCaptionMainWidget("");
  QString descripArea = mngLoader_->idAreaToDescription(mngLoader_->activeIdArea());
  w->setIcon(mngLoader_->iconModule(w->name()));
  toolBox->setCurrentItem(static_cast<QToolBar *>(toolBox->child(descripArea, "QToolBar")));

  AQ_UNSET_MNGLOADER
}

void FLApplication::setMainWidget(QWidget *w)
{
  if (!container)
    return;

  if (w == container || !w) {
    QApplication::setMainWidget(container);
    mainWidget_ = 0;
    return;
  }

  QApplication::setMainWidget(w);
  mainWidget_ = w;

  QMainWindow *mw = ::qt_cast<QMainWindow *>(mainWidget_);
  if (!mw)
    return;

  QAction *a, *b;
  if (toggleBars) {
    QObject *tgb = container->child("agToggleBars");
    a = ::qt_cast<QAction *>(tgb->child("Herramientas"));
    b = ::qt_cast<QAction *>(tgb->child("Estado"));
    QToolBar *tB = ::qt_cast<QToolBar *>(mw->child("toolBar"));
    if (tB)
      a->setOn(tB->isShown());
    b->setOn(mw->statusBar()->isShown());
  }
}

void FLApplication::makeStyle(const QString &style)
{
  QPalette p = palette();
  setStyle(style);
  setPalette(p, true);
  initToolBox();
  FLSettings::writeEntry("style", style);
}

void FLApplication::chooseFont()
{
  setFont(QFontDialog::getFont(0, font(), mainWidget()), true);
  QWidgetList *list = allWidgets();
  QWidgetListIt it(*list);
  QWidget *w;

  while ((w = it.current()) != 0) {
    ++it;
    w->setFont(font());
  }

  FLSettings::writeEntry("font/family", font().family());
  FLSettings::writeEntry("font/pointSize", font().pointSize());
  FLSettings::writeEntry("font/bold", font().bold());
  FLSettings::writeEntry("font/italic", font().italic());
  FLSettings::writeEntry("font/underline", font().underline());
  FLSettings::writeEntry("font/strikeOut", font().strikeOut());
}

void FLApplication::showStyles()
{
  if (!style)
    initStyles();
  if (style)
    style->exec(QCursor::pos());
}

void FLApplication::showToggleBars()
{
  if (toggleBars)
    toggleBars->exec(QCursor::pos());
}

void FLApplication::initToolBox()
{
  
  if (!toolBox || !modulesMenu)
    return;

  modulesMenu->clear();
  while (toolBox->count()) {
    QWidget *item = toolBox->item(0);
    if (item) {
      if (item->isA("QToolBar"))
        static_cast<QToolBar *>(item)->clear();
      toolBox->removeItem(item);
      delete item;
    }
  }

  AQ_SET_MNGLOADER

  QStringList listAreas = mngLoader_->listIdAreas(), listModules;
  QString descripArea, descripModule;
  QToolBar *newAreaBar;
  FLWidgetAction *newModuleAction;
  QWidget *w;
  int c = 65;


  for (QStringList::Iterator itA = listAreas.begin(); itA != listAreas.end(); ++itA) {
    descripArea = mngLoader_->idAreaToDescription(*itA);
    newAreaBar = new QToolBar(tr(descripArea), container, toolBox, false, descripArea);
    newAreaBar->setFrameStyle(QFrame::NoFrame);
    newAreaBar->setOrientation(Qt::Vertical);
    newAreaBar->boxLayout()->setSpacing(3);
    toolBox->addItem(newAreaBar, tr(descripArea));

    QActionGroup *ag = new QActionGroup(newAreaBar, descripArea);
    ag->setMenuText(descripArea);
    ag->setUsesDropDown(true);

    listModules = mngLoader_->listIdModules(*itA);
    listModules.sort();
    for (QStringList::Iterator itM = listModules.begin(); itM != listModules.end(); ++itM, ++c) {
      if (QChar(c) == 'Q')
        ++c;
        
#ifdef FL_QUICK_CLIENT
      if (*itM == "sys")
        continue;
#endif
        
    if (*itM == "sys") {

#ifdef QSDEBUGGER  /// Si compilamos el debugger nos aparece este apartado del menu.

  if (FLSettings::readBoolEntry("application/isDebuggerMode"))
                                  {      
	++c;  
               
        descripModule = QString(QChar(c)) + QString::fromLatin1(": ") +
                        tr("Carga Estática desde Disco Duro");
        newModuleAction = new FLWidgetAction(descripModule, descripModule, descripModule,
                                             QKeySequence(QString("Ctrl+Shift+") + QString(QChar(c))),
                                             newAreaBar, *itM);
        newModuleAction->setIconSet(QPixmap::fromMimeSource("image-svg.png"));
        newModuleAction->setIdModule(*itM);
        newModuleAction->addTo(newAreaBar);
        ag->add(newModuleAction);
        connect(newModuleAction, SIGNAL(activated()), this, SLOT(staticLoaderSetup()));

        ++c; 
       descripModule = QString(QChar(c)) + QString::fromLatin1(": ") +
                        tr("Reiniciar Scripts");
        newModuleAction = new FLWidgetAction(descripModule, descripModule, descripModule,
                                             QKeySequence(QString("Ctrl+Shift+") + QString(QChar(c))),
                                             newAreaBar, *itM);
        newModuleAction->setIconSet(QPixmap::fromMimeSource("reload.png"));
        newModuleAction->setIdModule(*itM);
        newModuleAction->addTo(newAreaBar);
        ag->add(newModuleAction);
        connect(newModuleAction, SIGNAL(activated()), this, SLOT(reinit()));
        
        ++c;
        descripModule = QString(QChar(c)) + QString::fromLatin1(": ") +
                        tr("Mostrar Consola de mensajes");
        newModuleAction = new FLWidgetAction(descripModule, descripModule, descripModule,
                                             QKeySequence(QString("Ctrl+Shift+") + QString(QChar(c))),
                                             newAreaBar, "shConsoleAction");
        newModuleAction->setIconSet(QPixmap::fromMimeSource("consola.png"));
        newModuleAction->setIdModule(*itM);
        newModuleAction->addTo(newAreaBar);
        ag->add(newModuleAction);
        connect(newModuleAction, SIGNAL(activated()), this, SLOT(showConsole()));


                                  }
#endif

#ifndef QSDEBUGGER

#else
        ++c;
#endif
      }

      descripModule = QString(QChar(c)) + ": " + mngLoader_->idModuleToDescription(*itM);
      newModuleAction = new FLWidgetAction(tr(descripModule),
                                           tr(descripModule),
                                           tr(descripModule),
                                           QKeySequence(QString("Ctrl+Shift+") + QString(QChar(c))),
                                           newAreaBar,
                                           (*itM));
      newModuleAction->setIconSet(mngLoader_->iconModule(*itM));
      newModuleAction->setIdModule(*itM);
      newModuleAction->addTo(newAreaBar);
      ag->add(newModuleAction);
      connect(newModuleAction, SIGNAL(activated()), this, SLOT(activateModule()));
    }

    w = new FLWidget(newAreaBar);
    w->setBackgroundMode(Qt::NoBackground);
    newAreaBar->setStretchableWidget(w);
    ag->addTo(modulesMenu);
  }

  AQ_UNSET_MNGLOADER

  QToolBar *configToolBar = new QToolBar(tr("Configuracion"), container, toolBox, false, "Configuracion");
  configToolBar->setFrameStyle(QFrame::NoFrame);
  configToolBar->setOrientation(Qt::Vertical);
  configToolBar->boxLayout()->setSpacing(3);
  toolBox->addItem(configToolBar, tr("Configuración"));

  FLWidgetAction *fontAction = new FLWidgetAction(tr("Fuente"), tr("Fuente"), tr("Fuente"), QKeySequence(), configToolBar, "fuente");
  fontAction->setIconSet(QPixmap::fromMimeSource("font.png"));
  connect(fontAction, SIGNAL(activated()), this, SLOT(chooseFont()));
  fontAction->addTo(configToolBar);

  FLWidgetAction *styleAction = new FLWidgetAction(tr("Estilo"), tr("Estilo"), tr("Estilo"), QKeySequence(), configToolBar, "estilo");
  styleAction->setIconSet(QPixmap::fromMimeSource("estilo.png"));
  styleAction->addTo(configToolBar);
  connect(styleAction, SIGNAL(activated()), this, SLOT(showStyles()));

  w = new FLWidget(configToolBar);
  w->setBackgroundMode(Qt::NoBackground);
  configToolBar->setStretchableWidget(w);

  QToolBar *helpToolBar = new QToolBar(tr("Ayuda"), container, toolBox, false, "Ayuda");
  helpToolBar->setFrameStyle(QFrame::NoFrame);
  helpToolBar->setOrientation(Qt::Vertical);
  helpToolBar->boxLayout()->setSpacing(3);
  toolBox->addItem(helpToolBar, tr("Ayuda"));

  FLWidgetAction *helpIndexAction = new FLWidgetAction(tr("Ayuda"), tr("Índice"), tr("Indice"), QKeySequence(), helpToolBar, "help");
  helpIndexAction->setIconSet(QPixmap::fromMimeSource("help_index.png"));
  connect(helpIndexAction, SIGNAL(activated()), this, SLOT(helpIndex()));
  helpIndexAction->addTo(helpToolBar);

  FLWidgetAction *aboutAction = new FLWidgetAction(tr("Ayuda"), tr("Acerca de Eneboo"), tr("&Acerca de Eneboo"), QKeySequence(), helpToolBar, "acercaeneboo");
  aboutAction->setIconSet(QPixmap::fromMimeSource("about.png"));
  connect(aboutAction, SIGNAL(activated()), this, SLOT(aboutAbanQ()));
  aboutAction->addTo(helpToolBar);
  
  FLWidgetAction *urlAbanqAction = new FLWidgetAction(tr("Ayuda"), tr("Visita Eneboo.org"), tr("&Visita Eneboo.org"), QKeySequence(), helpToolBar, "visitaeneboo");
  urlAbanqAction->setIconSet(QPixmap::fromMimeSource("about.png"));
  connect(urlAbanqAction, SIGNAL(activated()), this, SLOT(urlEneboo()));
  urlAbanqAction->addTo(helpToolBar);

  FLWidgetAction *aboutQt = new FLWidgetAction(tr("Ayuda"), tr("Acerca de Qt"), tr("&Acerca Qt"), QKeySequence(), helpToolBar, "acercaqt");
  aboutQt->setIconSet(QPixmap::fromMimeSource("aboutqt.png"));
  connect(aboutQt, SIGNAL(activated()), this, SLOT(aboutQt()));
  aboutQt->addTo(helpToolBar);

  w = new FLWidget(helpToolBar);
  w->setBackgroundMode(Qt::NoBackground);
  helpToolBar->setStretchableWidget(w);

  if (acl_)
    acl_->process(container);
}

void FLApplication::initActions()
{
  if (::qt_cast<QMainWindow *>(mainWidget_) && pWorkspace) {
    connect(windowCascadeAction, SIGNAL(activated()), pWorkspace, SLOT(cascade()));
    connect(windowTileAction, SIGNAL(activated()), pWorkspace, SLOT(tile()));
    connect(windowCloseAction, SIGNAL(activated()), pWorkspace, SLOT(closeActiveWindow()));
  }
}

void FLApplication::initMenuBar()
{
  connect(windowMenu, SIGNAL(aboutToShow()), this, SLOT(windowMenuAboutToShow()));
}

void FLApplication::initToolBar()
{
  QMainWindow *mw = ::qt_cast<QMainWindow *>(mainWidget_);
  if (!mw)
    return;

  QToolBar *tb = ::qt_cast<QToolBar *>(mw->child("toolBar"));
  if (!tb)
    return;

  tb->setMovingEnabled(false);
  if (tb->child("automatic what's this? button"))
    return;
  tb->addSeparator();
  QWhatsThis::whatsThisButton(tb);

  if (!toggleBars) {
    QAction *a, *b;
    toggleBars = new QPopupMenu(container, "toggleBars");
    toggleBars->setCheckable(true);
    QActionGroup *ag = new QActionGroup(container, "agToggleBars", false);
    a = new QAction(tr("Barra de Herramientas"), QKeySequence(), ag, "Herramientas");
    a->setToggleAction(true);
    a->setOn(true);
    connect(a, SIGNAL(toggled(bool)), this, SLOT(toggleToolBar(bool)));
    b = new QAction(tr("Barra de Estado"), QKeySequence(), ag, "Estado");
    b->setToggleAction(true);
    b->setOn(true);
    connect(b, SIGNAL(toggled(bool)), this, SLOT(toggleStatusBar(bool)));
    ag->addTo(toggleBars);
  }

  mw->menuBar()->insertItem(tr("&Ver"), toggleBars);
  mw->menuBar()->insertItem(tr("&Módulos"), modulesMenu);
}

void FLApplication::initStatusBar()
{
  QMainWindow *mw = ::qt_cast<QMainWindow *>(mainWidget_);
  if (!mw)
    return;
  mw->statusBar()->message(tr("Listo."));
  mw->statusBar()->setSizeGripEnabled(false);

  QLabel *conexion = new QLabel(mw->statusBar());
  conexion->setText(db()->user() + "@" + db()->database());
  mw->statusBar()->addWidget(conexion, 0, true);
}

void FLApplication::initView()
{
  QMainWindow *mw = ::qt_cast<QMainWindow *>(mainWidget_);
  if (!mw)
    return;

  QWidget *view_back = mw->centralWidget();
  if (!view_back) {
    view_back = new QVBox(mainWidget_);
    static_cast<QVBox *>(view_back)->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
    pWorkspace = new FLWorkspace(view_back, db()->managerModules()->activeIdModule());
    pWorkspace->setBackgroundMode(Qt::NoBackground);
    pWorkspace->setScrollBarsEnabled(true);
    mw->setCentralWidget(view_back);
  }
}

void FLApplication::initStyles()
{
  style = new QPopupMenu(container, "styles");
  style->setCheckable(true);

  QActionGroup *ag = new QActionGroup(container, 0);

  ag->setExclusive(true);
  QSignalMapper *styleMapper = new QSignalMapper(container);
  connect(styleMapper, SIGNAL(mapped(const QString &)), this, SLOT(makeStyle(const QString &)));

  QStringList list = QStyleFactory::keys();
  list.sort();
  QDict < int >stylesDict(17, false);

  for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) {
    QString styleStr = *it;
    QString styleAccel = styleStr;

    if (stylesDict[ styleAccel.left(1)]) {
      for (uint i = 0; i < styleAccel.length(); ++i) {
        if (!stylesDict[ styleAccel.mid(i, 1)]) {
          stylesDict.insert(styleAccel.mid(i, 1), (const int *) 1);
          styleAccel = styleAccel.insert(i, '&');
          break;
        }
      }
    } else {
      stylesDict.insert(styleAccel.left(1), (const int *) 1);
      styleAccel = "&" + styleAccel;
    }
    QAction *a = new QAction(styleStr, QIconSet(), styleAccel, 0, ag, 0,
                             ag->isExclusive());
    if (styleStr == FLSettings::readEntry("style", "QtCurve"))
      a->setOn(true);
    connect(a, SIGNAL(activated()), styleMapper, SLOT(map()));
    styleMapper->setMapping(a, a->text());
  }
  ag->addTo(style);
}

bool FLApplication::queryExit()
{
  if (notExit_)
    return false;
  if (!db()->interactiveGUI())
    return true;
  return (QMessageBox::Yes == QMessageBox::question(
            aqApp->mainWidget(), tr("Salir..."),
            tr("¿ Quiere salir de la aplicación ?"),
            QMessageBox::Yes,
            QMessageBox::No |
            QMessageBox::Default |
            QMessageBox::Escape)
         );
}

void FLApplication::generalExit(bool askExit)
{
  if (wb_)
    wb_->close();

  bool doExit = true;
  if (askExit)
    doExit = queryExit();
  if (doExit) {
    destroying_ = true;
    if (tedOutput_)
      tedOutput_->close();
    if (!formAlone_) {
      writeState();
      writeStateModule();
    }
    if (!db()->driverName().isEmpty())
      FLVar::clean();
    db()->managerModules()->finish();
    db()->manager()->finish();
    QTimer::singleShot(0, this, SLOT(quit()));
  }
}

QString FLApplication::getTabWidgetPages(const QString &wN, const QString &n)
{
  QString actionName;
  const FLAction *a;
  QWidget *w;
  if (wN.left(10) == "formRecord") {
    actionName = wN.mid(10, wN.length());
    a = db()->manager()->action(actionName);
    w = db()->managerModules()->createFormRecord(a, 0, 0, 0);
  } else if (wN.left(10) == "formSearch") {
    actionName = wN.mid(10, wN.length());
    a = db()->manager()->action(actionName);
    w = db()->managerModules()->createForm(a, 0, 0, 0);
  } else {
    actionName = wN.mid(4, wN.length());
    a = db()->manager()->action(actionName);
    w = db()->managerModules()->createForm(a, 0, 0, 0);
  }

  if (!w)
    return "";

  QTabWidget *tabW = static_cast<QTabWidget * >(w->child(n));
  if (!tabW)
    return "";

  QString s;
  QWidget *page = 0;
  for (int i = 0; i < tabW->count(); ++i) {
    page = tabW->page(i);
    s += QString(page->name()) + "/" + QString(page->caption()) + "*";
  }
  return s;
}

QString FLApplication::getWidgetList(const QString &wN, const QString &c)
{
  QString actionName;
  const FLAction *a;
  QWidget *w;
  if (wN.left(10) == "formRecord") {
    actionName = wN.mid(10, wN.length());
    a = db()->manager()->action(actionName);
    w = db()->managerModules()->createFormRecord(a, 0, 0, 0);
  } else if (wN.left(10) == "formSearch") {
    actionName = wN.mid(10, wN.length());
    a = db()->manager()->action(actionName);
    w = db()->managerModules()->createForm(a, 0, 0, 0);
  } else {
    actionName = wN.mid(4, wN.length());
    a = db()->manager()->action(actionName);
    w = db()->managerModules()->createForm(a, 0, 0, 0);
  }

  if (!w)
    return "";

  const QObjectList *oL = w->queryList(c);
  QObjectListIt it(*oL);
  QObject *o;
  QString s;
  QString name;
  QString fieldTable;

  while ((o = it.current()) != 0) {
    ++it;
    name = o->name();
    if (c == "FLFieldDB") {
      fieldTable = static_cast<FLFieldDB *>(o)->tableName();
      if (!fieldTable.isEmpty() && fieldTable != a->table())
        continue;
      s += name + "/" + static_cast<FLFieldDB *>(o)->fieldName() + "*";
    } else if (c == "FLTableDB") {
      s += name + "/" + static_cast<FLTableDB *>(o)->tableName() + "*";
    } else if (c == "QButton" || c == "Button") {
      if (name == "pushButtonDB" || name == "pbAux" || name == "qt_left_btn" || name == "qt_right_btn")
        continue;
      s += name + "/" + static_cast<QButton *>(o)->text() + "*";
    } else {
      if (name == "textLabelDB" || name == "componentDB" || name == "tab pages" ||
          name == "editor" || name == "FrameFind" || name == "TextLabelSearch" ||
          name == "TextLabelIn" || name == "lineEditSearch" || name == "in-combo" ||
          name == "voidTable")
        continue;
      if (o->isA("QGroupBox"))
        s += name + "/" + ((QGroupBox *) o)->title() + "*";
      else
        s += name + "/ " + "*";
    }
  }
  delete o;
  delete oL;
  delete w;
  return s;
}


void FLApplication::toggleToolBar(bool toggle)
{
  QMainWindow *mw = ::qt_cast<QMainWindow *>(mainWidget_);
  if (!mw)
    return;

  QToolBar *tb = ::qt_cast<QToolBar *>(mw->child("toolBar"));
  if (!tb)
    return;

  if (toggle)
    tb->show();
  else
    tb->hide();
}

void FLApplication::toggleStatusBar(bool toggle)
{
  QMainWindow *mw = ::qt_cast<QMainWindow *>(mainWidget_);
  if (!mw)
    return;

  if (toggle)
    mw->statusBar()->show();
  else
    mw->statusBar()->hide();
}

void FLApplication::aboutAbanQ()
{
  FLAbout *aboutAbanQ = new FLAbout(AQ_VERSION, 0);
  aboutAbanQ->exec();
  aboutAbanQ->deleteLater();
}

void FLApplication::helpIndex()
{
  aqApp->call("sys.openUrl", QSArgumentList("http://www.eneboo.com/pub/contrib/doc/standard/"), 0);
}

void FLApplication::urlEneboo()
{
  aqApp->call("sys.openUrl", QSArgumentList("http://www.eneboo.org/"), 0);
}

void FLApplication::statusHelpMsg(const QString &text)
{
  QMainWindow *mw = ::qt_cast<QMainWindow *>(mainWidget_);
  if (!mw)
    return;
  mw->statusBar()->message(text, 2000);
}

void FLApplication::windowMenuAboutToShow()
{
  if (!pWorkspace)
    return;

  windowMenu->clear();
  windowCascadeAction->addTo(windowMenu);
  windowTileAction->addTo(windowMenu);
  windowCloseAction->addTo(windowMenu);

  if (pWorkspace->windowList().isEmpty()) {
    windowCascadeAction->setEnabled(false);
    windowTileAction->setEnabled(false);
    windowCloseAction->setEnabled(false);
  } else {
    windowCascadeAction->setEnabled(true);
    windowTileAction->setEnabled(true);
    windowCloseAction->setEnabled(true);
    windowMenu->insertSeparator();
  }

  QWidgetList windows(pWorkspace->windowList());
  for (int i = 0; i < int(windows.count()); ++i) {
    int id = windowMenu->insertItem(windows.at(i)->caption(), this, SLOT(windowMenuActivated(int)));
    windowMenu->setItemParameter(id, i);
    windowMenu->setItemChecked(id, pWorkspace->activeWindow() == windows.at(i));
  }
}

void FLApplication::windowMenuActivated(int id)
{
  if (!pWorkspace)
    return;
  QWidget *w = pWorkspace->windowList().at(id);
  if (w)
    w->setFocus();
}

bool FLApplication::existsFormInMDI(const QString &id)
{
  if (id.isEmpty() || !pWorkspace)
    return false;
  if (!pWorkspace->windowList().isEmpty()) {
    QWidgetList windows = pWorkspace->windowList();
    for (int i = 0; i < int(windows.count()); ++i) {
      if (static_cast<FLFormDB *>(windows.at(i))->idMDI() == id) {
        windows.at(i)->showNormal();
        windows.at(i)->setFocus();
        return true;
      }
    }
  }
  return false;
}

void FLApplication::openMasterForm(const QString &n, const QPixmap & /*p*/)
{
  if (existsFormInMDI(n))
    return;

  bool showMaximized = false;
  if (pWorkspace && pWorkspace->activeWindow())
    showMaximized = pWorkspace->activeWindow()->isMaximized();
  FLFormDB *f = new FLFormDB(n, pWorkspace);

  f->setMainWidget();
  if (f->mainWidget()) {
    if ((pWorkspace && pWorkspace->windowList().isEmpty()) || showMaximized)
      f->showMaximized();
    else
      f->show();
  } else
    f->close();
}

void FLApplication::openDefaultForm()
{
  QObject *s = const_cast<QObject *>(sender());
  if (s && !s->inherits("QAction")) {
#ifdef FL_DEBUG
    qWarning(tr("FLApplication : El objeto que envia señales para abrir formularios debe ser de la clase QAction"));
#endif
    return;
  }
  QPixmap icon = static_cast<QAction *>(s)->iconSet().pixmap();
  openMasterForm(s->name(), icon);
}

void FLApplication::execMainScript(const QString &n)
{
  const FLAction *a = db()->manager()->action(n);
  if (!a) {
#ifdef FL_DEBUG
    qWarning(tr("FLApplication : No existe la acción %1").arg(n));
#endif

    return;
  }
  call("main", QSArgumentList(), "form" + a->name());
}

void FLApplication::execDefaultScript()
{
  QObject *s = const_cast<QObject *>(sender());
  if (s && !s->inherits("QAction")) {
#ifdef FL_DEBUG
    qWarning(tr("FLApplication : El objeto que envia señales para abrir scripts debe ser de la clase QAction"));
#endif
    return;
  }
  execMainScript(s->name());
}

void FLApplication::windowClose()
{
  if (!pWorkspace)
    return;
  pWorkspace->closeActiveWindow();
}

void FLApplication::writeState()
{
  FLSettings::writeEntry("MultiLang/Enabled", multiLangEnabled_);
  FLSettings::writeEntry("MultiLang/LangId", multiLangId_);

  if (container) {
    QStringList windowsOpened;
    QWidgetList *list = topLevelWidgets();
    QWidgetListIt it(*list);
    QWidget *w;
    if (initializing_) {
      while ((w = it.current()) != 0) {
        ++it;
        w->removeEventFilter(this);
        if (dictMainWidgets->find(w->name()) != 0) {
          if (w != container) {
            if (!w->isHidden())
              windowsOpened << w->name();
            w->hide();
          } else
            w->setDisabled(true);
        }
      }
    } else {
      while ((w = it.current()) != 0) {
        ++it;
        if (w != container && !w->isHidden() && dictMainWidgets->find(w->name()) != 0)
          windowsOpened << w->name();
      }
    }
    delete list;
    FLSettings::writeEntry("windowsOpened/Main", windowsOpened);

    FLSettings::writeEntry("Geometry/MainwindowMaximized", container->isMaximized());
    if (!container->isMaximized()) {
      FLSettings::writeEntry("Geometry/MainwindowX", container->x());
      FLSettings::writeEntry("Geometry/MainwindowY", container->y());
      FLSettings::writeEntry("Geometry/MainwindowWidth", container->width());
      FLSettings::writeEntry("Geometry/MainwindowHeight", container->height());
    }
  }

  for (QMap<QString, QRect>::const_iterator it = mapGeometryForms_.begin(); it != mapGeometryForms_.end(); ++it) {
    QRect r(*it);
    QString k("Geometry/" + it.key() + "/");

    FLSettings::writeEntry(k + "X", r.x());
    FLSettings::writeEntry(k + "Y", r.y());
    FLSettings::writeEntry(k + "Width", r.width());
    FLSettings::writeEntry(k + "Height", r.height());
  }
}

void FLApplication::writeStateModule()
{
  QString idM(db()->managerModules()->activeIdModule());
  if (!mainWidget_ || idM.isEmpty() || mainWidget_->name() != idM)
    return;

  if (::qt_cast<QMainWindow *>(mainWidget_) &&
      pWorkspace && !pWorkspace->windowList().isEmpty()) {
    QStringList windowsOpened;
    QWidgetList windows(pWorkspace->windowList());
    for (int i = 0; i < windows.count(); ++i)
      windowsOpened << static_cast<FLFormDB *>(windows.at(i))->idMDI();
    FLSettings::writeEntry("windowsOpened/" + idM, windowsOpened);
  } else
    FLSettings::writeEntry("windowsOpened/" + idM, QStringList());

  QString k("Geometry/" + idM);
  FLSettings::writeEntry(k + "/Maximized", mainWidget_->isMaximized());
  FLSettings::writeEntry(k + "/X", mainWidget_->x());
  FLSettings::writeEntry(k + "/Y", mainWidget_->y());
  FLSettings::writeEntry(k + "/Width", mainWidget_->width());
  FLSettings::writeEntry(k + "/Height", mainWidget_->height());
}

void FLApplication::readState()
{
  if (container) {
    QRect r(container->pos(), container->size());

    multiLangEnabled_ = FLSettings::readBoolEntry("MultiLang/Enabled", false);
    multiLangId_ = FLSettings::readEntry("MultiLang/LangId", QString(QTextCodec::locale()).left(2)).upper();

    if (!FLSettings::readBoolEntry("Geometry/MainwindowMaximized", false)) {
      r.setX(FLSettings::readNumEntry("Geometry/MainwindowX", r.x()));
      r.setY(FLSettings::readNumEntry("Geometry/MainwindowY", r.y()));
      r.setWidth(FLSettings::readNumEntry("Geometry/MainwindowWidth", r.width()));
      r.setHeight(FLSettings::readNumEntry("Geometry/MainwindowHeight", r.height()));

      QRect desk = QApplication::desktop()->availableGeometry(container);
      QRect inter = desk.intersect(r);
      container->resize(r.size());
      if (inter.width() * inter.height() > (r.width() * r.height() / 20))
        container->move(r.topLeft());
    } else
      container->resize(QApplication::desktop()->availableGeometry(container).size());

    QString activeIdModule(db()->managerModules()->activeIdModule());

#if defined (FL_QUICK_CLIENT) || !defined(QSDEBUGGER)
    if (activeIdModule == "sys")
      activeIdModule = QString::null;
#endif

    QStringList windowsOpened(FLSettings::readListEntry("windowsOpened/Main"));
    if (!windowsOpened.isEmpty()) {
      QStringList::Iterator it(windowsOpened.end());
      do {
        --it;
#if defined (FL_QUICK_CLIENT) || !defined(QSDEBUGGER)
        if ((*it) == "sys")
          continue;
#endif
        QWidget *w = 0;
        if ((*it) != activeIdModule && db()->managerModules()->listAllIdModules().contains(*it)) {
          w = dictMainWidgets->find(*it);
          if (!w) {
            QAction *act = ::qt_cast<QAction *>(container->child((*it), "QAction"));
            if (!act || !act->isVisible())
              continue;
            w = db()->managerModules()->createUI(*it + ".ui", this, 0, *it);
            dictMainWidgets->replace(*it, w);
            setName(*it);
            if (acl_)
              acl_->process(w);
            setMainWidget(w);
            call("init", QSArgumentList(), *it);
            db()->managerModules()->setActiveIdModule(*it);
            setMainWidget(w);
            initMainWidget();
          }
        }
      } while (it != windowsOpened.begin());
    }

    QDictIterator<QWidget> itD(*dictMainWidgets);
    QWidget *w;
    while ((w = itD.current()) != 0) {
      ++itD;
      if (w->name() != activeIdModule) {
        w->installEventFilter(this);
        w->show();
        w->setFont(font());
        QMainWindow *mw = ::qt_cast<QMainWindow *>(w);
        if (!mw)
          continue;
        QWidget *view_back = mw->centralWidget();
        if (view_back) {
          pWorkspace = static_cast<FLWorkspace *>(view_back->child(mw->name(), "QWorkspace"));
          view_back->show();
        }
      }
    }

    if (!activeIdModule.isEmpty()) {
      container->show();
      container->setFont(font());
    }
    activateModule(activeIdModule);
  }
}

void FLApplication::readStateModule()
{
  QString idM(db()->managerModules()->activeIdModule());
#if defined (FL_QUICK_CLIENT) || !defined(QSDEBUGGER)
  if (idM == "sys")
    return;
#endif
  if (!mainWidget_ || idM.isEmpty() || mainWidget_->name() != idM)
    return;

  if (::qt_cast<QMainWindow *>(mainWidget_)) {
    QStringList windowsOpened(FLSettings::readListEntry("windowsOpened/" + idM));
    if (!windowsOpened.isEmpty()) {
      QAction *act = 0;
      for (QStringList::Iterator it = windowsOpened.begin(); it != windowsOpened.end(); ++it) {
        act = ::qt_cast<QAction *>(mainWidget_->child((*it), "QAction"));
        if (act && act->isVisible())
          openMasterForm((*it), act->iconSet().pixmap());
      }
    }
  }

  QRect r(mainWidget_->pos(), mainWidget_->size());
  QString k("Geometry/" + idM);
  if (!FLSettings::readBoolEntry(k + "/Maximized", false)) {
    r.setX(FLSettings::readNumEntry(k + "/X", r.x()));
    r.setY(FLSettings::readNumEntry(k + "/Y", r.y()));
    r.setWidth(FLSettings::readNumEntry(k + "/Width", r.width()));
    r.setHeight(FLSettings::readNumEntry(k + "/Height", r.height()));
    QRect desk = QApplication::desktop()->availableGeometry(mainWidget_);
    QRect inter = desk.intersect(r);
    mainWidget_->resize(r.size());
    if (inter.width() * inter.height() > (r.width() * r.height() / 20))
      mainWidget_->move(r.topLeft());
  } else
    mainWidget_->resize(QApplication::desktop()->availableGeometry(mainWidget_).size());
}

void FLApplication::loadScripts()
{
  AQ_SET_MNGLOADER

  setOverrideCursor(Qt::WaitCursor);
  QStringList listModules(mngLoader_->listAllIdModules());
  for (QStringList::Iterator it = listModules.begin(); it != listModules.end(); ++it)
    loadScriptsFromModule(*it);
  restoreOverrideCursor();

  AQ_UNSET_MNGLOADER
}

void FLApplication::loadTranslations()
{
  if (closingDown())
    return;

  AQ_SET_MNGLOADER

  QValueList<QTranslator *> translatorsCopy;
  if (translators && !translators->empty()) {
    translatorsCopy = *translators;
    QValueListConstIterator<QTranslator *> it(translatorsCopy.begin());
    while (it != translatorsCopy.end()) {
      removeTranslator(*it);
      ++it;
    }
  }

  QString lang(QString(QTextCodec::locale()).left(2));
  QStringList listModules = mngLoader_->listAllIdModules();
  for (QStringList::Iterator it = listModules.begin(); it != listModules.end(); ++it)
    loadTranslationFromModule(*it, lang);

  if (!translatorsCopy.empty()) {
    QValueListConstIterator<QTranslator *> it(translatorsCopy.begin());
    FLTranslator *item;
    while (it != translatorsCopy.end()) {
      item = ::qt_cast<FLTranslator *> (*it);
      if (item) {
        if (item->sysTrans_)
          installTranslator(item);
        else
          item->deleteLater();
      }
      ++it;
    }
  }

  AQ_UNSET_MNGLOADER
}

QString FLApplication::trMulti(const QString &s, const QString &l)
{
  bool backMultiEnabled = multiLangEnabled_;
  QString ret(translate(l.upper() + QString::fromLatin1("_MULTILANG"), s));
  multiLangEnabled_ = backMultiEnabled;
  return ret;
}

QString FLApplication::translate(const char *context, const char *sourceText,
                                 const char *comment, Encoding encoding) const
{
  if (!sourceText)
    return QString::null;

  if (!multiLangEnabled_ && sysContexts_.find(context) != 0) {
    QString result(sysTr_->findMessage(context, sourceText, comment).translation());
    if (!result.isNull())
      return result;
  } else if (translators) {
    QValueList<QTranslator *>::iterator it;
    FLTranslator *mf;
    QString result;
    for (it = translators->begin(); it != translators->end(); ++it) {
      mf = ::qt_cast<FLTranslator *> (*it);
      if (mf) {
        if (multiLangEnabled_) {
          if (mf->multiLang_)
            result = mf->findMessage(multiLangId_ + QString::fromLatin1("_MULTILANG"),
                                     sourceText, comment).translation();
          else
            continue;
        } else if (!mf->multiLang_)
          result = mf->findMessage(context, sourceText, comment).translation();
        else
          continue;
      } else
        result = (*it)->findMessage(context, sourceText, comment).translation();
      if (!result.isNull())
        return result;
    }
  }

#ifndef QT_NO_TEXTCODEC
  if (encoding == UnicodeUTF8)
    return QString::fromUtf8(sourceText);
  else if (QTextCodec::codecForTr() != 0)
    return QTextCodec::codecForTr()->toUnicode(sourceText);
  else
#endif

    return QString::fromLatin1(sourceText);
}

void FLApplication::setMultiLang(bool enable, const QString &langid)
{
  multiLangEnabled_ = enable;
  if (enable && !langid.isEmpty())
    multiLangId_ = langid.upper();
}

QTranslator *FLApplication::createSysTranslator(const QString &lang, bool loadDefault)
{
  QString fileTs(QString::fromLatin1("sys.") + lang + QString::fromLatin1(".ts"));
  QString key(QString::fromLatin1("sys") + lang + QString::fromLatin1("ts"));
  bool ok = true;

  if (AQ_DISKCACHE_FILEPATH(key).isEmpty()) {
    QFile fi(AQ_DATA + QString::fromLatin1("/translations/") + fileTs);
    ok = false;
    if (fi.open(IO_ReadOnly)) {
      QTextStream t(&fi);
      ok = AQ_DISKCACHE_INS(key, t.read());
    }
  }

  if (ok) {
    bool multiLang = (lang == "multilang");
    FLTranslator *tor = new FLTranslator(0, QString::fromLatin1("sys_") + lang,
                                         multiLang, true);

    if (tor->loadTsContent(key)) {
      if (!multiLang) {
        FLTranslations tmpTr;
        MetaTranslator tmpTor;

        tmpTr.loadTsFile(tmpTor, AQ_DATA + QString::fromLatin1("/translations/") +
                         fileTs, false);
        QValueList<MetaTranslatorMessage> list(tmpTor.messages());
        QValueList<MetaTranslatorMessage>::const_iterator it(list.begin());

        const char *itCtx;
        while (it != list.end()) {
          itCtx = (*it).context();
          if (qstrcmp(itCtx, "MetaData") == 0 ||
              qstrcmp(itCtx, "Queries") == 0 ||
              qstrcmp(itCtx, "scripts") == 0) {
            ++it;
            continue;
          }
          if (sysContexts_.find(itCtx) == 0)
            sysContexts_.insert(itCtx, &multiLangEnabled_);
          ++it;
        }

        sysTr_ = tor;
      }
      return tor;
    }
  }

  return (loadDefault ? createSysTranslator("es") : 0);
}

QTranslator *FLApplication::createModTranslator(const QString &idM, const QString &lang,
                                                bool loadDefault) const
{
  QString fileTs(idM + "." + lang + ".ts");
  QString key(mngLoader_->shaOfFile(fileTs));
  bool ok = !key.isEmpty();

  if (ok && AQ_DISKCACHE_FILEPATH(key).isEmpty())
    ok = AQ_DISKCACHE_INS(key, mngLoader_->content(fileTs));

  if (ok) {
    FLTranslator *tor = new FLTranslator(0, idM + QString::fromLatin1("_") + lang,
                                         lang == "multilang");
    if (tor->loadTsContent(key))
      return tor;
  }

  return (loadDefault ? createModTranslator(idM, "es") : 0);
}

void FLApplication::loadTranslationFromModule(const QString &idM, const QString &lang)
{
  installTranslator(createModTranslator(idM, lang, true));
  installTranslator(createModTranslator(idM, "multilang"));
}

void FLApplication::loadScriptsFromModule(const QString &idM)
{
  QDomDocument doc("scripts");

  QString actionsXml(mngLoader_->contentCached(idM + QString::fromLatin1(".xml")));
  if (idM == "sys") {
    QString actionsXmlPlus(mngLoader_->contentCached("plus_sys.xml"));
    if (!actionsXmlPlus.isEmpty())
      actionsXml.replace("</ACTIONS>", actionsXmlPlus);
  }

  if (!FLUtil::domDocumentSetContent(doc, actionsXml)) {
#ifdef FL_DEBUG
    qWarning("FLApplication : " +
             QApplication::tr("Error al cargar las acciones del módulo %1").arg(idM));
#endif
    return;
  }

  QString sufMn("::Main");
  QString extqs(".qs");
  QString stream(mngLoader_->contentCode(idM + extqs));
  if (idM == "sys") {
    QString streamPlus(mngLoader_->contentCode("plus_sys.qs"));
    if (!streamPlus.isEmpty())
      stream += streamPlus;
  }

  FLApplicationInterface *ap = static_cast<FLApplicationInterface *>(project_->object(idM));
  if (!ap) {
    ap = new FLApplicationInterface(this);
    ap->setName(idM);
    project_->addObject(ap);
    QSScript *scr = project_->createScript(ap, stream);
    scr->setBaseFileName(idM + extqs + sufMn);
  } else {
    QSScript *scr = project_->script(ap);
    if (scr) {
      scr->setCode(stream);
    } else {
      scr = project_->createScript(ap, stream);
      scr->setBaseFileName(idM + extqs + sufMn);
    }
  }

  QDomNode no(doc.documentElement().firstChild());
  QString scriptForm, scriptFormRecord, name;
  QString preFm("form");
  QString preFs("formSearch");
  QString preFr("formRecord");
  QString sufFm("::Form");
  QString sufFs("::formSearch");
  QString sufFr("::FormRecord");

  int matchs;

  while (!no.isNull()) {
    QDomElement e(no.toElement());
    if (!e.isNull()) {
      if (e.tagName() == "action") {
        QDomNode no2(e.firstChild());
        scriptForm = scriptFormRecord = name = stream = QString::null;
        matchs = 0;

        while (!no2.isNull()) {
          QDomElement e2(no2.toElement());
          if (!e2.isNull()) {
            if (e2.tagName() == "name") {
              name = e2.text();
              no2 = no2.nextSibling();
              if (++matchs == 3)
                break;
              continue;
            }
            if (e2.tagName() == "scriptformrecord") {
              scriptFormRecord = e2.text() + extqs;
              no2 = no2.nextSibling();
              if (++matchs == 3)
                break;
              continue;
            }
            if (e2.tagName() == "scriptform") {
              scriptForm = e2.text() + extqs;
              no2 = no2.nextSibling();
              if (++matchs == 3)
                break;
              continue;
            }
          }
          no2 = no2.nextSibling();
        }

        if (!scriptForm.isEmpty()) {
          FLFormDBInterface *f = static_cast<FLFormDBInterface *>(project_->object(preFm + name));
          if (!f) {
            f = new FLFormDBInterface(0);
            f->setName(preFm + name);
            project_->addObject(f);
            stream = mngLoader_->contentCode(scriptForm);
            QSScript *scr = project_->createScript(f, stream);
            scr->setBaseFileName(scriptForm + sufFm);
            f->setScript(scr);
          } else {
            QSScript *scr = f->script();
            if (!scr) {
              scr = project_->script(f);
              if (scr)
                f->setScript(scr);
              else {
                stream = mngLoader_->contentCode(scriptForm);
                scr = project_->createScript(f, stream);
                scr->setBaseFileName(scriptForm + sufFm);
                f->setScript(scr);
              }
            } else {
              stream = mngLoader_->contentCode(scriptForm);
              if (QString::compare(scr->code(), stream))
                scr->setCode(stream);
            }
          }
          
          FLFormSearchDBInterface *fs = static_cast<FLFormSearchDBInterface *>(project_->object(preFs + name));
          if (!fs) {
            fs = new FLFormSearchDBInterface(0);
            fs->setName(preFs + name);
            project_->addObject(fs);
            if (stream.isEmpty())
              stream = mngLoader_->contentCode(scriptForm);
            QSScript *scr = project_->createScript(fs, stream);
            scr->setBaseFileName(scriptForm + sufFs);
            fs->setScript(scr);
          } else {
            QSScript *scr = fs->script();
            if (!scr) {
              scr = project_->script(fs);
              if (scr)
                fs->setScript(scr);
              else {
                if (stream.isEmpty())
                  stream = mngLoader_->contentCode(scriptForm);
                scr = project_->createScript(fs, stream);
                scr->setBaseFileName(scriptForm + sufFs);
                fs->setScript(scr);
              }
            } else {
              if (stream.isEmpty())
                stream = mngLoader_->contentCode(scriptForm);
              if (QString::compare(scr->code(), stream))
                scr->setCode(stream);
            }
          }
        }

        if (!scriptFormRecord.isEmpty()) {
          FLFormRecordDBInterface *fr = static_cast<FLFormRecordDBInterface *>(project_->object(preFr + name));
          if (!fr) {
            fr = new FLFormRecordDBInterface(0);
            fr->setName(preFr + name);
            project_->addObject(fr);
            stream = mngLoader_->contentCode(scriptFormRecord);
            QSScript *scr = project_->createScript(fr, stream);
            scr->setBaseFileName(scriptFormRecord + sufFr);
            fr->setScript(scr);
          } else {
            QSScript *scr = fr->script();
            if (!scr) {
              scr = project_->script(fr);
              if (scr)
                fr->setScript(scr);
              else {
                stream = mngLoader_->contentCode(scriptFormRecord);
                scr = project_->createScript(fr, stream);
                scr->setBaseFileName(scriptFormRecord + sufFr);
                fr->setScript(scr);
              }
            } else {
              stream = mngLoader_->contentCode(scriptFormRecord);
              if (QString::compare(scr->code(), stream))
                scr->setCode(stream);
            }
          }
        }

        no = no.nextSibling();
        continue;
      }
    }
    no = no.nextSibling();
  }
}

void FLApplication::activateModule(const QString &idM)
{
#if defined (FL_QUICK_CLIENT)
  if (idM == "sys")
    return;
#endif
  writeStateModule();

  QWidget *w = 0;
  if (db()->managerModules()->listAllIdModules().contains(idM)) {
    w = dictMainWidgets ? dictMainWidgets->find(idM) : 0;
    if (!w) {
      w = db()->managerModules()->createUI(idM + QString::fromLatin1(".ui"),
                                           this, 0, idM);
      if (!w)
        return;
      if (dictMainWidgets)
        dictMainWidgets->replace(idM, w);
      setName(idM);
      if (acl_)
        acl_->process(w);
      setMainWidget(w);
      call("init", QSArgumentList(), idM);
      w->removeEventFilter(this);
      db()->managerModules()->setActiveIdModule(idM);
      setMainWidget(w);
      initMainWidget();
      showMainWidget(w);
      w->installEventFilter(this);
      return;
    }
  }

  if (!w)
    db()->managerModules()->setActiveIdModule("");
  else
    db()->managerModules()->setActiveIdModule(idM);
  setMainWidget(w);
  showMainWidget(w);
}

void FLApplication::activateModule()
{
  FLWidgetAction *s = ::qt_cast<FLWidgetAction *>(sender());
  if (!s) {
#ifdef FL_DEBUG
    qWarning(tr("FLApplication : El objeto que envia señales activar módulos debe ser de la clase FLWidgetAction"));
#endif
    return;
  }
  QString shaG(db()->managerModules()->shaGlobal());
  if (shaG == "error")
    return;
  if (db()->managerModules()->shaLocal() != shaG)
    reinit();
  QString idM(s->idModule());
#if defined (FL_QUICK_CLIENT)
  if (idM == "sys")
    return;
#endif
  activateModule(idM);
}

void FLApplication::reinit()
{
  if (initializing_ || destroying_)
    return;

  stopTimerIdle();
  aqAppIdle();
  initializing_ = true;
  writeState();
  writeStateModule();

  pWorkspace = 0;

  QTimer::singleShot(0, this, SLOT(reinitP()));
}

void FLApplication::clearProject()
{
  if (wb_) {
    wb_->close();
    wb_->deleteLater();
    wb_ = 0;
  }

  notifyBeginTransaction_ = false;
  notifyEndTransaction_ = false;
  notifyRollbackTransaction_ = false;

  if (!project_)
    return;

  QSInterpreter *i = project_->interpreter();
  if (i) {
    i->stopExecution();
    i->clear();
  }

  project_->blockSignals(true);
  project_->clearObjects();

  QObjectList probjList(project_->objects());
  QPtrListIterator<QObject> itPrObj(probjList);
  QObject *prObj;
  while ((prObj = itPrObj()) != 0) {
    if (!prObj->aqWasDeleted())
      delete prObj;
  }
  QPtrList<QSScript> prscrList(project_->scripts());
  QPtrListIterator<QSScript> itScrObj(prscrList);
  QSScript *scrObj;
  while ((scrObj = itScrObj()) != 0) {
    if (!scrObj->aqWasDeleted())
      delete scrObj;
  }
  project_->blockSignals(false);
}

void FLApplication::reinitP()
{
  db()->managerModules()->finish();
  db()->manager()->finish();
  setMainWidget(0);
  db()->managerModules()->setActiveIdModule("");

  if (dictMainWidgets) {
    dictMainWidgets->setAutoDelete(true);
    dictMainWidgets->clear();
    dictMainWidgets->setAutoDelete(false);
  }

  clearProject();

  db()->manager()->init();
  db()->managerModules()->init();
  db()->manager()->cleanupMetaData();
  FLDomNodeInterface::cleanupDomNodesCache();

  if (acl_)
    acl_->init();

  loadScripts();
  db()->managerModules()->setShaLocalFromGlobal();

  call("init", QSArgumentList(), "sys");
  initToolBox();
  readState();

  if (container) {
    container->installEventFilter(this);
    container->setDisabled(false);
  }

  callScriptEntryFunction();

  initializing_ = false;
  startTimerIdle();
}

void FLApplication::showDocPage(const QString &url)
{
  aqApp->call("sys.openUrl", QSArgumentList(url), 0);
}

FLWorkspace *FLApplication::workspace() const
{
  return pWorkspace;
}

const QDateTime &FLApplication::timeUser() const
{
  return timeUser_;
}


static QMap<QString, QString> aqCallsCache_;

QSArgument FLApplication::call(const QString &function,
                               const QSArgumentList &arguments,
                               QObject *objectContext) const
{
  QSInterpreter *i = project_->interpreter();
  QString fKey;

  if (!objectContext) {
    fKey = function;

    QMap<QString, QString>::const_iterator it(aqCallsCache_.find(fKey));
    if (it != aqCallsCache_.end())
      return ((*it).isEmpty() ? QSArgument() : i->call(*it, arguments));

    if (!i->hasFunction(function)) {
      QString dot(".");
      QString dotIface(".iface.");
      QStringList sL(QStringList::split('.', function));
      QStringList classes(i->classes(sL[0]));

      QString cls(sL[0]);
      QString fun(sL.last());

      for (QStringList::const_iterator it = classes.begin(); it != classes.end(); ++it) {
        if (i->hasFunction(cls + dot + *it + dot + fun)) {
          QString fn(cls + dotIface + fun);
          aqCallsCache_.insert(fKey, fn);
          return i->call(fn, arguments);
        }
      }
    } else {
      aqCallsCache_.insert(fKey, function);
      return i->call(function, arguments);
    }
  } else {
    QString objName(objectContext->name());
    fKey = objName + function;
    QMap<QString, QString>::const_iterator it(aqCallsCache_.find(fKey));

    if (it != aqCallsCache_.end())
      return ((*it).isEmpty() ? QSArgument() : i->call(*it, arguments, objectContext));

    QString dot(".");

    if (!i->hasFunction(objName + dot + function)) {
      QString iface("iface.");
      QStringList classes(i->classes(objectContext));
      for (QStringList::const_iterator it = classes.begin(); it != classes.end(); ++it) {
        if (i->hasFunction(objName + dot + *it + dot + function)) {
          QString fn(iface + function);
          aqCallsCache_.insert(fKey, fn);
          return i->call(fn, arguments, objectContext);
        }
      }
    } else {
      aqCallsCache_.insert(fKey, function);
      return i->call(function, arguments, objectContext);
    }
  }

  aqCallsCache_.insert(function, QString::null);
  return QSArgument();
}

void FLApplication::setCaptionMainWidget(const QString &text)
{
  if (!text.isEmpty())
    lastTextCaption_ = text;

  if (!mainWidget_) {
    QWidget *mwi = aqApp->mainWidget();
    if (mwi) {
      QString bd(db()->driverNameToDriverAlias(db()->driverName()));
     /* mwi->setCaption(db()->database() +
                      " - [ " + lastTextCaption_ + " ] - [" + bd + ":" +
                      db()->user() + "]");*/
      mwi->setCaption(QString::fromLatin1("Eneboo " AQ_VERSION) + " - " + lastTextCaption_);
    }
    return;
  }

  AQ_SET_MNGLOADER

  QString descripArea(mngLoader_->idAreaToDescription(mngLoader_->activeIdArea()));
  QString descripModule(mngLoader_->idModuleToDescription(mainWidget_->name()));
  mainWidget_->setCaption(lastTextCaption_ + " - " + descripArea + " - " + descripModule);

  AQ_UNSET_MNGLOADER
}


void FLApplication::setNotExit(bool b)
{
  notExit_ = b;
}

void FLApplication::printTextEdit(QTextEdit *editor)
{
  if (!editor)
    return;

#if defined(Q_OS_WIN32)
  QPrinter printer(QPrinter::HighResolution);
#else
  QPrinter printer(QPrinter::ScreenResolution);
#endif
  printer.setFullPage(true);
  if (printer.setup(aqApp->mainWidget())) {
    QPainter p(&printer);
    if (!p.device())
      return;
    QPaintDeviceMetrics metrics(p.device());
    int dpiy = metrics.logicalDpiY();
    int margin = (int)((2 / 2.54) * dpiy);
    QRect view(margin, margin, metrics.width() - 2 * margin, metrics.height() - 2 * margin);
    QFont font(editor->QWidget::font());
    font.setPointSize(10);

    QSimpleRichText richText(editor->text(), font, editor->context(), editor->styleSheet(),
                             editor->mimeSourceFactory(), view.height());
    richText.setWidth(&p, view.width());
    int page = 1;
    do {
      if (aqApp->mainWidget())
        richText.draw(&p, margin, margin, view, aqApp->mainWidget()->colorGroup());
      view.moveBy(0, view.height());
      p.translate(0 , -view.height());
      p.setFont(font);
      p.drawText(view.right() - p.fontMetrics().width(QString::number(page)),
                 view.bottom() + p.fontMetrics().ascent() + 5, QString::number(page));
      if (view.top() - margin >= richText.height())
        break;
      printer.newPage();
      ++page;
    } while (true);
  }
}

void FLApplication::setPrintProgram(const QString &printProgram)
{
  printProgram_ = printProgram;
}

QString FLApplication::printProgram() const
{
  return printProgram_;
}

FLSqlDatabase *FLApplication::db()
{
  return FLSqlConnections::database();
}

bool FLApplication::addSysCode(const QString &code, const QString &scriptEntryFunction)
{
  if (code.isEmpty() || !project_->interpreter()->checkSyntax(code))
    return false;

  QString sha1(FLUtil::sha1(code));
  QSScript *scr = project_->script("sys");
  QString scrCode(scr->code());
  QString addCode = "\n\n// " + sha1 + "\n" + code + "\n";

  if (!scrCode.contains(sha1))
    scrCode += addCode;

  if (!project_->interpreter()->checkSyntax(scrCode))
    return false;

  db()->managerModules()->setContent("plus_sys.qs", "sys", addCode);

  if (!scriptEntryFunction.isEmpty())
    scriptEntryFunction_ = scriptEntryFunction;

  return true;
}

void FLApplication::setScriptEntryFunction(const QString &scriptEntryFunction)
{
  scriptEntryFunction_ = scriptEntryFunction;
}

void FLApplication::setDatabaseLockDetection(bool on, int msecLapsus, int limChecks,
                                             bool showWarn, const QString &msgWarn, const QString &connectionName)
{
  QString connName(connectionName.isEmpty() ? "default" : connectionName);
  QString timerId("TimerDbLock_" + connName);
  FLTimerDbLock *timerDbLock = ::qt_cast<FLTimerDbLock *>(child(timerId, "FLTimerDbLock", false));

  if (timerDbLock) {
    timerDbLock->stop();
    if (on) {
      QString defaultMsgWarn(tr("<p><img source=\"locked.png\" align=\"right\"><b><u>Bloqueo Detectado</u></b><br><br>"
                                "Su transacción actual está bloqueando a otros usuarios que han solicitado "
                                "acceder a datos que acaba de crear o modificar pero que aún no han sido "
                                "aceptados.<br><br>Si le es posible postponer la operación que está realizando se "
                                "recomienda guardar los cambios que ha efectuado aceptando todos los formularios "
                                "y esperar unos segundos antes de continuar."));
      QString moreInfo(tr("<br><br><em><a href=\"sys.statusDbLocksDialog\">Más información</a></em></p>"));

      timerDbLock->dbLocksChecks_ = limChecks;
      timerDbLock->dbLocksLapsus_ = (msecLapsus < 0 ? 0 : msecLapsus);
      timerDbLock->dbLocksShowWarn_ = showWarn;
      timerDbLock->dbLocksMsgWarn_ = (!msgWarn.isEmpty() ? msgWarn : defaultMsgWarn) + moreInfo;
      timerDbLock->dbLocksConn_ = connName;
      if (timerDbLock->dbLocksLapsus_)
        timerDbLock->start(timerDbLock->dbLocksLapsus_);
      else
        checkDatabaseLocks(timerDbLock);
    } else
      timerDbLock->deleteLater();
  } else if (on) {
    QString defaultMsgWarn(tr("<p><img source=\"locked.png\" align=\"right\"><b><u>Bloqueo Detectado</u></b><br><br>"
                              "Su transacción actual está bloqueando a otros usuarios que han solicitado "
                              "acceder a datos que acaba de crear o modificar pero que aún no han sido "
                              "aceptados.<br><br>Si le es posible postponer la operación que está realizando se "
                              "recomienda guardar los cambios que ha efectuado aceptando todos los formularios "
                              "y esperar unos segundos antes de continuar."));
    QString moreInfo(tr("<br><br><em><a href=\"sys.statusDbLocksDialog\">Más información</a></em></p>"));

    timerDbLock = new FLTimerDbLock(this, timerId);
    timerDbLock->dbLocksChecks_ = limChecks;
    timerDbLock->dbLocksLapsus_ = (msecLapsus < 0 ? 0 : msecLapsus);
    timerDbLock->dbLocksShowWarn_ = showWarn;
    timerDbLock->dbLocksMsgWarn_ = (!msgWarn.isEmpty() ? msgWarn : defaultMsgWarn) + moreInfo;
    timerDbLock->dbLocksConn_ = connName;
    connect(timerDbLock, SIGNAL(timeout()), this, SLOT(checkDatabaseLocks()));
    if (timerDbLock->dbLocksLapsus_)
      timerDbLock->start(timerDbLock->dbLocksLapsus_);
    else
      checkDatabaseLocks(timerDbLock);
  }
}

void FLApplication::popupWarn(const QString &msgWarn,
                              const QMap<QString, QSArgumentList> & scriptCalls)
{
  if (!container)
    {
    //return;
    container =  new QMainWindow(QApplication::desktop());
    }
  if (!popupWarn_)
    popupWarn_ = new FLPopupWarn(container);
  popupWarn_->scriptCalls_ = scriptCalls;
  QWhatsThis::display(msgWarn, QApplication::desktop()->mapToGlobal(QPoint(5, 5)), container);
}

void FLApplication::popupWarn(const QString &msgWarn)
{
  if (!container)
    return;
  QWhatsThis::display(msgWarn, QApplication::desktop()->mapToGlobal(QPoint(5, 5)), container);
  processEvents(50);
}

void FLApplication::checkDatabaseLocks(QObject *timer)
{
  FLTimerDbLock *timerDbLock = ::qt_cast<FLTimerDbLock *>(timer ? timer : sender());
  if (timerDbLock) {
    timerDbLock->stop();

    FLSqlDatabase *database = FLSqlConnections::database(timerDbLock->dbLocksConn_);
    bool showed = false;

    if (database && database->canDetectLocks()) {
      QStringList locks(database->detectLocks());
      if (!locks.isEmpty() || timer) {
        if (timerDbLock->dbLocksShowWarn_) {
          showed = true;
          QMap<QString, QSArgumentList> scrCall;
          scrCall["sys.statusDbLocksDialog"] = QSArgumentList(locks);
          popupWarn(timerDbLock->dbLocksMsgWarn_, scrCall);
        }
        emit databaseLockDetected();
      }
    }
    if (timerDbLock->dbLocksChecks_ != 0) {
      if (timerDbLock->dbLocksChecks_ > 0)
        timerDbLock->dbLocksChecks_--;
      if (showed)
        timerDbLock->start(60000);
      else
        timerDbLock->start(timerDbLock->dbLocksLapsus_);
    } else
      timerDbLock->deleteLater();
  }
}

void FLApplication::saveGeometryForm(const QString &name, const QRect &geo)
{
  mapGeometryForms_[ name ] = geo;
}

QRect FLApplication::geometryForm(const QString &name) const
{
  QRect r;

  if (!mapGeometryForms_.contains(name)) {
    QString k("Geometry/" + name + "/");
    QRect rconfig;
    bool ok = false;

    rconfig.setX(FLSettings::readNumEntry(k + "X", 0, &ok));
    if (ok) {
      rconfig.setY(FLSettings::readNumEntry(k + "Y"));
      rconfig.setWidth(FLSettings::readNumEntry(k + "Width"));
      rconfig.setHeight(FLSettings::readNumEntry(k + "Height"));
      r = rconfig;
    }
  } else
    r = mapGeometryForms_[ name ];

  return r;
}


void FLApplication::staticLoaderSetup()
{
  db()->managerModules()->staticLoaderSetup();
}

void FLApplication::loadModules()
{
  call("sys.loadModules", QSArgumentList(), 0);
}

void FLApplication::exportModules()
{
  call("sys.exportModules", QSArgumentList(), 0);
}

void FLApplication::importModules()
{
  call("sys.importModules", QSArgumentList(), 0);
}

void FLApplication::updateAbanQ()
{
  call("sys.updateAbanQ", QSArgumentList(), 0);
}

void FLApplication::dumpDatabase()
{
  call("sys.dumpDatabase", QSArgumentList(), 0);
}

void FLApplication::mrProper()
{
  FLSqlConnections::database()->Mr_Proper();
}

void FLApplication::showConsole()
{
  QMainWindow *mw = ::qt_cast<QMainWindow *>(mainWidget());
  if (mw && !tedOutput_) {
    QDockWindow *dw = new QDockWindow(QDockWindow::InDock, mw, "tedOutputDock");
    tedOutput_ = new FLTextEditOuput(dw);
    dw->setWidget(tedOutput_);
    dw->setCaption(tr("Mensajes de Eneboo"));
    dw->setResizeEnabled(true);
    dw->setCloseMode(QDockWindow::Always);
    dw->setFixedExtentWidth(300);
    mw->setDockEnabled(dw, Qt::DockTop, false);
    mw->setDockEnabled(dw, Qt::DockLeft, false);
    mw->setDockEnabled(dw, Qt::DockRight, false);
    mw->moveDockWindow(dw, Qt::DockBottom);
  }
  if (!tedOutput_)
    tedOutput_ = new FLTextEditOuput;
  if (::qt_cast<QDockWindow *>(tedOutput_->parentWidget()))
    tedOutput_->parentWidget()->show();
  tedOutput_->show();
}
bool FLApplication::consoleShown() const
{
  return (tedOutput_ && tedOutput_->isShown());
}

QWidget *FLApplication::modMainWidget(const QString &idModulo) const
{
  QWidget *w = dictMainWidgets ? dictMainWidgets->find(idModulo) : 0;
  if (!w) {
    QWidgetList *list = QApplication::topLevelWidgets();
    QWidgetListIt it(*list);
    while ((w = it.current())) {
      ++it;
      if (QString::fromLatin1(w->name()) == idModulo)
        break;
    }
    delete list;
  }
  if (!w && aqApp->mainWidget())
    w = static_cast<QWidget *>(aqApp->mainWidget()->child(idModulo, "QWidget"));
  return w;
}

void FLApplication::evaluateProject()
{
  if (project_) {
    project_->commitEditorContents();
    QTimer::singleShot(0, project_, SLOT(evaluate()));
    QTimer::singleShot(0, this, SLOT(callScriptEntryFunction()));
  }
}

void FLApplication::callScriptEntryFunction()
{
  if (!scriptEntryFunction_.isEmpty()) {
    call(scriptEntryFunction_, QSArgumentList(), aqApp);
    scriptEntryFunction_ = QString::null;
  }
}

void FLApplication::emitTransactionBegin(QObject *o)
{
  if (notifyBeginTransaction_)
    emit transactionBegin(o);
}

void FLApplication::emitTransactionEnd(QObject *o)
{
  if (notifyEndTransaction_)
    emit transactionEnd(o);
}

void FLApplication::emitTransactionRollback(QObject *o)
{
  if (notifyRollbackTransaction_)
    emit transactionRollback(o);
}

QString FLApplication::gsExecutable()
{
  if (!gsExecutable_.isEmpty())
    return gsExecutable_;

#if defined(Q_OS_WIN32)
#if defined(AQ_WIN64)
  gsExecutable_ = "gswin64c";
  bool gsOk = false;
  QProcess *procTemp = new QProcess();
  procTemp->addArgument(gsExecutable_);
  procTemp->addArgument("--version");
  gsOk = procTemp->start();
  delete procTemp;
  if (!gsOk)
#endif // AQ_WIN64
    gsExecutable_ = "gswin32c";
#else
  gsExecutable_ = "gs";
#endif // Q_OS_WIN32

  qWarning(tr("Ejecutable Ghostscript: ") + gsExecutable_);
  return gsExecutable_;
}

void FLApplication::evaluatedProject()
{
  notifyBeginTransaction_ = false;
  notifyEndTransaction_ = false;
  notifyRollbackTransaction_ = false;
}

void FLApplication::aqAppIdle()
{
  if (wb_ || !project_ || QApplication::activeModalWidget() || QApplication::activePopupWidget())
    return;
  if (QApplication::eventLoop()->loopLevel() > 1)
    return;
  QSInterpreter *i = project_->interpreter();
  if (!i || i->isRunning())
    return;
  if (aqQSARunning)
    return;
  checkAndFixTransactionLevel("Application::aqAppIdle()");
}

void FLApplication::startTimerIdle()
{
  if (!timerIdle_) {
    timerIdle_ = new QTimer(this);
    connect(timerIdle_, SIGNAL(timeout()), this, SLOT(aqAppIdle()));
  } else
    timerIdle_->stop();
  timerIdle_->start(1000, false);
}

void FLApplication::stopTimerIdle()
{
  if (timerIdle_ && timerIdle_->isActive())
    timerIdle_->stop();
}

bool FLApplication::singleFLLarge()
{
  	if (initSingleFLLarge_ == false)
  		{
  		initSingleFLLarge_ = true;
  		if (FLUtil::sqlSelect("flsettings", "valor", QString::fromLatin1("flkey='FLLargeMode'")) == QString::fromLatin1("true") || FLUtil::sqlSelect("flsettings", "valor", QString::fromLatin1("flkey='FLLargeMode'")) == QString::fromLatin1("1"))
  			{
  			#ifdef FL_DEBUG
  			qWarning("FLLarge: Modo multiples tablas");
  			#endif
  			singleFLLarge_ = false;
  			}
  		else
  			{
  			#ifdef FL_DEBUG
  			qWarning("FLLarge: Modo tabla única");
  			#endif
  			singleFLLarge_ = true;
  			}
  		}
  		
    return singleFLLarge_;
  }

void FLApplication::msgBoxWarning(const QString &text, bool gui)
{
  qWarning(text);
  if (gui && db()->interactiveGUI()) {
    QMessageBox::warning(focusWidget(), tr("Aviso"),
                         text, QMessageBox::Ok, 0, 0);
  }
}

void FLApplication::checkAndFixTransactionLevel(const QString &ctx)
{
  // ###
#ifndef QSDEBUGGER
  return;
#endif
  QDict<FLSqlDatabase> *dictDb = FLSqlConnections::dictDatabases();
  if (!dictDb)
    return;
  bool rollbackDone = false;
  FLSqlDatabase *curDb;
  QDictIterator<FLSqlDatabase> it(*dictDb);
  while ((curDb = it.current()) != 0) {
    ++it;
    if (curDb->transactionLevel() <= 0)
      continue;
    rollbackDone = true;
    if (curDb->lastActiveCursor())
      curDb->lastActiveCursor()->rollbackOpened(-1);
    if (curDb->transactionLevel() <= 0)
      continue;
    FLSqlCursor caux;
    caux.rollback();
  }
  if (!rollbackDone)
    return;
  QString msg(
    tr("Se han detectado transacciones abiertas en estado inconsistente.\n"
       "Esto puede suceder por un error en la conexión o en la ejecución\n"
       "de algún proceso de la aplicación.\n"
       "Para mantener la consistencia de los datos se han deshecho las\n"
       "últimas operaciones sobre la base de datos.\n"
       "Los últimos datos introducidos no han sido guardados, por favor\n"
       "revise sus últimas acciones y repita las operaciones que no\n"
       "se han guardado.\n")
  );
  if (!ctx.isEmpty())
    msg += tr("Contexto: %1\n").arg(ctx);
  msgBoxWarning(msg);
#ifndef QSDEBUGGER
  printf("%s\n", msg.latin1());
#endif
}

FLWorkspace::FLWorkspace(QWidget *parent, const char *name) : QWorkspace(parent, name)
{
  logo = QImage::fromMimeSource("mini_logo_abanq.png");
  fColor.setRgb(AQ_RGB_LOGO);
  pColor.setRgb(164, 170, 180);
}

void FLWorkspace::paintEvent(QPaintEvent *pe)
{
  QPainter p(this);
  p.fillRect(pe->rect(), fColor);

  int dx = width() - logo.width();
  int dy = height() - logo.height();
  p.drawImage(QPoint(dx, dy), logo);

  p.setPen(pColor);
  p.setBrush(pColor);
  //p.drawRect(dx + 23, 0, 2, dy);

  p.end();

  QWidget::paintEvent(pe);
}

FLWidget::FLWidget(QWidget *parent, const char *name,  WFlags f) : QWidget(parent, name, f)
{
  logo = QImage::fromMimeSource("mini_logo_abanq.png");
  fColor.setRgb(AQ_RGB_LOGO);
  pColor.setRgb(164, 170, 180);
}

void FLWidget::paintEvent(QPaintEvent *pe)
{
  QPainter p(this);
  p.fillRect(pe->rect(), fColor);

  int dx = width() - logo.width();
  int dy = height() - logo.height();
  p.drawImage(QPoint(dx, dy), logo);

  p.setPen(pColor);
  p.setBrush(pColor);
  //p.drawRect(dx + 23, 0, 2, dy);

  p.end();

  QWidget::paintEvent(pe);
}
