/*
 * chatsplitter.cpp - QSplitter replacement that masquerades it
 * Copyright (C) 2007  Michail Pishchagin
 *
 * 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; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

#include "chatsplitter.h"

#include "psioptions.h"

#include <QChildEvent>
#include <QSplitter>
#include <QVBoxLayout>

/**
 * Handy widget that masquerades itself as QSplitter, and could work
 * in both QSplitter mode, and QSplitter-less mode.
 */
ChatSplitter::ChatSplitter(QWidget *parent) :
    QWidget(parent), splitterEnabled_(true), splitter_(nullptr), layout_(nullptr)
{
    connect(PsiOptions::instance(), SIGNAL(optionChanged(const QString &)), SLOT(optionsChanged()));
    optionsChanged();

    if (!layout_)
        updateLayout();
}

/**
 * Dummy function to fool Qt Designer-generated forms.
 */
void ChatSplitter::setOrientation(Qt::Orientation orientation)
{
    Q_ASSERT(orientation == Qt::Vertical);
    Q_UNUSED(orientation);
}

/**
 * Adds the given \a widget to the splitter's layout after all the
 * other items. Don't call this function if widget is already added
 * to the splitter's layout.
 */
void ChatSplitter::addWidget(QWidget *widget)
{
    Q_ASSERT(!children_.contains(widget));
    children_ << widget;
    connect(widget, SIGNAL(destroyed(QObject *)), SLOT(childDestroyed(QObject *)));
    updateChildLayout(widget);
}

/**
 * If splitter mode is enabled, the \a list is passed to the
 * actual splitter. Has no effect otherwise.
 */
void ChatSplitter::setSizes(const QList<int> &list)
{
    if (splitter_)
        splitter_->setSizes(list);
}

QList<int> ChatSplitter::sizes()
{
    QList<int> list;
    if (splitter_)
        list = splitter_->sizes();

    return list;
}

/**
 * Moves \a child either to the real QSplitter, or adds it to the
 * private layout.
 */
void ChatSplitter::updateChildLayout(QWidget *child)
{
    if (splitterEnabled() && splitter_) {
        splitter_->addWidget(child);
    } else {
        layout_->addWidget(child);
    }
}

/**
 * Removes destroyed widget from the splitter's child list.
 */
void ChatSplitter::childDestroyed(QObject *obj)
{
    Q_ASSERT(obj->isWidgetType());
    children_.removeAll(static_cast<QWidget *>(obj));
}

/**
 * If \a enable is true, the true QSplitter gets enabled, otherwise
 * all widgets are managed by QLayout.
 */
void ChatSplitter::setSplitterEnabled(bool enable)
{
    if (splitterEnabled_ == enable)
        return;

    splitterEnabled_ = enable;
    updateLayout();
}

/**
 * Invalidates layout and moves all child widgets to the proper position.
 */
void ChatSplitter::updateLayout()
{
    for (QWidget *child : qAsConst(children_))
        child->setParent(this);

    delete splitter_;
    delete layout_;
    splitter_ = new QSplitter(this);
    layout_   = new QVBoxLayout(this);
    layout_->setMargin(0);
    layout_->addWidget(splitter_);
    splitter_->setOrientation(Qt::Vertical);
    splitter_->setVisible(splitterEnabled());

    for (QWidget *child : qAsConst(children_))
        updateChildLayout(child);

    connect(splitter_, SIGNAL(splitterMoved(int, int)), SIGNAL(splitterMoved(int, int)));
}

/**
 * Updates layout according to current options.
 * FIXME: When PsiOptions::instance()->getOption("options.ui.chat.use-expanding-line-edit").toBool() finally makes it to
 * PsiOptions, make this slot private.
 */
void ChatSplitter::optionsChanged()
{
    setSplitterEnabled(!PsiOptions::instance()->getOption("options.ui.chat.use-expanding-line-edit").toBool());
}
