/***************************************************************************
**
**  This file is part of QGpGuiTools.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file is distributed in the hope that it will be useful, but WITHOUT
**  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
**  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2008-09-14
**  Copyright: 2008-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "MultiDocumentWindow.h"
#include "MultiDocumentTabWidget.h"
#include "MultiDocumentTab.h"
#include "MultiDocumentSubWindow.h"
#include "MultiDocumentEnvironment.h"
#include "Application.h"
#include "SizeGrip.h"
#include "Settings.h"
#if(QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
#include "TitledWidget.h"
#include "Dialog.h"
#endif

namespace QGpGuiTools {

/*!
  \class MultiDocumentWindow MultiDocumentWindow.h
  \brief Brief description of class still missing

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
MultiDocumentWindow::MultiDocumentWindow(QWidget * parent, Qt::WindowFlags f)
    : QMainWindow(parent, f)
{
  TRACE;
  setAttribute(Qt::WA_DeleteOnClose, true);

  _tabs=new MultiDocumentTabWidget;
  connect(_tabs, SIGNAL(newTabRequested(int)), this, SLOT(insertTab(int)));
  connect(_tabs, SIGNAL(closeTabRequested(int)), this, SLOT(closeTab(int)));
  connect(_tabs, SIGNAL(tabifyRequested(int)), this, SLOT(tabify(int)));
  connect(this, SIGNAL(closeTabRequested(MultiDocumentTab *)),
          this, SLOT(closeTab(MultiDocumentTab *)), Qt::QueuedConnection);
  setCentralWidget(_tabs);
  createWindowsActions();
}

/*!
  Description of destructor still missing
*/
MultiDocumentWindow::~MultiDocumentWindow()
{
  TRACE;
}

void MultiDocumentWindow::addFileActions()
{
  TRACE;

  QMenu * m;
  QToolBar * tb;

  m=menuBar()->addMenu(tr("&File"));
  m->setTearOffEnabled (true);
  tb=addToolBar(tr("File"));
  tb->setObjectName("FileBar");
  tb->setIconSize(QSize(24, 24));

  _fileMenu=m;
  _fileBar=tb;

  MultiDocumentEnvironment::instance()->addFileActions(m, tb);
}

void MultiDocumentWindow::addEditActions()
{
  TRACE;

  QMenu * m;
  QToolBar * tb;

  m=menuBar()->addMenu(tr("&Edit"));
  m->setTearOffEnabled (true);
  tb=addToolBar(tr("Edit"));
  tb->setObjectName("EditBar");
  tb->setIconSize(QSize(24, 24));

  _editMenu=m;
  _editBar=tb;

  MultiDocumentEnvironment::instance()->addEditActions(m, tb);
}

void MultiDocumentWindow::addViewActions()
{
  TRACE;

  QMenu * m;
  QToolBar * tb;

  m=menuBar()->addMenu(tr("&View"));
  m->setTearOffEnabled (true);
  tb=addToolBar(tr("View"));
  tb->setObjectName("ViewBar");
  tb->setIconSize(QSize(24, 24));

  _viewMenu=m;
  _viewBar=tb;

  MultiDocumentEnvironment::instance()->addViewActions(m, tb);
}

void MultiDocumentWindow::addWindowsActions()
{
  TRACE;

  _windowsMenu=menuBar()->addMenu(tr("&Windows"));
  _windowsMenu->setTearOffEnabled(true);
  MultiDocumentEnvironment::instance()->addWindowsActions(_windowsMenu);
  addWindowsActions(_windowsMenu);
  _windowsMenu->addSeparator();
}

void MultiDocumentWindow::addHelpActions()
{
  TRACE;

  QMenu * m;

  m=menuBar()->addMenu(tr("&Help"));
  m->setTearOffEnabled (true);

  _helpMenu=m;

  MultiDocumentEnvironment::instance()->addHelpActions(m);
}

void MultiDocumentWindow::createWindowsActions()
{
  TRACE;
  QAction * a;

  a=new QAction(tr("New &tab"), this);
  a->setToolTip(tr("Add a new tab"));
  connect(a, SIGNAL(triggered()), this, SLOT(addTab()));
  _windowsNewTabAction=a;

  a=new QAction(tr("Close win&dow"), this);
  a->setToolTip(tr("Close current sub window"));
  a->setEnabled(false);
  connect(a, SIGNAL(triggered()), this, SLOT(closeSubWindow()));
  _windowsCloseAction=a;

  a=new QAction(tr("Close all w&indows"), this);
  a->setToolTip(tr("Close all sub windows of the current tab"));
  a->setEnabled(false);
  connect(a, SIGNAL(triggered()), this, SLOT(closeAllSubWindows()));
  _windowsCloseAllSubWindowsAction=a;

  a=new QAction(tr("Close t&ab"), this);
  a->setToolTip(tr("Close current tab"));
  connect(a, SIGNAL(triggered()), this, SLOT(closeTab()));
  _windowsCloseTabAction=a;

  a=new QAction(tr("Close all ta&bs"), this);
  a->setToolTip(tr("Close all tabs"));
  connect(a, SIGNAL(triggered()), this, SLOT(closeAllTabs()));
  _windowsCloseAllTabsAction=a;

  a=new QAction(tr("&Cascade"), this);
  a->setToolTip(tr("Organize sub windows in cascade"));
  a->setEnabled(false);
  connect(a, SIGNAL(triggered()), this, SLOT(cascadeSubWindows()));
  _windowsCascadeAction=a;

  a=new QAction(tr("Ti&le"), this);
  a->setToolTip(tr("Organize sub windows in tiles"));
  a->setEnabled(false);
  connect(a, SIGNAL(triggered()), this, SLOT(tileSubWindows()));
  _windowsTileAction=a;

  _toolBarsMenu=new QMenu(this);
  connect(_toolBarsMenu, SIGNAL(aboutToShow()), this, SLOT(showToolBarMenu()));

  a=new QAction(tr("T&ool bars"), this);
  a->setMenu(_toolBarsMenu);
  _windowsToolBarsAction=a;
}

void MultiDocumentWindow::addWindowsActions(QMenu * m)
{
  TRACE;
  if(m) {
    m->addAction(_windowsNewTabAction);
    m->addSeparator();
    m->addAction(_windowsCloseAction);
    m->addAction(_windowsCloseAllSubWindowsAction);
    m->addAction(_windowsCloseTabAction);
    m->addAction(_windowsCloseAllTabsAction);
    m->addSeparator();
    m->addAction(_windowsCascadeAction);
    m->addAction(_windowsTileAction);
    m->addSeparator();
    m->addAction(_windowsToolBarsAction);
  }
}

void MultiDocumentWindow::setWindowsMenuEnabled(bool b)
{
  TRACE;
  _windowsCloseAction->setEnabled(b);
  _windowsCloseAllSubWindowsAction->setEnabled(b);
  _windowsCascadeAction->setEnabled(b);
  _windowsTileAction->setEnabled(b);
}

void MultiDocumentWindow::addTab()
{
  TRACE;
  MultiDocumentTab * t=new MultiDocumentTab;
  connect(t, SIGNAL(subWindowActivated(QMdiSubWindow *)),
          this, SLOT(setCurrentSubWindow(QMdiSubWindow *)));
  _tabs->addTab(t);
  _windowsMenu->addAction(t->windowMenuAction());
}

void MultiDocumentWindow::insertTab(int at)
{
  TRACE;
  MultiDocumentTab * t=new MultiDocumentTab;
  connect(t, SIGNAL(subWindowActivated(QMdiSubWindow *)),
          this, SLOT(setCurrentSubWindow(QMdiSubWindow *)));
  _tabs->insertTab(at+1, t);
  _windowsMenu->addAction(t->windowMenuAction());
}

MultiDocumentTab * MultiDocumentWindow::tab(int index) const
{
  TRACE;
  ASSERT(index>=0 && index<_tabs->count());
  return qobject_cast<MultiDocumentTab *>(_tabs->widget(index));
}

