summaryrefslogtreecommitdiffstats
path: root/sfx2/source/doc/autoredactdialog.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sfx2/source/doc/autoredactdialog.cxx
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sfx2/source/doc/autoredactdialog.cxx')
-rw-r--r--sfx2/source/doc/autoredactdialog.cxx770
1 files changed, 770 insertions, 0 deletions
diff --git a/sfx2/source/doc/autoredactdialog.cxx b/sfx2/source/doc/autoredactdialog.cxx
new file mode 100644
index 000000000..6509f8c47
--- /dev/null
+++ b/sfx2/source/doc/autoredactdialog.cxx
@@ -0,0 +1,770 @@
+/* -*- 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 <autoredactdialog.hxx>
+
+#include <sfx2/filedlghelper.hxx>
+#include <sfx2/sfxresid.hxx>
+#include <sfx2/strings.hrc>
+
+#include <osl/file.hxx>
+#include <sal/log.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <unotools/viewoptions.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+
+#include <boost/property_tree/json_parser.hpp>
+
+constexpr OUStringLiteral FILEDIALOG_FILTER_JSON = u"*.json";
+
+int TargetsTable::GetRowByTargetName(std::u16string_view sName)
+{
+ for (int i = 0, nCount = m_xControl->n_children(); i < nCount; ++i)
+ {
+ RedactionTarget* pTarget = weld::fromId<RedactionTarget*>(m_xControl->get_id(i));
+ if (pTarget->sName == sName)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+TargetsTable::TargetsTable(std::unique_ptr<weld::TreeView> xControl)
+ : m_xControl(std::move(xControl))
+{
+ m_xControl->set_size_request(555, 250);
+ std::vector<int> aWidths{ 100, 50, 200, 105, 105 };
+ m_xControl->set_column_fixed_widths(aWidths);
+ m_xControl->set_selection_mode(SelectionMode::Multiple);
+}
+
+namespace
+{
+OUString getTypeName(RedactionTargetType nType)
+{
+ OUString sTypeName(SfxResId(STR_REDACTION_TARGET_TYPE_UNKNOWN));
+
+ switch (nType)
+ {
+ case RedactionTargetType::REDACTION_TARGET_TEXT:
+ sTypeName = SfxResId(STR_REDACTION_TARGET_TYPE_TEXT);
+ break;
+ case RedactionTargetType::REDACTION_TARGET_REGEX:
+ sTypeName = SfxResId(STR_REDACTION_TARGET_TYPE_REGEX);
+ break;
+ case RedactionTargetType::REDACTION_TARGET_PREDEFINED:
+ sTypeName = SfxResId(STR_REDACTION_TARGET_TYPE_PREDEF);
+ break;
+ case RedactionTargetType::REDACTION_TARGET_UNKNOWN:
+ sTypeName = SfxResId(STR_REDACTION_TARGET_TYPE_UNKNOWN);
+ break;
+ }
+
+ return sTypeName;
+}
+
+/// Returns TypeID to be used in the add/edit target dialog
+OUString getTypeID(RedactionTargetType nType)
+{
+ OUString sTypeID("unknown");
+
+ switch (nType)
+ {
+ case RedactionTargetType::REDACTION_TARGET_TEXT:
+ sTypeID = "text";
+ break;
+ case RedactionTargetType::REDACTION_TARGET_REGEX:
+ sTypeID = "regex";
+ break;
+ case RedactionTargetType::REDACTION_TARGET_PREDEFINED:
+ sTypeID = "predefined";
+ break;
+ case RedactionTargetType::REDACTION_TARGET_UNKNOWN:
+ sTypeID = "unknown";
+ break;
+ }
+
+ return sTypeID;
+}
+}
+
+void TargetsTable::InsertTarget(RedactionTarget* pTarget)
+{
+ if (!pTarget)
+ {
+ SAL_WARN("sfx.doc", "pTarget is null in TargetsTable::InsertTarget()");
+ return;
+ }
+
+ // Check if the name is empty or invalid (clashing with another entry's name)
+ if (pTarget->sName.isEmpty() || GetRowByTargetName(pTarget->sName) != -1)
+ {
+ pTarget->sName = GetNameProposal();
+ }
+
+ OUString sContent = pTarget->sContent;
+
+ if (pTarget->sType == RedactionTargetType::REDACTION_TARGET_PREDEFINED)
+ {
+ //selection_num;selection_name
+ sContent = sContent.getToken(1, ';');
+ }
+
+ // Add to the end
+ int nRow = m_xControl->n_children();
+ m_xControl->append(weld::toId(pTarget), pTarget->sName);
+ m_xControl->set_text(nRow, getTypeName(pTarget->sType), 1);
+ m_xControl->set_text(nRow, sContent, 2);
+ m_xControl->set_text(
+ nRow, pTarget->bCaseSensitive ? SfxResId(STR_REDACTION_YES) : SfxResId(STR_REDACTION_NO),
+ 3);
+ m_xControl->set_text(
+ nRow, pTarget->bWholeWords ? SfxResId(STR_REDACTION_YES) : SfxResId(STR_REDACTION_NO), 4);
+}
+
+RedactionTarget* TargetsTable::GetTargetByName(std::u16string_view sName)
+{
+ int nEntry = GetRowByTargetName(sName);
+ if (nEntry == -1)
+ return nullptr;
+
+ return weld::fromId<RedactionTarget*>(m_xControl->get_id(nEntry));
+}
+
+OUString TargetsTable::GetNameProposal() const
+{
+ OUString sDefaultTargetName(SfxResId(STR_REDACTION_TARGET));
+ sal_Int32 nHighestTargetId = 0;
+ for (int i = 0, nCount = m_xControl->n_children(); i < nCount; ++i)
+ {
+ RedactionTarget* pTarget = weld::fromId<RedactionTarget*>(m_xControl->get_id(i));
+ const OUString& sName = pTarget->sName;
+ sal_Int32 nIndex = 0;
+ if (o3tl::getToken(sName, 0, ' ', nIndex) == sDefaultTargetName)
+ {
+ sal_Int32 nCurrTargetId = o3tl::toInt32(o3tl::getToken(sName, 0, ' ', nIndex));
+ nHighestTargetId = std::max<sal_Int32>(nHighestTargetId, nCurrTargetId);
+ }
+ }
+ return sDefaultTargetName + " " + OUString::number(nHighestTargetId + 1);
+}
+
+void TargetsTable::setRowData(int nRowIndex, const RedactionTarget* pTarget)
+{
+ OUString sContent = pTarget->sContent;
+
+ if (pTarget->sType == RedactionTargetType::REDACTION_TARGET_PREDEFINED)
+ {
+ //selection_num;selection_name
+ sContent = sContent.getToken(1, ';');
+ }
+
+ m_xControl->set_text(nRowIndex, pTarget->sName, 0);
+ m_xControl->set_text(nRowIndex, getTypeName(pTarget->sType), 1);
+ m_xControl->set_text(nRowIndex, sContent, 2);
+ m_xControl->set_text(
+ nRowIndex,
+ pTarget->bCaseSensitive ? SfxResId(STR_REDACTION_YES) : SfxResId(STR_REDACTION_NO), 3);
+ m_xControl->set_text(
+ nRowIndex, pTarget->bWholeWords ? SfxResId(STR_REDACTION_YES) : SfxResId(STR_REDACTION_NO),
+ 4);
+}
+
+IMPL_LINK_NOARG(SfxAutoRedactDialog, Load, weld::Button&, void)
+{
+ //Load a targets list from a previously saved file (a json file?)
+ // ask for filename, where we should load the new config data from
+ StartFileDialog(StartFileDialogType::Open, SfxResId(STR_REDACTION_LOAD_TARGETS));
+}
+
+IMPL_LINK_NOARG(SfxAutoRedactDialog, Save, weld::Button&, void)
+{
+ //Allow saving the targets into a file
+ StartFileDialog(StartFileDialogType::SaveAs, SfxResId(STR_REDACTION_SAVE_TARGETS));
+}
+
+IMPL_LINK_NOARG(SfxAutoRedactDialog, AddHdl, weld::Button&, void)
+{
+ // Open the Add Target dialog, create a new target and insert into the targets vector and the listbox
+ SfxAddTargetDialog aAddTargetDialog(getDialog(), m_xTargetsBox->GetNameProposal());
+
+ bool bIncomplete;
+ do
+ {
+ bIncomplete = false;
+
+ if (aAddTargetDialog.run() != RET_OK)
+ return;
+
+ if (aAddTargetDialog.getName().isEmpty()
+ || aAddTargetDialog.getType() == RedactionTargetType::REDACTION_TARGET_UNKNOWN
+ || aAddTargetDialog.getContent().isEmpty())
+ {
+ bIncomplete = true;
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
+ getDialog(), VclMessageType::Warning, VclButtonsType::Ok,
+ SfxResId(STR_REDACTION_FIELDS_REQUIRED)));
+ xBox->run();
+ }
+ else if (m_xTargetsBox->GetTargetByName(aAddTargetDialog.getName()))
+ {
+ bIncomplete = true;
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
+ getDialog(), VclMessageType::Warning, VclButtonsType::Ok,
+ SfxResId(STR_REDACTION_TARGET_NAME_CLASH)));
+ xBox->run();
+ }
+
+ } while (bIncomplete);
+
+ //Alright, we now have everything we need to construct a new target
+ RedactionTarget* redactiontarget = new RedactionTarget(
+ { aAddTargetDialog.getName(), aAddTargetDialog.getType(), aAddTargetDialog.getContent(),
+ aAddTargetDialog.isCaseSensitive(), aAddTargetDialog.isWholeWords(), 0 });
+
+ // Only the visual/display part
+ m_xTargetsBox->InsertTarget(redactiontarget);
+
+ // Actually add to the targets vector
+ if (m_xTargetsBox->GetTargetByName(redactiontarget->sName))
+ m_aTableTargets.emplace_back(redactiontarget, redactiontarget->sName);
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
+ getDialog(), VclMessageType::Warning, VclButtonsType::Ok,
+ SfxResId(STR_REDACTION_TARGET_ADD_ERROR)));
+ xBox->run();
+ delete redactiontarget;
+ }
+}
+
+IMPL_LINK_NOARG(SfxAutoRedactDialog, EditHdl, weld::Button&, void)
+{
+ sal_Int32 nSelectedRow = m_xTargetsBox->get_selected_index();
+
+ // No selection, nothing to edit
+ if (nSelectedRow < 0)
+ return;
+
+ // Only one entry should be selected for editing
+ if (m_xTargetsBox->get_selected_rows().size() > 1)
+ {
+ //Warn the user about multiple selections
+ std::unique_ptr<weld::MessageDialog> xBox(
+ Application::CreateMessageDialog(getDialog(), VclMessageType::Error, VclButtonsType::Ok,
+ SfxResId(STR_REDACTION_MULTI_EDIT)));
+ xBox->run();
+ return;
+ }
+
+ // Get the redaction target to be edited
+ RedactionTarget* pTarget = weld::fromId<RedactionTarget*>(m_xTargetsBox->get_id(nSelectedRow));
+
+ // Construct and run the edit target dialog
+ SfxAddTargetDialog aEditTargetDialog(getDialog(), pTarget->sName, pTarget->sType,
+ pTarget->sContent, pTarget->bCaseSensitive,
+ pTarget->bWholeWords);
+
+ bool bIncomplete;
+ do
+ {
+ bIncomplete = false;
+
+ if (aEditTargetDialog.run() != RET_OK)
+ return;
+
+ if (aEditTargetDialog.getName().isEmpty()
+ || aEditTargetDialog.getType() == RedactionTargetType::REDACTION_TARGET_UNKNOWN
+ || aEditTargetDialog.getContent().isEmpty())
+ {
+ bIncomplete = true;
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
+ getDialog(), VclMessageType::Warning, VclButtonsType::Ok,
+ SfxResId(STR_REDACTION_FIELDS_REQUIRED)));
+ xBox->run();
+ }
+ else if (aEditTargetDialog.getName() != pTarget->sName
+ && m_xTargetsBox->GetTargetByName(aEditTargetDialog.getName()))
+ {
+ bIncomplete = true;
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
+ getDialog(), VclMessageType::Warning, VclButtonsType::Ok,
+ SfxResId(STR_REDACTION_TARGET_NAME_CLASH)));
+ xBox->run();
+ }
+
+ } while (bIncomplete);
+
+ // Update the redaction target
+ pTarget->sName = aEditTargetDialog.getName();
+ pTarget->sType = aEditTargetDialog.getType();
+ pTarget->sContent = aEditTargetDialog.getContent();
+ pTarget->bCaseSensitive = aEditTargetDialog.isCaseSensitive();
+ pTarget->bWholeWords = aEditTargetDialog.isWholeWords();
+
+ // And sync the targets box row with the actual target data
+ m_xTargetsBox->setRowData(nSelectedRow, pTarget);
+}
+IMPL_LINK_NOARG(SfxAutoRedactDialog, DoubleClickEditHdl, weld::TreeView&, bool)
+{
+ if (m_xEditBtn->get_sensitive())
+ m_xEditBtn->clicked();
+ return true;
+}
+IMPL_LINK_NOARG(SfxAutoRedactDialog, DeleteHdl, weld::Button&, void)
+{
+ std::vector<int> aSelectedRows = m_xTargetsBox->get_selected_rows();
+
+ //No selection, so nothing to delete
+ if (aSelectedRows.empty())
+ return;
+
+ if (aSelectedRows.size() > 1)
+ {
+ OUString sMsg(SfxResId(STR_REDACTION_MULTI_DELETE)
+ .replaceFirst("$(TARGETSCOUNT)", OUString::number(aSelectedRows.size())));
+ //Warn the user about multiple deletions
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
+ getDialog(), VclMessageType::Question, VclButtonsType::OkCancel, sMsg));
+ if (xBox->run() == RET_CANCEL)
+ return;
+ }
+
+ // After each delete, the indexes of the following items decrease by one.
+ int delta = 0;
+ for (const auto& i : aSelectedRows)
+ {
+ m_aTableTargets.erase(m_aTableTargets.begin() + (i - delta));
+ m_xTargetsBox->remove(i - delta++);
+ }
+}
+
+namespace
+{
+boost::property_tree::ptree redactionTargetToJSON(const RedactionTarget* pTarget)
+{
+ boost::property_tree::ptree aNode;
+ aNode.put("sName", pTarget->sName.toUtf8().getStr());
+ aNode.put("eType", pTarget->sType);
+ aNode.put("sContent", pTarget->sContent.toUtf8().getStr());
+ aNode.put("bWholeWords", pTarget->bWholeWords);
+ aNode.put("bCaseSensitive", pTarget->bCaseSensitive);
+ aNode.put("nID", pTarget->nID);
+
+ return aNode;
+}
+
+std::unique_ptr<RedactionTarget>
+JSONtoRedactionTarget(const boost::property_tree::ptree::value_type& rValue)
+{
+ OUString sName = OUString::fromUtf8(rValue.second.get<std::string>("sName").c_str());
+ RedactionTargetType eType
+ = static_cast<RedactionTargetType>(atoi(rValue.second.get<std::string>("eType").c_str()));
+ OUString sContent = OUString::fromUtf8(rValue.second.get<std::string>("sContent").c_str());
+ bool bCaseSensitive
+ = OUString::fromUtf8(rValue.second.get<std::string>("bCaseSensitive").c_str()).toBoolean();
+ bool bWholeWords
+ = OUString::fromUtf8(rValue.second.get<std::string>("bWholeWords").c_str()).toBoolean();
+ sal_uInt32 nID = atoi(rValue.second.get<std::string>("nID").c_str());
+
+ return std::unique_ptr<RedactionTarget>(
+ new RedactionTarget{ sName, eType, sContent, bCaseSensitive, bWholeWords, nID });
+}
+}
+
+IMPL_LINK_NOARG(SfxAutoRedactDialog, LoadHdl, sfx2::FileDialogHelper*, void)
+{
+ assert(m_pFileDlg);
+
+ OUString sTargetsFile;
+ if (ERRCODE_NONE == m_pFileDlg->GetError())
+ sTargetsFile = m_pFileDlg->GetPath();
+
+ if (sTargetsFile.isEmpty())
+ return;
+
+ OUString sSysPath;
+ osl::File::getSystemPathFromFileURL(sTargetsFile, sSysPath);
+ sTargetsFile = sSysPath;
+
+ weld::WaitObject aWaitObject(getDialog());
+
+ try
+ {
+ // Create path string, and read JSON from file
+ std::string sPathStr(OUStringToOString(sTargetsFile, RTL_TEXTENCODING_UTF8).getStr());
+
+ boost::property_tree::ptree aTargetsJSON;
+
+ boost::property_tree::read_json(sPathStr, aTargetsJSON);
+
+ // Clear the dialog
+ clearTargets();
+
+ // Recreate & add the targets to the dialog
+ for (const boost::property_tree::ptree::value_type& rValue :
+ aTargetsJSON.get_child("RedactionTargets"))
+ {
+ addTarget(JSONtoRedactionTarget(rValue));
+ }
+ }
+ catch (css::uno::Exception& e)
+ {
+ SAL_WARN("sfx.doc",
+ "Exception caught while trying to load the targets JSON from file: " << e.Message);
+ return;
+ //TODO: Warn the user with a message box
+ }
+}
+
+IMPL_LINK_NOARG(SfxAutoRedactDialog, SaveHdl, sfx2::FileDialogHelper*, void)
+{
+ assert(m_pFileDlg);
+
+ OUString sTargetsFile;
+ if (ERRCODE_NONE == m_pFileDlg->GetError())
+ sTargetsFile = m_pFileDlg->GetPath();
+
+ if (sTargetsFile.isEmpty())
+ return;
+
+ OUString sSysPath;
+ osl::File::getSystemPathFromFileURL(sTargetsFile, sSysPath);
+ sTargetsFile = sSysPath;
+
+ weld::WaitObject aWaitObject(getDialog());
+
+ try
+ {
+ // Put the targets into a JSON array
+ boost::property_tree::ptree aTargetsArray;
+ for (const auto& targetPair : m_aTableTargets)
+ {
+ aTargetsArray.push_back(
+ std::make_pair("", redactionTargetToJSON(targetPair.first.get())));
+ }
+
+ // Build the JSON tree
+ boost::property_tree::ptree aTargetsTree;
+ aTargetsTree.add_child("RedactionTargets", aTargetsArray);
+
+ // Create path string, and write JSON to file
+ std::string sPathStr(OUStringToOString(sTargetsFile, RTL_TEXTENCODING_UTF8).getStr());
+
+ boost::property_tree::write_json(sPathStr, aTargetsTree);
+ }
+ catch (css::uno::Exception& e)
+ {
+ SAL_WARN("sfx.doc",
+ "Exception caught while trying to save the targets JSON to file: " << e.Message);
+ return;
+ //TODO: Warn the user with a message box
+ }
+}
+
+void SfxAutoRedactDialog::StartFileDialog(StartFileDialogType nType, const OUString& rTitle)
+{
+ OUString aFilterAllStr(SfxResId(STR_SFX_FILTERNAME_ALL));
+ OUString aFilterJsonStr(SfxResId(STR_REDACTION_JSON_FILE_FILTER));
+
+ bool bSave = nType == StartFileDialogType::SaveAs;
+ short nDialogType = bSave ? css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION
+ : css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE;
+ m_pFileDlg.reset(new sfx2::FileDialogHelper(nDialogType, FileDialogFlags::NONE, getDialog()));
+
+ m_pFileDlg->SetTitle(rTitle);
+ m_pFileDlg->AddFilter(aFilterAllStr, FILEDIALOG_FILTER_ALL);
+ m_pFileDlg->AddFilter(aFilterJsonStr, FILEDIALOG_FILTER_JSON);
+ m_pFileDlg->SetCurrentFilter(aFilterJsonStr);
+
+ Link<sfx2::FileDialogHelper*, void> aDlgClosedLink
+ = bSave ? LINK(this, SfxAutoRedactDialog, SaveHdl)
+ : LINK(this, SfxAutoRedactDialog, LoadHdl);
+ m_pFileDlg->SetContext(sfx2::FileDialogHelper::AutoRedact);
+ m_pFileDlg->StartExecuteModal(aDlgClosedLink);
+}
+
+void SfxAutoRedactDialog::addTarget(std::unique_ptr<RedactionTarget> pTarget)
+{
+ // Only the visual/display part
+ m_xTargetsBox->InsertTarget(pTarget.get());
+
+ // Actually add to the targets vector
+ auto name = pTarget->sName;
+ if (m_xTargetsBox->GetTargetByName(name))
+ m_aTableTargets.emplace_back(std::move(pTarget), name);
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
+ getDialog(), VclMessageType::Warning, VclButtonsType::Ok,
+ SfxResId(STR_REDACTION_TARGET_ADD_ERROR)));
+ xBox->run();
+ }
+}
+
+void SfxAutoRedactDialog::clearTargets()
+{
+ // Clear the targets box
+ m_xTargetsBox->clear();
+
+ // Clear the targets vector
+ m_aTableTargets.clear();
+}
+
+SfxAutoRedactDialog::SfxAutoRedactDialog(weld::Window* pParent)
+ : SfxDialogController(pParent, "sfx/ui/autoredactdialog.ui", "AutoRedactDialog")
+ , m_bIsValidState(true)
+ , m_bTargetsCopied(false)
+ , m_xRedactionTargetsLabel(m_xBuilder->weld_label("labelRedactionTargets"))
+ , m_xTargetsBox(new TargetsTable(m_xBuilder->weld_tree_view("targets")))
+ , m_xLoadBtn(m_xBuilder->weld_button("btnLoadTargets"))
+ , m_xSaveBtn(m_xBuilder->weld_button("btnSaveTargets"))
+ , m_xAddBtn(m_xBuilder->weld_button("add"))
+ , m_xEditBtn(m_xBuilder->weld_button("edit"))
+ , m_xDeleteBtn(m_xBuilder->weld_button("delete"))
+{
+ // Can be used to remember the last set of redaction targets?
+ OUString sExtraData;
+ SvtViewOptions aDlgOpt(EViewType::Dialog,
+ OStringToOUString(m_xDialog->get_help_id(), RTL_TEXTENCODING_UTF8));
+
+ if (aDlgOpt.Exists())
+ {
+ css::uno::Any aUserItem = aDlgOpt.GetUserItem("UserItem");
+ aUserItem >>= sExtraData;
+ }
+
+ // update the targets configuration if necessary
+ if (!sExtraData.isEmpty())
+ {
+ weld::WaitObject aWaitCursor(m_xDialog.get());
+
+ try
+ {
+ // Create path string, and read JSON from file
+ boost::property_tree::ptree aTargetsJSON;
+ std::stringstream aStream(std::string(sExtraData.toUtf8()));
+
+ boost::property_tree::read_json(aStream, aTargetsJSON);
+
+ // Recreate & add the targets to the dialog
+ for (const boost::property_tree::ptree::value_type& rValue :
+ aTargetsJSON.get_child("RedactionTargets"))
+ {
+ addTarget(JSONtoRedactionTarget(rValue));
+ }
+ }
+ catch (css::uno::Exception& e)
+ {
+ SAL_WARN("sfx.doc",
+ "Exception caught while trying to load the last dialog state: " << e.Message);
+ return;
+ //TODO: Warn the user with a message box
+ }
+ }
+
+ // Handler connections
+ m_xLoadBtn->connect_clicked(LINK(this, SfxAutoRedactDialog, Load));
+ m_xSaveBtn->connect_clicked(LINK(this, SfxAutoRedactDialog, Save));
+ m_xAddBtn->connect_clicked(LINK(this, SfxAutoRedactDialog, AddHdl));
+ m_xEditBtn->connect_clicked(LINK(this, SfxAutoRedactDialog, EditHdl));
+ m_xDeleteBtn->connect_clicked(LINK(this, SfxAutoRedactDialog, DeleteHdl));
+ m_xTargetsBox->connect_row_activated(LINK(this, SfxAutoRedactDialog, DoubleClickEditHdl));
+}
+
+SfxAutoRedactDialog::~SfxAutoRedactDialog()
+{
+ if (m_aTableTargets.empty())
+ {
+ // Clear the dialog data
+ SvtViewOptions aDlgOpt(EViewType::Dialog,
+ OStringToOUString(m_xDialog->get_help_id(), RTL_TEXTENCODING_UTF8));
+ aDlgOpt.Delete();
+ return;
+ }
+
+ try
+ {
+ // Put the targets into a JSON array
+ boost::property_tree::ptree aTargetsArray;
+ for (const auto& targetPair : m_aTableTargets)
+ {
+ aTargetsArray.push_back(
+ std::make_pair("", redactionTargetToJSON(targetPair.first.get())));
+ }
+
+ // Build the JSON tree
+ boost::property_tree::ptree aTargetsTree;
+ aTargetsTree.add_child("RedactionTargets", aTargetsArray);
+ std::stringstream aStream;
+
+ boost::property_tree::write_json(aStream, aTargetsTree, false);
+
+ OUString sUserDataStr(OUString::fromUtf8(aStream.str().c_str()));
+
+ // Store the dialog data
+ SvtViewOptions aDlgOpt(EViewType::Dialog,
+ OStringToOUString(m_xDialog->get_help_id(), RTL_TEXTENCODING_UTF8));
+ aDlgOpt.SetUserItem("UserItem", css::uno::Any(sUserDataStr));
+
+ if (!m_bTargetsCopied)
+ clearTargets();
+ }
+ catch (css::uno::Exception& e)
+ {
+ SAL_WARN("sfx.doc",
+ "Exception caught while trying to store the dialog state: " << e.Message);
+ return;
+ //TODO: Warn the user with a message box
+ }
+}
+
+bool SfxAutoRedactDialog::hasTargets() const
+{
+ //TODO: Add also some validity checks?
+ if (m_aTableTargets.empty())
+ return false;
+
+ return true;
+}
+
+bool SfxAutoRedactDialog::getTargets(std::vector<std::pair<RedactionTarget, OUString>>& r_aTargets)
+{
+ if (m_aTableTargets.empty())
+ return true;
+
+ for (auto const& rPair : m_aTableTargets)
+ r_aTargets.push_back({ *rPair.first, rPair.second });
+ m_bTargetsCopied = true;
+ return true;
+}
+
+IMPL_LINK_NOARG(SfxAddTargetDialog, SelectTypeHdl, weld::ComboBox&, void)
+{
+ if (m_xType->get_active_id() == "predefined")
+ {
+ // Hide the usual content widgets
+ // We will just set the id as content
+ // And handle with proper regex in the SfxRedactionHelper
+ m_xLabelContent->set_sensitive(false);
+ m_xLabelContent->set_visible(false);
+ m_xContent->set_sensitive(false);
+ m_xContent->set_visible(false);
+ m_xWholeWords->set_sensitive(false);
+ m_xWholeWords->set_visible(false);
+ m_xCaseSensitive->set_sensitive(false);
+ m_xCaseSensitive->set_visible(false);
+
+ // And show the predefined targets
+ m_xLabelPredefContent->set_sensitive(true);
+ m_xLabelPredefContent->set_visible(true);
+ m_xPredefContent->set_sensitive(true);
+ m_xPredefContent->set_visible(true);
+ }
+ else
+ {
+ m_xLabelPredefContent->set_sensitive(false);
+ m_xLabelPredefContent->set_visible(false);
+ m_xPredefContent->set_sensitive(false);
+ m_xPredefContent->set_visible(false);
+
+ m_xLabelContent->set_sensitive(true);
+ m_xLabelContent->set_visible(true);
+ m_xContent->set_sensitive(true);
+ m_xContent->set_visible(true);
+ m_xWholeWords->set_sensitive(true);
+ m_xWholeWords->set_visible(true);
+ m_xCaseSensitive->set_sensitive(true);
+ m_xCaseSensitive->set_visible(true);
+ }
+}
+
+SfxAddTargetDialog::SfxAddTargetDialog(weld::Window* pParent, const OUString& rName)
+ : GenericDialogController(pParent, "sfx/ui/addtargetdialog.ui", "AddTargetDialog")
+ , m_xName(m_xBuilder->weld_entry("name"))
+ , m_xType(m_xBuilder->weld_combo_box("type"))
+ , m_xLabelContent(m_xBuilder->weld_label("label_content"))
+ , m_xContent(m_xBuilder->weld_entry("content"))
+ , m_xLabelPredefContent(m_xBuilder->weld_label("label_content_predef"))
+ , m_xPredefContent(m_xBuilder->weld_combo_box("content_predef"))
+ , m_xCaseSensitive(m_xBuilder->weld_check_button("checkboxCaseSensitive"))
+ , m_xWholeWords(m_xBuilder->weld_check_button("checkboxWholeWords"))
+{
+ m_xName->set_text(rName);
+ m_xName->select_region(0, rName.getLength());
+
+ m_xType->connect_changed(LINK(this, SfxAddTargetDialog, SelectTypeHdl));
+}
+
+SfxAddTargetDialog::SfxAddTargetDialog(weld::Window* pParent, const OUString& sName,
+ const RedactionTargetType& eTargetType,
+ const OUString& sContent, bool bCaseSensitive,
+ bool bWholeWords)
+ : GenericDialogController(pParent, "sfx/ui/addtargetdialog.ui", "AddTargetDialog")
+ , m_xName(m_xBuilder->weld_entry("name"))
+ , m_xType(m_xBuilder->weld_combo_box("type"))
+ , m_xLabelContent(m_xBuilder->weld_label("label_content"))
+ , m_xContent(m_xBuilder->weld_entry("content"))
+ , m_xLabelPredefContent(m_xBuilder->weld_label("label_content_predef"))
+ , m_xPredefContent(m_xBuilder->weld_combo_box("content_predef"))
+ , m_xCaseSensitive(m_xBuilder->weld_check_button("checkboxCaseSensitive"))
+ , m_xWholeWords(m_xBuilder->weld_check_button("checkboxWholeWords"))
+{
+ m_xName->set_text(sName);
+ m_xName->select_region(0, sName.getLength());
+
+ m_xType->set_active_id(getTypeID(eTargetType));
+ m_xType->connect_changed(LINK(this, SfxAddTargetDialog, SelectTypeHdl));
+
+ if (eTargetType == RedactionTargetType::REDACTION_TARGET_PREDEFINED)
+ {
+ SelectTypeHdl(*m_xPredefContent);
+ m_xPredefContent->set_active(o3tl::toInt32(o3tl::getToken(sContent, 0, ';')));
+ }
+ else
+ {
+ m_xContent->set_text(sContent);
+ }
+
+ m_xCaseSensitive->set_active(bCaseSensitive);
+ m_xWholeWords->set_active(bWholeWords);
+
+ set_title(SfxResId(STR_REDACTION_EDIT_TARGET));
+}
+
+RedactionTargetType SfxAddTargetDialog::getType() const
+{
+ OUString sTypeID = m_xType->get_active_id();
+
+ if (sTypeID == "text")
+ return RedactionTargetType::REDACTION_TARGET_TEXT;
+ else if (sTypeID == "regex")
+ return RedactionTargetType::REDACTION_TARGET_REGEX;
+ else if (sTypeID == "predefined")
+ return RedactionTargetType::REDACTION_TARGET_PREDEFINED;
+ else
+ return RedactionTargetType::REDACTION_TARGET_UNKNOWN;
+}
+
+OUString SfxAddTargetDialog::getContent() const
+{
+ if (m_xType->get_active_id() == "predefined")
+ {
+ return OUString(OUString::number(m_xPredefContent->get_active()) + ";"
+ + m_xPredefContent->get_active_text());
+ }
+
+ return m_xContent->get_text();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */