/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
 
#include <docfunc.hxx>
#include <condformateasydlg.hxx>
#include <stlpool.hxx>
#include <viewdata.hxx>
#include <reffact.hxx>
#include <scresid.hxx>
#include <svl/style.hxx>
#include <strings.hrc>
#include <condformathelper.hxx>
 
namespace
{
condformat::ScCondFormatDateType GetScCondFormatDateType(ScConditionMode mode)
{
    switch (mode)
    {
        case ScConditionMode::Today:
            return condformat::ScCondFormatDateType::TODAY;
        case ScConditionMode::Yesterday:
            return condformat::ScCondFormatDateType::YESTERDAY;
        case ScConditionMode::Tomorrow:
            return condformat::ScCondFormatDateType::TOMORROW;
        case ScConditionMode::Last7days:
            return condformat::ScCondFormatDateType::LAST7DAYS;
        case ScConditionMode::ThisWeek:
            return condformat::ScCondFormatDateType::THISWEEK;
        case ScConditionMode::LastWeek:
            return condformat::ScCondFormatDateType::LASTWEEK;
        case ScConditionMode::NextWeek:
            return condformat::ScCondFormatDateType::NEXTWEEK;
        case ScConditionMode::ThisMonth:
            return condformat::ScCondFormatDateType::THISMONTH;
        case ScConditionMode::LastMonth:
            return condformat::ScCondFormatDateType::LASTMONTH;
        case ScConditionMode::NextMonth:
            return condformat::ScCondFormatDateType::NEXTMONTH;
        case ScConditionMode::ThisYear:
            return condformat::ScCondFormatDateType::THISYEAR;
        case ScConditionMode::LastYear:
            return condformat::ScCondFormatDateType::LASTYEAR;
        case ScConditionMode::NextYear:
            return condformat::ScCondFormatDateType::NEXTYEAR;
        default:
            return condformat::ScCondFormatDateType::TODAY;
    }
}
}
 