/*!
  Add window \a w to tab \a t.
*/
MultiDocumentSubWindow * MultiDocumentWindow::addSubWindow(QWidget * w, MultiDocumentTab * t)
{
  TRACE;
  MultiDocumentSubWindow * mdiw=new MultiDocumentSubWindow;
  mdiw->setWidget(w);
  mdiw->setWindowTitle(w->windowTitle());
  mdiw->setWindowIcon(w->windowIcon());
  new SizeGrip(w);
  connect(mdiw, SIGNAL(moveToTabMenuRequested(QMenu *, MultiDocumentSubWindow *)),
          this, SLOT(moveToTabMenu(QMenu *, MultiDocumentSubWindow *)));
#if(QT_VERSION > QT_VERSION_CHECK(5, 0, 0))
  connect(w, SIGNAL(windowTitleChanged(const QString&)), mdiw, SLOT(setWindowTitle(QString)));
#else
  Dialog * dw=qobject_cast<Dialog *>(w);
  if(dw) {
    connect(dw, SIGNAL(windowTitleChangedQt4(const QString&)), mdiw, SLOT(setWindowTitle(QString)));
  } else {
    connect(static_cast<TitledWidget *>(w), SIGNAL(windowTitleChangedQt4(const QString&)), mdiw, SLOT(setWindowTitle(QString)));
  }
#endif
  if(!t) {
    t=tab(_tabs->currentIndex());
  }
  t->addSubWindow(mdiw);
  Settings::getSize(mdiw, w->objectName());
  mdiw->show();
  return mdiw;
}

void MultiDocumentWindow::setCurrentSubWindow(QMdiSubWindow * w)
{
  TRACE;
  MultiDocumentSubWindow * mdw=qobject_cast<MultiDocumentSubWindow *>(w);
  if(!mdw) return;
  MultiDocumentTab * t=mdw->tab();
  QList<MultiDocumentSubWindow *>	wList=t->subWindowList();
  if(t==tab(_tabs->currentIndex())) { // Enable or not menu only if a is the current tab
    setWindowsMenuEnabled(!wList.isEmpty());
  }
  foreach(MultiDocumentSubWindow * subw, wList) {
    if(subw) {
      QAction * a=subw->windowMenuAction();
      if(subw==mdw) {
        a->setChecked(true);
        emit activeWindowChanged(subw);
      } else {
        a->setChecked(false);
      }
    }
  } 
}

void MultiDocumentWindow::moveToTabMenu(QMenu * m, MultiDocumentSubWindow * w)
{
  TRACE;
  m->clear();
  QAction * a;
  for(int i=0; i<_tabs->count(); i++) {
    MultiDocumentTab * t=tab(i);
    a=new QAction(t->name(), this);
    a->setData(QVariant::fromValue(static_cast<void *>(w)));
    connect(a, SIGNAL(triggered()), t, SLOT(moveSubWindow()));
    m->addAction(a);
  }
}

QList<MultiDocumentSubWindow *> MultiDocumentWindow::subWindowList() const
{
  TRACE;
  QList<MultiDocumentSubWindow *> l;
  for(int i=_tabs->count()-1; i>=0; i--) {
    l.append(tab(i)->subWindowList());
  }
  return l;
}

/*!
  Close current sub window of current tab.
*/
void MultiDocumentWindow::closeSubWindow()
{
  TRACE;
  MultiDocumentTab * t=tab(_tabs->currentIndex());
  MultiDocumentSubWindow * w=t->currentSubWindow();
  if(w) {
    w->close();
  }
}

/*!
  Close all sub windows of current tab.
*/
bool MultiDocumentWindow::closeAllSubWindows()
{
  TRACE;
  MultiDocumentTab * t=tab(_tabs->currentIndex());
  return t->closeAllSubWindows();
}

/*!
  Close all sub windows of all tabs.
*/
bool MultiDocumentWindow::closeAllSubWindowsFromAllTabs()
{
  TRACE;
  for(int i=_tabs->count()-1; i>=0; i--) {
    MultiDocumentTab * t=tab(i);
    if(!t->closeAllSubWindows()) {
      return false;
    }
  }
  return true;
}

