1237 lines
40 KiB
C++
1237 lines
40 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* 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/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <svx/dialmgr.hxx>
|
|
#include <svx/strings.hrc>
|
|
#include <bitmaps.hlst>
|
|
#include <docrecovery.hxx>
|
|
|
|
#include <comphelper/propertyvalue.hxx>
|
|
#include <comphelper/sequenceashashmap.hxx>
|
|
#include <comphelper/string.hxx>
|
|
#include <svtools/imagemgr.hxx>
|
|
#include <sfx2/filedlghelper.hxx>
|
|
#include <tools/urlobj.hxx>
|
|
#include <utility>
|
|
#include <vcl/weld.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
|
|
#include <com/sun/star/util/URL.hpp>
|
|
#include <com/sun/star/util/XURLTransformer.hpp>
|
|
#include <com/sun/star/frame/theAutoRecovery.hpp>
|
|
#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp>
|
|
#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
|
|
#include <com/sun/star/util/URLTransformer.hpp>
|
|
#include <osl/diagnose.h>
|
|
#include <osl/file.hxx>
|
|
#include <unotools/pathoptions.hxx>
|
|
|
|
namespace svx::DocRecovery
|
|
{
|
|
|
|
using namespace ::osl;
|
|
|
|
#define COLUMN_STANDARDIMAGE -1
|
|
#define COLUMN_DISPLAYNAME 0
|
|
#define COLUMN_STATUSIMAGE 1
|
|
#define COLUMN_STATUSTEXT 2
|
|
|
|
RecoveryCore::RecoveryCore(css::uno::Reference< css::uno::XComponentContext > xContext,
|
|
bool bUsedForSaving)
|
|
: m_xContext (std::move( xContext ))
|
|
, m_pListener ( nullptr )
|
|
, m_bListenForSaving(bUsedForSaving)
|
|
{
|
|
impl_startListening();
|
|
}
|
|
|
|
|
|
RecoveryCore::~RecoveryCore()
|
|
{
|
|
impl_stopListening();
|
|
}
|
|
|
|
|
|
const css::uno::Reference< css::uno::XComponentContext >& RecoveryCore::getComponentContext() const
|
|
{
|
|
return m_xContext;
|
|
}
|
|
|
|
|
|
TURLList& RecoveryCore::getURLListAccess()
|
|
{
|
|
return m_lURLs;
|
|
}
|
|
|
|
|
|
bool RecoveryCore::isBrokenTempEntry(const TURLInfo& rInfo)
|
|
{
|
|
if (rInfo.TempURL.isEmpty())
|
|
return false;
|
|
|
|
// Note: If the original files was recovery ... but a temp file
|
|
// exists ... an error inside the temp file exists!
|
|
if (
|
|
(rInfo.RecoveryState != E_RECOVERY_FAILED ) &&
|
|
(rInfo.RecoveryState != E_ORIGINAL_DOCUMENT_RECOVERED)
|
|
)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void RecoveryCore::saveBrokenTempEntries(const OUString& rPath)
|
|
{
|
|
if (rPath.isEmpty())
|
|
return;
|
|
|
|
if (!m_xRealCore.is())
|
|
return;
|
|
|
|
// prepare all needed parameters for the following dispatch() request.
|
|
css::util::URL aCopyURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_BACKUP);
|
|
css::uno::Sequence< css::beans::PropertyValue > lCopyArgs(3);
|
|
auto plCopyArgs = lCopyArgs.getArray();
|
|
plCopyArgs[0].Name = PROP_DISPATCHASYNCHRON;
|
|
plCopyArgs[0].Value <<= false;
|
|
plCopyArgs[1].Name = PROP_SAVEPATH;
|
|
plCopyArgs[1].Value <<= rPath;
|
|
plCopyArgs[2].Name = PROP_ENTRYID;
|
|
// lCopyArgs[2].Value will be changed during next loop...
|
|
|
|
// work on a copied list only...
|
|
// Reason: We will get notifications from the core for every
|
|
// changed or removed element. And that will change our m_lURLs list.
|
|
// That's not a good idea, if we use a stl iterator inbetween .-)
|
|
TURLList lURLs = m_lURLs;
|
|
for (const TURLInfo& rInfo : lURLs)
|
|
{
|
|
if (!RecoveryCore::isBrokenTempEntry(rInfo))
|
|
continue;
|
|
|
|
plCopyArgs[2].Value <<= rInfo.ID;
|
|
m_xRealCore->dispatch(aCopyURL, lCopyArgs);
|
|
}
|
|
}
|
|
|
|
|
|
void RecoveryCore::saveAllTempEntries(const OUString& rPath)
|
|
{
|
|
if (rPath.isEmpty())
|
|
return;
|
|
|
|
if (!m_xRealCore.is())
|
|
return;
|
|
|
|
// prepare all needed parameters for the following dispatch() request.
|
|
css::util::URL aCopyURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_BACKUP);
|
|
css::uno::Sequence< css::beans::PropertyValue > lCopyArgs(3);
|
|
auto plCopyArgs = lCopyArgs.getArray();
|
|
plCopyArgs[0].Name = PROP_DISPATCHASYNCHRON;
|
|
plCopyArgs[0].Value <<= false;
|
|
plCopyArgs[1].Name = PROP_SAVEPATH;
|
|
plCopyArgs[1].Value <<= rPath;
|
|
plCopyArgs[2].Name = PROP_ENTRYID;
|
|
// lCopyArgs[2].Value will be changed during next loop ...
|
|
|
|
// work on a copied list only ...
|
|
// Reason: We will get notifications from the core for every
|
|
// changed or removed element. And that will change our m_lURLs list.
|
|
// That's not a good idea, if we use a stl iterator inbetween .-)
|
|
TURLList lURLs = m_lURLs;
|
|
for (const TURLInfo& rInfo : lURLs)
|
|
{
|
|
if (rInfo.TempURL.isEmpty())
|
|
continue;
|
|
|
|
plCopyArgs[2].Value <<= rInfo.ID;
|
|
m_xRealCore->dispatch(aCopyURL, lCopyArgs);
|
|
}
|
|
}
|
|
|
|
|
|
void RecoveryCore::forgetBrokenTempEntries()
|
|
{
|
|
if (!m_xRealCore.is())
|
|
return;
|
|
|
|
css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
|
|
css::uno::Sequence< css::beans::PropertyValue > lRemoveArgs(2);
|
|
auto plRemoveArgs = lRemoveArgs.getArray();
|
|
plRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
|
|
plRemoveArgs[0].Value <<= false;
|
|
plRemoveArgs[1].Name = PROP_ENTRYID;
|
|
// lRemoveArgs[1].Value will be changed during next loop ...
|
|
|
|
// work on a copied list only ...
|
|
// Reason: We will get notifications from the core for every
|
|
// changed or removed element. And that will change our m_lURLs list.
|
|
// That's not a good idea, if we use a stl iterator inbetween .-)
|
|
TURLList lURLs = m_lURLs;
|
|
for (const TURLInfo& rInfo : lURLs)
|
|
{
|
|
if (!RecoveryCore::isBrokenTempEntry(rInfo))
|
|
continue;
|
|
|
|
plRemoveArgs[1].Value <<= rInfo.ID;
|
|
m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
|
|
}
|
|
}
|
|
|
|
// should only be called with valid m_xRealCore
|
|
void RecoveryCore::forgetAllRecoveryEntriesMarkedForDiscard()
|
|
{
|
|
assert(m_xRealCore);
|
|
|
|
// potential to move in a separate function
|
|
css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
|
|
css::uno::Sequence<css::beans::PropertyValue> lRemoveArgs(2);
|
|
auto plRemoveArgs = lRemoveArgs.getArray();
|
|
plRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
|
|
plRemoveArgs[0].Value <<= false;
|
|
plRemoveArgs[1].Name = PROP_ENTRYID;
|
|
|
|
// work on a copied list only ...
|
|
// Reason: We will get notifications from the core for every
|
|
// changed or removed element. And that will change our m_lURLs list.
|
|
// That's not a good idea, if we use a stl iterator inbetween .-)
|
|
TURLList lURLs = m_lURLs;
|
|
for (const TURLInfo& rInfo : lURLs)
|
|
{
|
|
if (!rInfo.ShouldDiscard)
|
|
continue;
|
|
|
|
plRemoveArgs[1].Value <<= rInfo.ID;
|
|
m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
|
|
}
|
|
}
|
|
|
|
void RecoveryCore::forgetAllRecoveryEntries()
|
|
{
|
|
if (!m_xRealCore.is())
|
|
return;
|
|
|
|
css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
|
|
css::uno::Sequence< css::beans::PropertyValue > lRemoveArgs(2);
|
|
auto plRemoveArgs = lRemoveArgs.getArray();
|
|
plRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
|
|
plRemoveArgs[0].Value <<= false;
|
|
plRemoveArgs[1].Name = PROP_ENTRYID;
|
|
// lRemoveArgs[1].Value will be changed during next loop ...
|
|
|
|
// work on a copied list only ...
|
|
// Reason: We will get notifications from the core for every
|
|
// changed or removed element. And that will change our m_lURLs list.
|
|
// That's not a good idea, if we use a stl iterator inbetween .-)
|
|
TURLList lURLs = m_lURLs;
|
|
for (const TURLInfo& rInfo : lURLs)
|
|
{
|
|
plRemoveArgs[1].Value <<= rInfo.ID;
|
|
m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
|
|
}
|
|
}
|
|
|
|
|
|
void RecoveryCore::forgetBrokenRecoveryEntries()
|
|
{
|
|
if (!m_xRealCore.is())
|
|
return;
|
|
|
|
css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
|
|
css::uno::Sequence< css::beans::PropertyValue > lRemoveArgs(2);
|
|
auto plRemoveArgs = lRemoveArgs.getArray();
|
|
plRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
|
|
plRemoveArgs[0].Value <<= false;
|
|
plRemoveArgs[1].Name = PROP_ENTRYID;
|
|
// lRemoveArgs[1].Value will be changed during next loop ...
|
|
|
|
// work on a copied list only ...
|
|
// Reason: We will get notifications from the core for every
|
|
// changed or removed element. And that will change our m_lURLs list.
|
|
// That's not a good idea, if we use a stl iterator inbetween .-)
|
|
TURLList lURLs = m_lURLs;
|
|
for (const TURLInfo& rInfo : lURLs)
|
|
{
|
|
if (!RecoveryCore::isBrokenTempEntry(rInfo))
|
|
continue;
|
|
|
|
plRemoveArgs[1].Value <<= rInfo.ID;
|
|
m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
|
|
}
|
|
}
|
|
|
|
|
|
void RecoveryCore::setProgressHandler(const css::uno::Reference< css::task::XStatusIndicator >& xProgress)
|
|
{
|
|
m_xProgress = xProgress;
|
|
}
|
|
|
|
|
|
void RecoveryCore::setUpdateListener(IRecoveryUpdateListener* pListener)
|
|
{
|
|
m_pListener = pListener;
|
|
}
|
|
|
|
|
|
void RecoveryCore::doEmergencySavePrepare()
|
|
{
|
|
if (!m_xRealCore.is())
|
|
return;
|
|
|
|
css::util::URL aURL = impl_getParsedURL(RECOVERY_CMD_DO_PREPARE_EMERGENCY_SAVE);
|
|
|
|
css::uno::Sequence< css::beans::PropertyValue > lArgs{ comphelper::makePropertyValue(
|
|
PROP_DISPATCHASYNCHRON, false) };
|
|
|
|
m_xRealCore->dispatch(aURL, lArgs);
|
|
}
|
|
|
|
|
|
void RecoveryCore::doEmergencySave()
|
|
{
|
|
if (!m_xRealCore.is())
|
|
return;
|
|
|
|
css::util::URL aURL = impl_getParsedURL(RECOVERY_CMD_DO_EMERGENCY_SAVE);
|
|
|
|
css::uno::Sequence< css::beans::PropertyValue > lArgs{
|
|
comphelper::makePropertyValue(PROP_STATUSINDICATOR, m_xProgress),
|
|
comphelper::makePropertyValue(PROP_DISPATCHASYNCHRON, true)
|
|
};
|
|
|
|
m_xRealCore->dispatch(aURL, lArgs);
|
|
}
|
|
|
|
|
|
void RecoveryCore::doRecovery()
|
|
{
|
|
if (!m_xRealCore.is())
|
|
return;
|
|
|
|
forgetAllRecoveryEntriesMarkedForDiscard();
|
|
|
|
css::util::URL aURL = impl_getParsedURL(RECOVERY_CMD_DO_RECOVERY);
|
|
|
|
css::uno::Sequence< css::beans::PropertyValue > lArgs{
|
|
comphelper::makePropertyValue(PROP_STATUSINDICATOR, m_xProgress),
|
|
comphelper::makePropertyValue(PROP_DISPATCHASYNCHRON, true)
|
|
};
|
|
|
|
m_xRealCore->dispatch(aURL, lArgs);
|
|
}
|
|
|
|
|
|
ERecoveryState RecoveryCore::mapDocState2RecoverState(EDocStates eDocState)
|
|
{
|
|
// ???
|
|
ERecoveryState eRecState = E_NOT_RECOVERED_YET;
|
|
|
|
/* Attention:
|
|
Some of the following states can occur at the
|
|
same time. So we have to check for the "worst case" first!
|
|
|
|
DAMAGED -> INCOMPLETE -> HANDLED
|
|
*/
|
|
|
|
// running ...
|
|
if (
|
|
(eDocState & EDocStates::TryLoadBackup ) ||
|
|
(eDocState & EDocStates::TryLoadOriginal)
|
|
)
|
|
eRecState = E_RECOVERY_IS_IN_PROGRESS;
|
|
// red
|
|
else if (eDocState & EDocStates::Damaged)
|
|
eRecState = E_RECOVERY_FAILED;
|
|
// yellow
|
|
else if (eDocState & EDocStates::Incomplete)
|
|
eRecState = E_ORIGINAL_DOCUMENT_RECOVERED;
|
|
// green
|
|
else if (eDocState & EDocStates::Succeeded)
|
|
eRecState = E_SUCCESSFULLY_RECOVERED;
|
|
|
|
return eRecState;
|
|
}
|
|
|
|
|
|
void SAL_CALL RecoveryCore::statusChanged(const css::frame::FeatureStateEvent& aEvent)
|
|
{
|
|
// a) special notification about start/stop async dispatch!
|
|
// FeatureDescriptor = "start" || "stop"
|
|
if (aEvent.FeatureDescriptor == RECOVERY_OPERATIONSTATE_START)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (aEvent.FeatureDescriptor == RECOVERY_OPERATIONSTATE_STOP)
|
|
{
|
|
if (m_pListener)
|
|
m_pListener->end();
|
|
return;
|
|
}
|
|
|
|
// b) normal notification about changed items
|
|
// FeatureDescriptor = "Update"
|
|
// State = List of information [seq< NamedValue >]
|
|
if (aEvent.FeatureDescriptor != RECOVERY_OPERATIONSTATE_UPDATE)
|
|
return;
|
|
|
|
::comphelper::SequenceAsHashMap lInfo(aEvent.State);
|
|
TURLInfo aNew;
|
|
|
|
aNew.ID = lInfo.getUnpackedValueOrDefault(STATEPROP_ID , sal_Int32(0) );
|
|
aNew.DocState = static_cast<EDocStates>(lInfo.getUnpackedValueOrDefault(STATEPROP_STATE , sal_Int32(0) ));
|
|
aNew.OrgURL = lInfo.getUnpackedValueOrDefault(STATEPROP_ORGURL , OUString());
|
|
aNew.TempURL = lInfo.getUnpackedValueOrDefault(STATEPROP_TEMPURL , OUString());
|
|
aNew.FactoryURL = lInfo.getUnpackedValueOrDefault(STATEPROP_FACTORYURL , OUString());
|
|
aNew.TemplateURL = lInfo.getUnpackedValueOrDefault(STATEPROP_TEMPLATEURL, OUString());
|
|
aNew.DisplayName = lInfo.getUnpackedValueOrDefault(STATEPROP_TITLE , OUString());
|
|
aNew.Module = lInfo.getUnpackedValueOrDefault(STATEPROP_MODULE , OUString());
|
|
|
|
if (aNew.OrgURL.isEmpty()) {
|
|
// If there is no file URL, the window title is used for the display name.
|
|
// Remove any unwanted elements such as " - LibreOffice Writer".
|
|
sal_Int32 i = aNew.DisplayName.indexOf(" - ");
|
|
if (i > 0)
|
|
aNew.DisplayName = aNew.DisplayName.copy(0, i);
|
|
} else {
|
|
// If there is a file URL, parse out the filename part as the display name.
|
|
INetURLObject aOrgURL(aNew.OrgURL);
|
|
aNew.DisplayName = aOrgURL.getName(INetURLObject::LAST_SEGMENT, true,
|
|
INetURLObject::DecodeMechanism::WithCharset);
|
|
}
|
|
|
|
// search for already existing items and update her nState value ...
|
|
for (TURLInfo& aOld : m_lURLs)
|
|
{
|
|
if (aOld.ID == aNew.ID)
|
|
{
|
|
// change existing
|
|
aOld.DocState = aNew.DocState;
|
|
aOld.RecoveryState = RecoveryCore::mapDocState2RecoverState(aOld.DocState);
|
|
if (m_pListener)
|
|
{
|
|
m_pListener->updateItems();
|
|
m_pListener->stepNext(&aOld);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
// append as new one
|
|
// TODO think about matching Module name to a corresponding icon
|
|
OUString sURL = aNew.OrgURL;
|
|
if (sURL.isEmpty())
|
|
sURL = aNew.FactoryURL;
|
|
if (sURL.isEmpty())
|
|
sURL = aNew.TempURL;
|
|
if (sURL.isEmpty())
|
|
sURL = aNew.TemplateURL;
|
|
INetURLObject aURL(sURL);
|
|
aNew.StandardImageId = SvFileInformationManager::GetFileImageId(aURL);
|
|
|
|
/* set the right UI state for this item to NOT_RECOVERED_YET... because nDocState shows the state of
|
|
the last emergency save operation before and is interesting for the used recovery core service only...
|
|
for now! But if there is a further notification for this item (see lines above!) we must
|
|
map the doc state to an UI state. */
|
|
aNew.RecoveryState = E_NOT_RECOVERED_YET;
|
|
|
|
m_lURLs.push_back(aNew);
|
|
|
|
if (m_pListener)
|
|
m_pListener->updateItems();
|
|
}
|
|
|
|
|
|
void SAL_CALL RecoveryCore::disposing(const css::lang::EventObject& /*aEvent*/)
|
|
{
|
|
m_xRealCore.clear();
|
|
}
|
|
|
|
|
|
void RecoveryCore::impl_startListening()
|
|
{
|
|
// listening already initialized ?
|
|
if (m_xRealCore.is())
|
|
return;
|
|
m_xRealCore = css::frame::theAutoRecovery::get(m_xContext);
|
|
|
|
css::util::URL aURL;
|
|
if (m_bListenForSaving)
|
|
aURL.Complete = RECOVERY_CMD_DO_EMERGENCY_SAVE;
|
|
else
|
|
aURL.Complete = RECOVERY_CMD_DO_RECOVERY;
|
|
css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
|
|
xParser->parseStrict(aURL);
|
|
|
|
/* Note: addStatusListener() call us synchronous back ... so we
|
|
will get the complete list of currently open documents! */
|
|
m_xRealCore->addStatusListener(static_cast< css::frame::XStatusListener* >(this), aURL);
|
|
}
|
|
|
|
|
|
void RecoveryCore::impl_stopListening()
|
|
{
|
|
// Ignore it, if this instance doesn't listen currently
|
|
if (!m_xRealCore.is())
|
|
return;
|
|
|
|
css::util::URL aURL;
|
|
if (m_bListenForSaving)
|
|
aURL.Complete = RECOVERY_CMD_DO_EMERGENCY_SAVE;
|
|
else
|
|
aURL.Complete = RECOVERY_CMD_DO_RECOVERY;
|
|
css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
|
|
xParser->parseStrict(aURL);
|
|
|
|
m_xRealCore->removeStatusListener(static_cast< css::frame::XStatusListener* >(this), aURL);
|
|
m_xRealCore.clear();
|
|
}
|
|
|
|
|
|
css::util::URL RecoveryCore::impl_getParsedURL(const OUString& sURL)
|
|
{
|
|
css::util::URL aURL;
|
|
aURL.Complete = sURL;
|
|
|
|
css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
|
|
xParser->parseStrict(aURL);
|
|
|
|
return aURL;
|
|
}
|
|
|
|
PluginProgress::PluginProgress(weld::ProgressBar* pProgressBar)
|
|
: m_pProgressBar(pProgressBar)
|
|
, m_nRange(100)
|
|
{
|
|
}
|
|
|
|
PluginProgress::~PluginProgress()
|
|
{
|
|
}
|
|
|
|
void SAL_CALL PluginProgress::dispose()
|
|
{
|
|
m_pProgressBar = nullptr;
|
|
}
|
|
|
|
void SAL_CALL PluginProgress::addEventListener(const css::uno::Reference< css::lang::XEventListener >& )
|
|
{
|
|
}
|
|
|
|
void SAL_CALL PluginProgress::removeEventListener( const css::uno::Reference< css::lang::XEventListener >& )
|
|
{
|
|
}
|
|
|
|
void SAL_CALL PluginProgress::start(const OUString&, sal_Int32 nRange)
|
|
{
|
|
m_nRange = nRange;
|
|
if (m_pProgressBar)
|
|
m_pProgressBar->set_percentage(0);
|
|
}
|
|
|
|
void SAL_CALL PluginProgress::end()
|
|
{
|
|
if (m_pProgressBar)
|
|
m_pProgressBar->set_percentage(m_nRange);
|
|
}
|
|
|
|
void SAL_CALL PluginProgress::setText(const OUString& rText)
|
|
{
|
|
if (m_pProgressBar)
|
|
m_pProgressBar->set_text(rText);
|
|
}
|
|
|
|
void SAL_CALL PluginProgress::setValue(sal_Int32 nValue)
|
|
{
|
|
if (m_pProgressBar)
|
|
m_pProgressBar->set_percentage((nValue * 100) / m_nRange);
|
|
}
|
|
|
|
void SAL_CALL PluginProgress::reset()
|
|
{
|
|
if (m_pProgressBar)
|
|
m_pProgressBar->set_percentage(0);
|
|
}
|
|
|
|
SaveDialog::SaveDialog(weld::Window* pParent, RecoveryCore* pCore)
|
|
: GenericDialogController(pParent, u"svx/ui/docrecoverysavedialog.ui"_ustr, u"DocRecoverySaveDialog"_ustr)
|
|
, m_pCore(pCore)
|
|
, m_xFileListLB(m_xBuilder->weld_tree_view(u"filelist"_ustr))
|
|
, m_xOkBtn(m_xBuilder->weld_button(u"ok"_ustr))
|
|
{
|
|
m_xFileListLB->set_size_request(-1, m_xFileListLB->get_height_rows(10));
|
|
|
|
// Prepare the office for the following crash save step.
|
|
// E.g. hide all open windows so the user can't influence our
|
|
// operation .-)
|
|
m_pCore->doEmergencySavePrepare();
|
|
|
|
m_xOkBtn->connect_clicked(LINK(this, SaveDialog, OKButtonHdl));
|
|
|
|
// fill listbox with current open documents
|
|
|
|
TURLList& rURLs = m_pCore->getURLListAccess();
|
|
|
|
for (const TURLInfo& rInfo : rURLs)
|
|
{
|
|
m_xFileListLB->append(u""_ustr, rInfo.DisplayName, rInfo.StandardImageId);
|
|
}
|
|
}
|
|
|
|
SaveDialog::~SaveDialog()
|
|
{
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SaveDialog, OKButtonHdl, weld::Button&, void)
|
|
{
|
|
// start crash-save with progress
|
|
std::unique_ptr<SaveProgressDialog> xProgress(new SaveProgressDialog(m_xDialog.get(), m_pCore));
|
|
short nResult = xProgress->run();
|
|
xProgress.reset();
|
|
|
|
// if "CANCEL" => return "CANCEL"
|
|
// if "OK" => request a restart always!
|
|
if (nResult == DLG_RET_OK)
|
|
nResult = DLG_RET_OK_AUTOLAUNCH;
|
|
|
|
m_xDialog->response(nResult);
|
|
}
|
|
|
|
SaveProgressDialog::SaveProgressDialog(weld::Window* pParent, RecoveryCore* pCore)
|
|
: GenericDialogController(pParent, u"svx/ui/docrecoveryprogressdialog.ui"_ustr, u"DocRecoveryProgressDialog"_ustr)
|
|
, m_pCore(pCore)
|
|
, m_xProgressBar(m_xBuilder->weld_progress_bar(u"progress"_ustr))
|
|
{
|
|
m_xProgressBar->set_size_request(m_xProgressBar->get_approximate_digit_width() * 50, -1);
|
|
m_xProgress = new PluginProgress(m_xProgressBar.get());
|
|
}
|
|
|
|
SaveProgressDialog::~SaveProgressDialog()
|
|
{
|
|
if (m_xProgress)
|
|
m_xProgress->dispose();
|
|
}
|
|
|
|
short SaveProgressDialog::run()
|
|
{
|
|
::SolarMutexGuard aLock;
|
|
|
|
m_pCore->setProgressHandler(m_xProgress);
|
|
m_pCore->setUpdateListener(this);
|
|
m_pCore->doEmergencySave();
|
|
short nRet = DialogController::run();
|
|
m_pCore->setUpdateListener(nullptr);
|
|
return nRet;
|
|
}
|
|
|
|
void SaveProgressDialog::updateItems()
|
|
{
|
|
}
|
|
|
|
void SaveProgressDialog::stepNext(TURLInfo* )
|
|
{
|
|
/* TODO
|
|
|
|
if m_pCore would have a member m_mCurrentItem, you could see,
|
|
who is current, who is next ... You can show this information
|
|
in progress report FixText
|
|
*/
|
|
}
|
|
|
|
void SaveProgressDialog::end()
|
|
{
|
|
m_xDialog->response(DLG_RET_OK);
|
|
}
|
|
|
|
static short impl_askUserForWizardCancel(weld::Widget* pParent, TranslateId pRes)
|
|
{
|
|
std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(pParent,
|
|
VclMessageType::Question, VclButtonsType::YesNo, SvxResId(pRes)));
|
|
if (xQuery->run() == RET_YES)
|
|
return DLG_RET_OK;
|
|
else
|
|
return DLG_RET_CANCEL;
|
|
}
|
|
|
|
RecoveryDialog::RecoveryDialog(weld::Window* pParent, RecoveryCore* pCore)
|
|
: GenericDialogController(pParent, u"svx/ui/docrecoveryrecoverdialog.ui"_ustr, u"DocRecoveryRecoverDialog"_ustr)
|
|
, m_aTitleRecoveryInProgress(SvxResId(RID_SVXSTR_RECOVERY_INPROGRESS))
|
|
, m_aRecoveryOnlyFinish (SvxResId(RID_SVXSTR_RECOVERYONLY_FINISH))
|
|
, m_aRecoveryOnlyFinishDescr(SvxResId(RID_SVXSTR_RECOVERYONLY_FINISH_DESCR))
|
|
, m_pCore(pCore)
|
|
, m_eRecoveryState(RecoveryDialog::E_RECOVERY_PREPARED)
|
|
, m_bWaitForCore(false)
|
|
, m_bWasRecoveryStarted(false)
|
|
// , m_aColumnOffset(0)
|
|
, m_aToggleCount(0)
|
|
, m_aSuccessRecovStr(SvxResId(RID_SVXSTR_SUCCESSRECOV))
|
|
, m_aOrigDocRecovStr(SvxResId(RID_SVXSTR_ORIGDOCRECOV))
|
|
, m_aRecovFailedStr(SvxResId(RID_SVXSTR_RECOVFAILED))
|
|
, m_aRecovInProgrStr(SvxResId(RID_SVXSTR_RECOVINPROGR))
|
|
, m_aNotRecovYetStr(SvxResId(RID_SVXSTR_NOTRECOVYET))
|
|
, m_aWillBeDiscStr(SvxResId(RID_SVXSTR_WILLDISCARD))
|
|
, m_xDescrFT(m_xBuilder->weld_label(u"desc"_ustr))
|
|
, m_xProgressBar(m_xBuilder->weld_progress_bar(u"progress"_ustr))
|
|
, m_xFileListLB(m_xBuilder->weld_tree_view(u"filelist"_ustr))
|
|
, m_xNextBtn(m_xBuilder->weld_button(u"next"_ustr))
|
|
, m_xCancelBtn(m_xBuilder->weld_button(u"cancel"_ustr))
|
|
{
|
|
const auto nWidth = m_xFileListLB->get_approximate_digit_width() * 80;
|
|
m_xFileListLB->set_size_request(nWidth, m_xFileListLB->get_height_rows(10));
|
|
m_xProgressBar->set_size_request(m_xProgressBar->get_approximate_digit_width() * 50, -1);
|
|
m_xProgress = new PluginProgress(m_xProgressBar.get());
|
|
|
|
std::vector<int> aWidths;
|
|
aWidths.push_back(60 * nWidth / 100);
|
|
aWidths.push_back(5 * nWidth / 100);
|
|
m_xFileListLB->set_column_fixed_widths(aWidths);
|
|
m_xFileListLB->enable_toggle_buttons(weld::ColumnToggleType::Check);
|
|
m_xFileListLB->connect_toggled( LINK(this, RecoveryDialog, ToggleRowHdl) );
|
|
|
|
m_xNextBtn->set_sensitive(true);
|
|
m_xNextBtn->connect_clicked( LINK( this, RecoveryDialog, NextButtonHdl ) );
|
|
m_xCancelBtn->connect_clicked( LINK( this, RecoveryDialog, CancelButtonHdl ) );
|
|
|
|
// fill list box first time
|
|
TURLList& rURLList = m_pCore->getURLListAccess();
|
|
for (size_t i = 0, nCount = rURLList.size(); i < nCount; ++i)
|
|
{
|
|
const TURLInfo& rInfo = rURLList[i];
|
|
m_xFileListLB->append();
|
|
m_xFileListLB->set_toggle(i, TRISTATE_TRUE);
|
|
m_xFileListLB->set_id(i, weld::toId(&rInfo));
|
|
m_xFileListLB->set_image(i, rInfo.StandardImageId, COLUMN_STANDARDIMAGE);
|
|
m_xFileListLB->set_text(i, rInfo.DisplayName, COLUMN_DISPLAYNAME);
|
|
m_xFileListLB->set_image(i, impl_getStatusImage(rInfo), COLUMN_STATUSIMAGE);
|
|
m_xFileListLB->set_text(i, impl_getStatusString(rInfo), COLUMN_STATUSTEXT);
|
|
m_aToggleCount++;
|
|
}
|
|
|
|
// mark first item
|
|
if (m_xFileListLB->n_children())
|
|
m_xFileListLB->set_cursor(0);
|
|
}
|
|
|
|
RecoveryDialog::~RecoveryDialog()
|
|
{
|
|
if (m_xProgress)
|
|
m_xProgress->dispose();
|
|
}
|
|
|
|
bool RecoveryDialog::allSuccessfullyRecovered()
|
|
{
|
|
const int c = m_xFileListLB->n_children();
|
|
for (int i = 0; i < c; ++i)
|
|
{
|
|
TURLInfo* pInfo = weld::fromId<TURLInfo*>(m_xFileListLB->get_id(i));
|
|
if (!pInfo)
|
|
continue;
|
|
|
|
if (pInfo->RecoveryState != E_SUCCESSFULLY_RECOVERED)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
short RecoveryDialog::execute()
|
|
{
|
|
::SolarMutexGuard aSolarLock;
|
|
|
|
switch (m_eRecoveryState)
|
|
{
|
|
case RecoveryDialog::E_RECOVERY_IN_PROGRESS :
|
|
{
|
|
// user decided to start recovery ...
|
|
m_bWasRecoveryStarted = true;
|
|
// do it asynchronous (to allow repaints)
|
|
// and wait for this asynchronous operation.
|
|
m_xDescrFT->set_label( m_aTitleRecoveryInProgress );
|
|
m_xNextBtn->set_sensitive(false);
|
|
m_xCancelBtn->set_sensitive(false);
|
|
m_pCore->setProgressHandler(m_xProgress);
|
|
m_pCore->setUpdateListener(this);
|
|
m_pCore->doRecovery();
|
|
|
|
m_bWaitForCore = true;
|
|
while(m_bWaitForCore && !Application::IsQuit())
|
|
Application::Yield();
|
|
|
|
m_pCore->setUpdateListener(nullptr);
|
|
|
|
// Skip FINISH button if everything was successfully recovered
|
|
if (allSuccessfullyRecovered())
|
|
m_eRecoveryState = RecoveryDialog::E_RECOVERY_DONE;
|
|
else
|
|
m_eRecoveryState = RecoveryDialog::E_RECOVERY_CORE_DONE;
|
|
return execute();
|
|
}
|
|
|
|
case RecoveryDialog::E_RECOVERY_CORE_DONE :
|
|
{
|
|
// the core finished it's task.
|
|
// let the user decide the next step.
|
|
m_xDescrFT->set_label(m_aRecoveryOnlyFinishDescr);
|
|
m_xNextBtn->set_label(m_aRecoveryOnlyFinish);
|
|
m_xNextBtn->set_sensitive(true);
|
|
m_xCancelBtn->set_sensitive(false);
|
|
return 0;
|
|
}
|
|
|
|
case RecoveryDialog::E_RECOVERY_DONE :
|
|
{
|
|
// All documents were recovered.
|
|
// User decided to step to the "next" wizard page.
|
|
// Do it ... but check first, if there exist some
|
|
// failed recovery documents. They must be saved to
|
|
// a user selected directory.
|
|
short nRet = DLG_RET_UNKNOWN;
|
|
BrokenRecoveryDialog aBrokenRecoveryDialog(m_xDialog.get(), m_pCore, !m_bWasRecoveryStarted);
|
|
OUString sSaveDir = aBrokenRecoveryDialog.getSaveDirURL(); // get the default dir
|
|
if (aBrokenRecoveryDialog.isExecutionNeeded())
|
|
{
|
|
nRet = aBrokenRecoveryDialog.run();
|
|
sSaveDir = aBrokenRecoveryDialog.getSaveDirURL();
|
|
}
|
|
|
|
switch(nRet)
|
|
{
|
|
// no broken temp files exists
|
|
// step to the next wizard page
|
|
case DLG_RET_UNKNOWN :
|
|
{
|
|
m_eRecoveryState = RecoveryDialog::E_RECOVERY_HANDLED;
|
|
return DLG_RET_OK;
|
|
}
|
|
|
|
// user decided to save the broken temp files
|
|
// do and forget it
|
|
// step to the next wizard page
|
|
case DLG_RET_OK :
|
|
{
|
|
m_pCore->saveBrokenTempEntries(sSaveDir);
|
|
m_pCore->forgetBrokenTempEntries();
|
|
m_eRecoveryState = RecoveryDialog::E_RECOVERY_HANDLED;
|
|
return DLG_RET_OK;
|
|
}
|
|
|
|
// user decided to ignore broken temp files.
|
|
// Ask it again ... may be this decision was wrong.
|
|
// Results:
|
|
// IGNORE => remove broken temp files
|
|
// => step to the next wizard page
|
|
// CANCEL => step back to the recovery page
|
|
case DLG_RET_CANCEL :
|
|
{
|
|
// TODO ask user ...
|
|
m_pCore->forgetBrokenTempEntries();
|
|
m_eRecoveryState = RecoveryDialog::E_RECOVERY_HANDLED;
|
|
return DLG_RET_OK;
|
|
}
|
|
}
|
|
|
|
m_eRecoveryState = RecoveryDialog::E_RECOVERY_HANDLED;
|
|
return DLG_RET_OK;
|
|
}
|
|
|
|
case RecoveryDialog::E_RECOVERY_CANCELED :
|
|
{
|
|
// "YES" => break recovery
|
|
// But there exist different states, where "cancel" can be called.
|
|
// Handle it different.
|
|
if (m_bWasRecoveryStarted)
|
|
m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED_AFTERWARDS;
|
|
else
|
|
m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED_BEFORE;
|
|
return execute();
|
|
}
|
|
|
|
case RecoveryDialog::E_RECOVERY_CANCELED_BEFORE :
|
|
case RecoveryDialog::E_RECOVERY_CANCELED_AFTERWARDS :
|
|
{
|
|
// We have to check if there exists some temp. files.
|
|
// They should be saved to a user defined location.
|
|
// If no temp files exists or user decided to ignore it ...
|
|
// we have to remove all recovery/session data anyway!
|
|
short nRet = DLG_RET_UNKNOWN;
|
|
BrokenRecoveryDialog aBrokenRecoveryDialog(m_xDialog.get(), m_pCore, !m_bWasRecoveryStarted);
|
|
OUString sSaveDir = aBrokenRecoveryDialog.getSaveDirURL(); // get the default save location
|
|
|
|
// dialog itself checks if there is a need to copy files for this mode.
|
|
// It uses the information m_bWasRecoveryStarted doing so.
|
|
if (aBrokenRecoveryDialog.isExecutionNeeded())
|
|
{
|
|
nRet = aBrokenRecoveryDialog.run();
|
|
sSaveDir = aBrokenRecoveryDialog.getSaveDirURL();
|
|
}
|
|
|
|
// Possible states:
|
|
// a) nRet == DLG_RET_UNKNOWN
|
|
// dialog was not shown ...
|
|
// because there exists no temp file for copy.
|
|
// => remove all recovery data
|
|
// b) nRet == DLG_RET_OK
|
|
// dialog was shown ...
|
|
// user decided to save temp files
|
|
// => save all OR broken temp files (depends from the time, where cancel was called)
|
|
// => remove all recovery data
|
|
// c) nRet == DLG_RET_CANCEL
|
|
// dialog was shown ...
|
|
// user decided to ignore temp files
|
|
// => remove all recovery data
|
|
// => a)/c) are the same ... b) has one additional operation
|
|
|
|
// b)
|
|
if (nRet == DLG_RET_OK)
|
|
{
|
|
if (m_bWasRecoveryStarted)
|
|
m_pCore->saveBrokenTempEntries(sSaveDir);
|
|
else
|
|
m_pCore->saveAllTempEntries(sSaveDir);
|
|
}
|
|
|
|
// a,b,c)
|
|
if (m_bWasRecoveryStarted)
|
|
m_pCore->forgetBrokenRecoveryEntries();
|
|
else
|
|
m_pCore->forgetAllRecoveryEntries();
|
|
m_eRecoveryState = RecoveryDialog::E_RECOVERY_HANDLED;
|
|
|
|
// THERE IS NO WAY BACK. see impl_askUserForWizardCancel()!
|
|
return DLG_RET_CANCEL;
|
|
}
|
|
}
|
|
|
|
// should never be reached .-)
|
|
OSL_FAIL("Should never be reached!");
|
|
return DLG_RET_OK;
|
|
}
|
|
|
|
void RecoveryDialog::updateItems()
|
|
{
|
|
int c = m_xFileListLB->n_children();
|
|
for (int i = 0; i < c; ++i)
|
|
{
|
|
TURLInfo* pInfo = weld::fromId<TURLInfo*>(m_xFileListLB->get_id(i));
|
|
if ( !pInfo )
|
|
continue;
|
|
|
|
m_xFileListLB->set_image(i, impl_getStatusImage(*pInfo), COLUMN_STATUSIMAGE);
|
|
OUString sStatus = impl_getStatusString( *pInfo );
|
|
if (!sStatus.isEmpty())
|
|
m_xFileListLB->set_text(i, sStatus, COLUMN_STATUSTEXT);
|
|
}
|
|
}
|
|
|
|
void RecoveryDialog::stepNext(TURLInfo* pItem)
|
|
{
|
|
int c = m_xFileListLB->n_children();
|
|
for (int i=0; i < c; ++i)
|
|
{
|
|
TURLInfo* pInfo = weld::fromId<TURLInfo*>(m_xFileListLB->get_id(i));
|
|
if (pInfo->ID != pItem->ID)
|
|
continue;
|
|
|
|
m_xFileListLB->set_cursor(i);
|
|
m_xFileListLB->scroll_to_row(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void RecoveryDialog::end()
|
|
{
|
|
m_bWaitForCore = false;
|
|
}
|
|
|
|
IMPL_LINK_NOARG(RecoveryDialog, NextButtonHdl, weld::Button&, void)
|
|
{
|
|
switch (m_eRecoveryState)
|
|
{
|
|
case RecoveryDialog::E_RECOVERY_PREPARED:
|
|
m_eRecoveryState = RecoveryDialog::E_RECOVERY_IN_PROGRESS;
|
|
execute();
|
|
break;
|
|
case RecoveryDialog::E_RECOVERY_CORE_DONE:
|
|
m_eRecoveryState = RecoveryDialog::E_RECOVERY_DONE;
|
|
execute();
|
|
break;
|
|
}
|
|
|
|
if (m_eRecoveryState == RecoveryDialog::E_RECOVERY_HANDLED)
|
|
{
|
|
m_xDialog->response(DLG_RET_OK);
|
|
}
|
|
}
|
|
|
|
IMPL_LINK_NOARG(RecoveryDialog, CancelButtonHdl, weld::Button&, void)
|
|
{
|
|
switch (m_eRecoveryState)
|
|
{
|
|
case RecoveryDialog::E_RECOVERY_PREPARED:
|
|
if (impl_askUserForWizardCancel(m_xDialog.get(), RID_SVXSTR_QUERY_EXIT_RECOVERY) != DLG_RET_CANCEL)
|
|
{
|
|
m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED;
|
|
execute();
|
|
}
|
|
break;
|
|
case RecoveryDialog::E_RECOVERY_CORE_DONE:
|
|
m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED;
|
|
execute();
|
|
break;
|
|
}
|
|
|
|
if (m_eRecoveryState == RecoveryDialog::E_RECOVERY_HANDLED)
|
|
{
|
|
m_xDialog->response(RET_CANCEL);
|
|
}
|
|
}
|
|
|
|
IMPL_LINK_NOARG(RecoveryDialog, ToggleRowHdl, const weld::TreeView::iter_col&, void)
|
|
{
|
|
int aIndex = m_xFileListLB->get_selected_index();
|
|
TriState eState = m_xFileListLB->get_toggle(aIndex);
|
|
|
|
if (m_bWasRecoveryStarted)
|
|
{
|
|
switch (eState)
|
|
{
|
|
case TRISTATE_FALSE:
|
|
eState = TRISTATE_TRUE;
|
|
break;
|
|
case TRISTATE_TRUE:
|
|
eState = TRISTATE_FALSE;
|
|
break;
|
|
default:
|
|
// should never happen
|
|
assert(false);
|
|
break;
|
|
}
|
|
|
|
// revert toggle
|
|
m_xFileListLB->set_toggle(aIndex, eState);
|
|
}
|
|
else
|
|
{
|
|
impl_updateItemDescription(aIndex, eState);
|
|
|
|
switch (eState)
|
|
{
|
|
case TRISTATE_FALSE:
|
|
m_aToggleCount--;
|
|
break;
|
|
case TRISTATE_TRUE:
|
|
m_aToggleCount++;
|
|
break;
|
|
default:
|
|
// should never happen
|
|
assert(false);
|
|
break;
|
|
}
|
|
|
|
m_xNextBtn->set_sensitive(m_aToggleCount != 0);
|
|
}
|
|
}
|
|
|
|
OUString RecoveryDialog::impl_getStatusString( const TURLInfo& rInfo ) const
|
|
{
|
|
OUString sStatus;
|
|
switch ( rInfo.RecoveryState )
|
|
{
|
|
case E_SUCCESSFULLY_RECOVERED :
|
|
sStatus = m_aSuccessRecovStr;
|
|
break;
|
|
case E_ORIGINAL_DOCUMENT_RECOVERED :
|
|
sStatus = m_aOrigDocRecovStr;
|
|
break;
|
|
case E_RECOVERY_FAILED :
|
|
sStatus = m_aRecovFailedStr;
|
|
break;
|
|
case E_RECOVERY_IS_IN_PROGRESS :
|
|
sStatus = m_aRecovInProgrStr;
|
|
break;
|
|
case E_NOT_RECOVERED_YET :
|
|
sStatus = m_aNotRecovYetStr;
|
|
break;
|
|
case E_WILL_BE_DISCARDED:
|
|
sStatus = m_aWillBeDiscStr;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return sStatus;
|
|
}
|
|
|
|
OUString RecoveryDialog::impl_getStatusImage( const TURLInfo& rInfo )
|
|
{
|
|
OUString sStatus;
|
|
switch ( rInfo.RecoveryState )
|
|
{
|
|
case E_SUCCESSFULLY_RECOVERED :
|
|
sStatus = RID_SVXBMP_GREENCHECK;
|
|
break;
|
|
case E_ORIGINAL_DOCUMENT_RECOVERED :
|
|
sStatus = RID_SVXBMP_YELLOWCHECK;
|
|
break;
|
|
case E_RECOVERY_FAILED :
|
|
sStatus = RID_SVXBMP_REDCROSS;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return sStatus;
|
|
}
|
|
|
|
void RecoveryDialog::impl_updateItemDescription(int row, const TriState& rState)
|
|
{
|
|
TURLInfo* pInfo = reinterpret_cast<TURLInfo*>(m_xFileListLB->get_id(row).toInt64());
|
|
if (!pInfo)
|
|
return;
|
|
|
|
switch (rState)
|
|
{
|
|
case TRISTATE_FALSE:
|
|
pInfo->RecoveryState = ERecoveryState::E_WILL_BE_DISCARDED;
|
|
pInfo->ShouldDiscard = true;
|
|
break;
|
|
case TRISTATE_TRUE:
|
|
pInfo->RecoveryState = ERecoveryState::E_NOT_RECOVERED_YET;
|
|
pInfo->ShouldDiscard = false;
|
|
break;
|
|
default:
|
|
// should never happen
|
|
assert(false);
|
|
break;
|
|
}
|
|
|
|
OUString sStatus = impl_getStatusString(*pInfo);
|
|
if (!sStatus.isEmpty())
|
|
m_xFileListLB->set_text(row, sStatus, COLUMN_STATUSTEXT);
|
|
}
|
|
|
|
BrokenRecoveryDialog::BrokenRecoveryDialog(weld::Window* pParent,
|
|
RecoveryCore* pCore,
|
|
bool bBeforeRecovery)
|
|
: GenericDialogController(pParent, u"svx/ui/docrecoverybrokendialog.ui"_ustr, u"DocRecoveryBrokenDialog"_ustr)
|
|
, m_pCore(pCore)
|
|
, m_bBeforeRecovery(bBeforeRecovery)
|
|
, m_bExecutionNeeded(false)
|
|
, m_xFileListLB(m_xBuilder->weld_tree_view(u"filelist"_ustr))
|
|
, m_xSaveDirED(m_xBuilder->weld_entry(u"savedir"_ustr))
|
|
, m_xSaveDirBtn(m_xBuilder->weld_button(u"change"_ustr))
|
|
, m_xOkBtn(m_xBuilder->weld_button(u"ok"_ustr))
|
|
, m_xCancelBtn(m_xBuilder->weld_button(u"cancel"_ustr))
|
|
{
|
|
m_xSaveDirBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, SaveButtonHdl ) );
|
|
m_xOkBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, OkButtonHdl ) );
|
|
m_xCancelBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, CancelButtonHdl ) );
|
|
|
|
m_sSavePath = SvtPathOptions().GetWorkPath();
|
|
INetURLObject aObj( m_sSavePath );
|
|
OUString sPath;
|
|
osl::FileBase::getSystemPathFromFileURL(aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), sPath);
|
|
m_xSaveDirED->set_text(sPath);
|
|
|
|
impl_refresh();
|
|
}
|
|
|
|
BrokenRecoveryDialog::~BrokenRecoveryDialog()
|
|
{
|
|
}
|
|
|
|
void BrokenRecoveryDialog::impl_refresh()
|
|
{
|
|
m_bExecutionNeeded = false;
|
|
TURLList& rURLList = m_pCore->getURLListAccess();
|
|
for (const TURLInfo& rInfo : rURLList)
|
|
{
|
|
if (m_bBeforeRecovery)
|
|
{
|
|
// "Cancel" before recovery ->
|
|
// search for any temp files!
|
|
if (rInfo.TempURL.isEmpty())
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// "Cancel" after recovery ->
|
|
// search for broken temp files
|
|
if (!RecoveryCore::isBrokenTempEntry(rInfo))
|
|
continue;
|
|
}
|
|
|
|
m_bExecutionNeeded = true;
|
|
|
|
m_xFileListLB->append(weld::toId(&rInfo), rInfo.DisplayName, rInfo.StandardImageId);
|
|
}
|
|
m_sSavePath.clear();
|
|
m_xOkBtn->grab_focus();
|
|
}
|
|
|
|
bool BrokenRecoveryDialog::isExecutionNeeded() const
|
|
{
|
|
return m_bExecutionNeeded;
|
|
}
|
|
|
|
const OUString& BrokenRecoveryDialog::getSaveDirURL() const
|
|
{
|
|
return m_sSavePath;
|
|
}
|
|
|
|
IMPL_LINK_NOARG(BrokenRecoveryDialog, OkButtonHdl, weld::Button&, void)
|
|
{
|
|
OUString sPhysicalPath = comphelper::string::strip(m_xSaveDirED->get_text(), ' ');
|
|
OUString sURL;
|
|
osl::FileBase::getFileURLFromSystemPath( sPhysicalPath, sURL );
|
|
m_sSavePath = sURL;
|
|
while (m_sSavePath.isEmpty())
|
|
impl_askForSavePath();
|
|
|
|
m_xDialog->response(DLG_RET_OK);
|
|
}
|
|
|
|
IMPL_LINK_NOARG(BrokenRecoveryDialog, CancelButtonHdl, weld::Button&, void)
|
|
{
|
|
m_xDialog->response(RET_CANCEL);
|
|
}
|
|
|
|
IMPL_LINK_NOARG(BrokenRecoveryDialog, SaveButtonHdl, weld::Button&, void)
|
|
{
|
|
impl_askForSavePath();
|
|
}
|
|
|
|
void BrokenRecoveryDialog::impl_askForSavePath()
|
|
{
|
|
css::uno::Reference< css::ui::dialogs::XFolderPicker2 > xFolderPicker =
|
|
sfx2::createFolderPicker(m_pCore->getComponentContext(), m_xDialog.get());
|
|
|
|
INetURLObject aURL(m_sSavePath, INetProtocol::File);
|
|
xFolderPicker->setDisplayDirectory(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
|
|
short nRet = xFolderPicker->execute();
|
|
if (nRet == css::ui::dialogs::ExecutableDialogResults::OK)
|
|
{
|
|
m_sSavePath = xFolderPicker->getDirectory();
|
|
OUString sPath;
|
|
osl::FileBase::getSystemPathFromFileURL(m_sSavePath, sPath);
|
|
m_xSaveDirED->set_text(sPath);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|