namespace sc
{
void ConditionalFormatEasyDialog::SetDescription(std::u16string_view rCondition)
{
    mxDescription->set_label(mxDescription->get_label().replaceAll("%1", rCondition));
}
 
ConditionalFormatEasyDialog::ConditionalFormatEasyDialog(SfxBindings* pBindings,
                                                         SfxChildWindow* pChildWindow,
                                                         weld::Window* pParent,
                                                         ScViewData* pViewData)
    : ScAnyRefDlgController(pBindings, pChildWindow, pParent,
                            u"modules/scalc/ui/conditionaleasydialog.ui"_ustr,
                            u"CondFormatEasyDlg"_ustr)
    , mpParent(pParent)
    , mpViewData(pViewData)
    , mpDocument(&mpViewData->GetDocument())
    , mbIsManaged(false)
    , mnFormatKey(0)
    , mnEntryIndex(0)
    , mxNumberEntry(m_xBuilder->weld_entry(u"entryNumber"_ustr))
    , mxNumberEntry2(m_xBuilder->weld_entry(u"entryNumber2"_ustr))
    , mxAllInputs(m_xBuilder->weld_container(u"allInputs"_ustr))
    , mxWarningLabel(m_xBuilder->weld_label(u"warning"_ustr))
    , mxRangeEntry(new formula::RefEdit(m_xBuilder->weld_entry(u"entryRange"_ustr)))
    , mxButtonRangeEdit(new formula::RefButton(m_xBuilder->weld_button(u"rbassign"_ustr)))
    , mxStyles(m_xBuilder->weld_combo_box(u"themeCombo"_ustr))
    , mxWdPreviewWin(m_xBuilder->weld_widget(u"previewwin"_ustr))
    , mxWdPreview(new weld::CustomWeld(*m_xBuilder, "preview", maWdPreview))
    , mxDescription(m_xBuilder->weld_label(u"description"_ustr))
    , mxButtonOk(m_xBuilder->weld_button(u"ok"_ustr))
    , mxButtonCancel(m_xBuilder->weld_button(u"cancel"_ustr))
{
    mxButtonRangeEdit->SetReferences(this, mxRangeEntry.get());
    const ScConditionEasyDialogData CurrentData
        = pViewData->GetDocument().GetEasyConditionalFormatDialogData();
    if (!CurrentData.Mode)
    {
        SAL_WARN(
            "sc",
            "Condition mode not set for easy conditional format dialog, this should not happen");
        meMode = ScConditionMode::Greater;
    }
    else
    {
        meMode = *CurrentData.Mode;
        mbIsManaged = CurrentData.IsManaged;
        msFormula = CurrentData.Formula;
        mnFormatKey = CurrentData.FormatKey;
        mnEntryIndex = CurrentData.EntryIndex;
    }
    mxNumberEntry2->hide();
    switch (meMode)
    {
        case ScConditionMode::Equal:
            SetDescription(ScResId(STR_CONDITION_EQUAL));
            break;
        case ScConditionMode::Less:
            SetDescription(ScResId(STR_CONDITION_LESS));
            break;
        case ScConditionMode::Greater:
            SetDescription(ScResId(STR_CONDITION_GREATER));
            break;
        case ScConditionMode::EqLess:
            SetDescription(ScResId(STR_CONDITION_EQLESS));
            break;
        case ScConditionMode::EqGreater:
            SetDescription(ScResId(STR_CONDITION_EQGREATER));
            break;
        case ScConditionMode::NotEqual:
            SetDescription(ScResId(STR_CONDITION_NOT_EQUAL));
            break;
        case ScConditionMode::Between:
            SetDescription(ScResId(STR_CONDITION_BETWEEN));
            mxNumberEntry2->show();
            break;
        case ScConditionMode::NotBetween:
            SetDescription(ScResId(STR_CONDITION_NOT_BETWEEN));
            mxNumberEntry2->show();
            break;
        case ScConditionMode::Duplicate:
            SetDescription(ScResId(STR_CONDITION_DUPLICATE));
            mxAllInputs->hide();
            break;
        case ScConditionMode::NotDuplicate:
            SetDescription(ScResId(STR_CONDITION_NOT_DUPLICATE));
            mxAllInputs->hide();
            break;
        // TODO: Direct
        case ScConditionMode::Top10:
            SetDescription(ScResId(STR_CONDITION_TOP_N_ELEMENTS));
            break;
        case ScConditionMode::Bottom10:
            SetDescription(ScResId(STR_CONDITION_BOTTOM_N_ELEMENTS));
            break;
 
        case ScConditionMode::TopPercent:
            SetDescription(ScResId(STR_CONDITION_TOP_N_PERCENT));
            break;
        case ScConditionMode::BottomPercent:
            SetDescription(ScResId(STR_CONDITION_BOTTOM_N_PERCENT));
            break;
 
        case ScConditionMode::AboveAverage:
            SetDescription(ScResId(STR_CONDITION_ABOVE_AVERAGE));
            mxAllInputs->hide();
            break;
        case ScConditionMode::BelowAverage:
            SetDescription(ScResId(STR_CONDITION_BELOW_AVERAGE));
            mxAllInputs->hide();
            break;
 
        case ScConditionMode::AboveEqualAverage:
            SetDescription(ScResId(STR_CONDITION_ABOVE_OR_EQUAL_AVERAGE));
            mxAllInputs->hide();
            break;
        case ScConditionMode::BelowEqualAverage:
            SetDescription(ScResId(STR_CONDITION_BELOW_OR_EQUAL_AVERAGE));
            mxAllInputs->hide();
            break;
        case ScConditionMode::Error:
            SetDescription(ScResId(STR_CONDITION_ERROR));
            break;
        case ScConditionMode::NoError:
            SetDescription(ScResId(STR_CONDITION_NOERROR));
            break;
        case ScConditionMode::BeginsWith:
            SetDescription(ScResId(STR_CONDITION_BEGINS_WITH));
            break;
        case ScConditionMode::EndsWith:
            SetDescription(ScResId(STR_CONDITION_ENDS_WITH));
            break;
        case ScConditionMode::ContainsText:
            SetDescription(ScResId(STR_CONDITION_CONTAINS_TEXT));
            break;
        case ScConditionMode::NotContainsText:
            SetDescription(ScResId(STR_CONDITION_NOT_CONTAINS_TEXT));
            break;
        case ScConditionMode::Formula:
            SetDescription(ScResId(STR_CONDITION_FORMULA));
            mxAllInputs->hide();
            break;
        case ScConditionMode::Today:
            SetDescription(ScResId(STR_CONDITION_TODAY));
            mxAllInputs->hide();
            break;
        case ScConditionMode::Yesterday:
            SetDescription(ScResId(STR_CONDITION_YESTERDAY));
            mxAllInputs->hide();
            break;
        case ScConditionMode::Tomorrow:
            SetDescription(ScResId(STR_CONDITION_TOMORROW));
            mxAllInputs->hide();
            break;
        case ScConditionMode::Last7days:
            SetDescription(ScResId(STR_CONDITION_LAST7DAYS));
            mxAllInputs->hide();
            break;
        case ScConditionMode::ThisWeek:
            SetDescription(ScResId(STR_CONDITION_THISWEEK));
            mxAllInputs->hide();
            break;
        case ScConditionMode::LastWeek:
            SetDescription(ScResId(STR_CONDITION_LASTWEEK));
            mxAllInputs->hide();
            break;
        case ScConditionMode::NextWeek:
            SetDescription(ScResId(STR_CONDITION_NEXTWEEK));
            mxAllInputs->hide();
            break;
        case ScConditionMode::ThisMonth:
            SetDescription(ScResId(STR_CONDITION_THISMONTH));
            mxAllInputs->hide();
            break;
        case ScConditionMode::LastMonth:
            SetDescription(ScResId(STR_CONDITION_LASTMONTH));
            mxAllInputs->hide();
            break;
        case ScConditionMode::NextMonth:
            SetDescription(ScResId(STR_CONDITION_NEXTMONTH));
            mxAllInputs->hide();
            break;
        case ScConditionMode::ThisYear:
            SetDescription(ScResId(STR_CONDITION_THISYEAR));
            mxAllInputs->hide();
            break;
        case ScConditionMode::LastYear:
            SetDescription(ScResId(STR_CONDITION_LASTYEAR));
            mxAllInputs->hide();
            break;
        case ScConditionMode::NextYear:
            SetDescription(ScResId(STR_CONDITION_NEXTYEAR));
            mxAllInputs->hide();
            break;
        default:
            SAL_WARN("sc",
                     "ConditionalFormatEasyDialog::ConditionalFormatEasyDialog: invalid format");
            break;
    }
 
    mxButtonOk->connect_clicked(LINK(this, ConditionalFormatEasyDialog, ButtonPressed));
    mxButtonCancel->connect_clicked(LINK(this, ConditionalFormatEasyDialog, ButtonPressed));
    mxStyles->connect_changed(LINK(this, ConditionalFormatEasyDialog, StyleSelectHdl));
    mxNumberEntry->connect_changed(LINK(this, ConditionalFormatEasyDialog, OnEdChanged));
    mxNumberEntry2->connect_changed(LINK(this, ConditionalFormatEasyDialog, OnEdChanged));
 
    ScRangeList aRange;
    mpViewData->GetMarkData().FillRangeListWithMarks(&aRange, false);
    ScConditionalFormat* format
        = mpDocument->GetCondFormList(mpViewData->GetTabNo())->GetFormat(mnFormatKey);
    if (aRange.empty() && mnFormatKey != -1 && mnEntryIndex != -1)
    {
        aRange = format->GetRangeList();
    }
    else if (aRange.empty())
    {
        ScAddress aPosition(mpViewData->GetCurX(), mpViewData->GetCurY(), mpViewData->GetTabNo());
        aRange.push_back(ScRange(aPosition));
    }
    maPosition = aRange.GetTopLeftCorner();
    // FIX me: Tab is always 0 in some cases
    // Refer to test tdf100793
    maPosition.SetTab(mpViewData->GetTabNo());
 
    OUString sRangeString;
    aRange.Format(sRangeString, ScRefFlags::VALID, *mpDocument, mpDocument->GetAddressConvention());
    mxRangeEntry->SetText(sRangeString);
 
    OUString sStyleName;
    if (format)
    {
        const ScFormatEntry* entry = format->GetEntry(mnEntryIndex);
        if (!entry)
            return;
        ScFormatEntry::Type type = entry->GetType();
        if (type == ScFormatEntry::Type::Condition)
        {
            const ScCondFormatEntry* condEntry = static_cast<const ScCondFormatEntry*>(entry);
            sStyleName = condEntry->GetStyle();
            if (mxNumberEntry->get_visible())
                mxNumberEntry->set_text(condEntry->GetExpression(aRange.GetTopLeftCorner(), 0));
            if (mxNumberEntry2->get_visible())
                mxNumberEntry2->set_text(condEntry->GetExpression(aRange.GetTopLeftCorner(), 1));
        }
        else if (type == ScFormatEntry::Type::Date)
        {
            const ScCondDateFormatEntry* dateEntry
                = static_cast<const ScCondDateFormatEntry*>(entry);
            sStyleName = dateEntry->GetStyleName();
        }
    }
 
    StartListening(*mpDocument->GetStyleSheetPool(), DuplicateHandling::Prevent);
    ScCondFormatHelper::FillStyleListBox(mpDocument, *mxStyles);
 
    mxStyles->set_active_text(sStyleName);
    StyleSelectHdl(*mxStyles);
    mxWdPreviewWin->show();
}
 
ConditionalFormatEasyDialog::~ConditionalFormatEasyDialog()
{
    if (mbIsManaged)
    {
        GetBindings().GetDispatcher()->Execute(SID_OPENDLG_CONDFRMT_MANAGER,
                                               SfxCallMode::ASYNCHRON);
    }
}
 
void ConditionalFormatEasyDialog::Notify(SfxBroadcaster&, const SfxHint& rHint)
{
    if (rHint.GetId() == SfxHintId::StyleSheetModified
        || rHint.GetId() == SfxHintId::StyleSheetModifiedExtended)
        ScCondFormatHelper::UpdateStyleList(*mxStyles, mpDocument);
}
 
void ConditionalFormatEasyDialog::SetReference(const ScRange& rRange, ScDocument&)
{
    formula::RefEdit* pEdit = mxRangeEntry.get();
    if (rRange.aStart != rRange.aEnd)
        RefInputStart(pEdit);
 
    ScRefFlags nFlags = ScRefFlags::RANGE_ABS;
    const ScDocument& rDoc = mpViewData->GetDocument();
    OUString sRange(
        rRange.Format(rDoc, nFlags, ScAddress::Details(mpDocument->GetAddressConvention(), 0, 0)));
    pEdit->SetRefString(sRange);
    maPosition = rRange.aStart;
}
 
void ConditionalFormatEasyDialog::SetActive()
{
    mxRangeEntry->GrabFocus();
    RefInputDone();
}
 
void ConditionalFormatEasyDialog::Close()
{
    DoClose(ConditionalFormatEasyDialogWrapper::GetChildWindowId());
}
 
IMPL_LINK(ConditionalFormatEasyDialog, ButtonPressed, weld::Button&, rButton, void)
{
    if (&rButton == mxButtonOk.get())
    {
        if (mnEntryIndex != -1 && mnFormatKey != -1) // isEdit
            mpDocument->GetCondFormList(maPosition.Tab())
                ->GetFormat(mnFormatKey)
                ->RemoveEntry(mnEntryIndex);
 
        std::unique_ptr<ScConditionalFormat> pFormat(new ScConditionalFormat(0, mpDocument));
 
        OUString sExpression1 = (mxNumberEntry->get_visible() && mxAllInputs->get_visible()
                                     ? mxNumberEntry->get_text()
                                     : u""_ustr);
        OUString sExpression2 = (mxNumberEntry2->get_visible() && mxAllInputs->get_visible()
                                     ? mxNumberEntry2->get_text()
                                     : u""_ustr);
 
        switch (meMode)
        {
            case ScConditionMode::ContainsText:
            case ScConditionMode::NotContainsText:
            case ScConditionMode::BeginsWith:
            case ScConditionMode::EndsWith:
                sExpression1 = "\"" + sExpression1 + "\"";
                sExpression2 = "\"" + sExpression2 + "\"";
                break;
            default:
                break;
        }
 
        std::unique_ptr<ScFormatEntry> xEntry;
        if (meMode < ScConditionMode::Formula)
        {
            xEntry.reset(new ScCondFormatEntry(meMode, sExpression1, sExpression2, *mpDocument,
                                               maPosition, mxStyles->get_active_text()));
        }
        else if (meMode >= ScConditionMode::Today && meMode < ScConditionMode::NONE)
        {
            ScCondDateFormatEntry entry(mpDocument);
            entry.SetDateType(GetScCondFormatDateType(meMode));
            entry.SetStyleName(mxStyles->get_active_text());
            xEntry.reset(new ScCondDateFormatEntry(mpDocument, entry));
        }
        else if (meMode == ScConditionMode::Formula)
        {
            xEntry.reset(new ScCondFormatEntry(ScConditionMode::Direct, msFormula, OUString(),
                                               *mpDocument, maPosition,
                                               mxStyles->get_active_text()));
        }
        else
        {
            DBG_ASSERT(false, "Invalid condition type selected.");
            return;
        }
 
        ScRangeList aRange;
        ScRefFlags nFlags
            = aRange.Parse(mxRangeEntry->GetText(), mpViewData->GetDocument(),
                           mpViewData->GetDocument().GetAddressConvention(), maPosition.Tab());
        if ((nFlags & ScRefFlags::VALID) && !aRange.empty())
        {
            pFormat->AddEntry(xEntry.release());
            pFormat->SetRange(aRange);
            auto& rRangeList = pFormat->GetRange();
            mpViewData->GetDocShell()->GetDocFunc().ReplaceConditionalFormat(
                0, std::move(pFormat), maPosition.Tab(), rRangeList);
        }
        m_xDialog->response(RET_OK);
    }
    else if (&rButton == mxButtonCancel.get())
        m_xDialog->response(RET_CANCEL);
}
 
IMPL_LINK_NOARG(ConditionalFormatEasyDialog, StyleSelectHdl, weld::ComboBox&, void)
{
    ScCondFormatHelper::StyleSelect(mpParent, *mxStyles, &(mpViewData->GetDocument()), maWdPreview);
}
 
IMPL_LINK(ConditionalFormatEasyDialog, OnEdChanged, weld::Entry&, rEntry, void)
{
    ScCondFormatHelper::ValidateInputField(rEntry, *mxWarningLabel, mpDocument, maPosition);
 
    if (!mxWarningLabel->get_label().isEmpty())
        mxWarningLabel->show();
    else
        mxWarningLabel->hide();
}
 
} // namespace sc
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

V530 The return value of function 'Execute' is required to be utilized.

V595 The 'format' pointer was utilized before it was verified against nullptr. Check lines: 270, 287.