/*!
  Close tab with index \a at.
*/
void MultiDocumentWindow::closeTab(int at)
{
  TRACE;
  if(at<0) {
    at=_tabs->currentIndex();
    ASSERT(at>=0);  // There is always at least one tab.
  }
  if(_tabs->count()>1) {
    MultiDocumentTab * t=_tabs->tab(at);
    // Explicitely close all sub windows, usefull if some sub windows have to execute
    // specific code on closing.
    if(t->closeAllSubWindows()) {
      emit closeTabRequested(t);
    }
  }
}

void MultiDocumentWindow::closeTab(MultiDocumentTab * t)
{
  QList<MultiDocumentSubWindow *> wList=t->subWindowList();
  if(wList.isEmpty()) {
    int at=_tabs->indexOf(t);
    _tabs->removeTab(at);
    if(at==_tabs->count()) {
      _tabs->setCurrentIndex(at-1);
    }
    delete t;
  } else {
    for(QList<MultiDocumentSubWindow *>::iterator it=wList.begin(); it!=wList.end(); it++) {
      (*it)->show();
    }
    Message::warning(MSG_ID, tr("Closing tab"),
                     tr("Not all windows can be closed in tab '%1'.")
                     .arg(t->name()), true);
  }
}

/*!
  Close all tabs.
*/
void MultiDocumentWindow::closeAllTabs()
{
  TRACE;
  for(int i=_tabs->count()-1; i>0; i--) {
    closeTab(i);
  }
  // There is always at least one tab
  _tabs->tab(0)->closeAllSubWindows();
}

void MultiDocumentWindow::cascadeSubWindows()
{
  TRACE;
  MultiDocumentTab * t=tab(_tabs->currentIndex());
  t->cascadeSubWindows();
}

void MultiDocumentWindow::tileSubWindows()
{
  TRACE;
  MultiDocumentTab * t=tab(_tabs->currentIndex());
  t->tileSubWindows();
}

void MultiDocumentWindow::showToolBarMenu()
{
  TRACE;
  _toolBarsMenu->clear();
  QList<QDockWidget *> dockwidgetList=findChildren<QDockWidget *>();
  QAction * a;
  for(QList<QDockWidget *>::iterator it=dockwidgetList.begin();it!=dockwidgetList.end();++it) {
    a=new QAction((*it) ->windowTitle(), this);
    a->setCheckable(true);
    if((*it) ->isVisible())
      a->setChecked(true);
    connect(a, SIGNAL(toggled(bool)), *it, SLOT(setVisible(bool)));
    _toolBarsMenu->addAction(a);
  }
  _toolBarsMenu->addSeparator();
  QList<QToolBar *> toolBarList=findChildren<QToolBar *>();
  for(QList<QToolBar *>::iterator it=toolBarList.begin();it!=toolBarList.end();++it) {
    a=new QAction((*it) ->windowTitle(), this);
    a->setCheckable(true);
    if((*it) ->isVisible())
      a->setChecked(true);
    connect(a, SIGNAL(toggled(bool)), *it, SLOT(setVisible(bool)));
    _toolBarsMenu->addAction(a);
  }
}

MultiDocumentTab * MultiDocumentWindow::currentTab() const
{
  TRACE;
  return qobject_cast<MultiDocumentTab *>(_tabs->currentWidget());
}

void MultiDocumentWindow::tabify(int at)
{
  TRACE;
  if(at<0) {
    at=_tabs->currentIndex();
    ASSERT(at>=0);  // There is always at least one tab.
  }
  MultiDocumentTab * t=_tabs->tab(at);
  QList<MultiDocumentSubWindow *> wList=t->subWindowList();
  QList<MultiDocumentSubWindow *>::iterator it=wList.begin();
  if(it!=wList.end()) {
    (*it)->showMaximized();
    for(it++; it!=wList.end(); it++) {
      insertTab(at++);
      _tabs->tab(at)->addSubWindow(*it);
      (*it)->showMaximized();
    }
  }
}
} // namespace QGpGuiTools
