LibreOffice Module svx (master) 1
docrecovery.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <svx/dialmgr.hxx>
21#include <svx/strings.hrc>
22#include <bitmaps.hlst>
23#include <docrecovery.hxx>
24
27#include <comphelper/string.hxx>
28#include <o3tl/safeint.hxx>
29#include <svtools/imagemgr.hxx>
31#include <tools/urlobj.hxx>
32#include <utility>
33#include <vcl/weld.hxx>
34#include <vcl/svapp.hxx>
35
36#include <com/sun/star/util/URL.hpp>
37#include <com/sun/star/util/XURLTransformer.hpp>
38#include <com/sun/star/frame/theAutoRecovery.hpp>
39#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp>
40#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
41#include <com/sun/star/util/URLTransformer.hpp>
42#include <osl/file.hxx>
44
46{
47
48using namespace ::osl;
49
50#define COLUMN_STANDARDIMAGE -1
51#define COLUMN_DISPLAYNAME 0
52#define COLUMN_STATUSIMAGE 1
53#define COLUMN_STATUSTEXT 2
54
55RecoveryCore::RecoveryCore(css::uno::Reference< css::uno::XComponentContext > xContext,
56 bool bUsedForSaving)
57 : m_xContext (std::move( xContext ))
58 , m_pListener ( nullptr )
59 , m_bListenForSaving(bUsedForSaving)
60{
62}
63
64
66{
68}
69
70
71const css::uno::Reference< css::uno::XComponentContext >& RecoveryCore::getComponentContext() const
72{
73 return m_xContext;
74}
75
76
78{
79 return m_lURLs;
80}
81
82
84{
85 if (rInfo.TempURL.isEmpty())
86 return false;
87
88 // Note: If the original files was recovery ... but a temp file
89 // exists ... an error inside the temp file exists!
90 if (
91 (rInfo.RecoveryState != E_RECOVERY_FAILED ) &&
93 )
94 return false;
95
96 return true;
97}
98
99
100void RecoveryCore::saveBrokenTempEntries(const OUString& rPath)
101{
102 if (rPath.isEmpty())
103 return;
104
105 if (!m_xRealCore.is())
106 return;
107
108 // prepare all needed parameters for the following dispatch() request.
109 css::util::URL aCopyURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_BACKUP);
110 css::uno::Sequence< css::beans::PropertyValue > lCopyArgs(3);
111 auto plCopyArgs = lCopyArgs.getArray();
112 plCopyArgs[0].Name = PROP_DISPATCHASYNCHRON;
113 plCopyArgs[0].Value <<= false;
114 plCopyArgs[1].Name = PROP_SAVEPATH;
115 plCopyArgs[1].Value <<= rPath;
116 plCopyArgs[2].Name = PROP_ENTRYID;
117 // lCopyArgs[2].Value will be changed during next loop...
118
119 // work on a copied list only...
120 // Reason: We will get notifications from the core for every
121 // changed or removed element. And that will change our m_lURLs list.
122 // That's not a good idea, if we use a stl iterator inbetween .-)
123 TURLList lURLs = m_lURLs;
124 for (const TURLInfo& rInfo : lURLs)
125 {
127 continue;
128
129 plCopyArgs[2].Value <<= rInfo.ID;
130 m_xRealCore->dispatch(aCopyURL, lCopyArgs);
131 }
132}
133
134
135void RecoveryCore::saveAllTempEntries(const OUString& rPath)
136{
137 if (rPath.isEmpty())
138 return;
139
140 if (!m_xRealCore.is())
141 return;
142
143 // prepare all needed parameters for the following dispatch() request.
144 css::util::URL aCopyURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_BACKUP);
145 css::uno::Sequence< css::beans::PropertyValue > lCopyArgs(3);
146 auto plCopyArgs = lCopyArgs.getArray();
147 plCopyArgs[0].Name = PROP_DISPATCHASYNCHRON;
148 plCopyArgs[0].Value <<= false;
149 plCopyArgs[1].Name = PROP_SAVEPATH;
150 plCopyArgs[1].Value <<= rPath;
151 plCopyArgs[2].Name = PROP_ENTRYID;
152 // lCopyArgs[2].Value will be changed during next loop ...
153
154 // work on a copied list only ...
155 // Reason: We will get notifications from the core for every
156 // changed or removed element. And that will change our m_lURLs list.
157 // That's not a good idea, if we use a stl iterator inbetween .-)
158 TURLList lURLs = m_lURLs;
159 for (const TURLInfo& rInfo : lURLs)
160 {
161 if (rInfo.TempURL.isEmpty())
162 continue;
163
164 plCopyArgs[2].Value <<= rInfo.ID;
165 m_xRealCore->dispatch(aCopyURL, lCopyArgs);
166 }
167}
168
169
171{
172 if (!m_xRealCore.is())
173 return;
174
175 css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
176 css::uno::Sequence< css::beans::PropertyValue > lRemoveArgs(2);
177 auto plRemoveArgs = lRemoveArgs.getArray();
178 plRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
179 plRemoveArgs[0].Value <<= false;
180 plRemoveArgs[1].Name = PROP_ENTRYID;
181 // lRemoveArgs[1].Value will be changed during next loop ...
182
183 // work on a copied list only ...
184 // Reason: We will get notifications from the core for every
185 // changed or removed element. And that will change our m_lURLs list.
186 // That's not a good idea, if we use a stl iterator inbetween .-)
187 TURLList lURLs = m_lURLs;
188 for (const TURLInfo& rInfo : lURLs)
189 {
191 continue;
192
193 plRemoveArgs[1].Value <<= rInfo.ID;
194 m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
195 }
196}
197
198// should only be called with valid m_xRealCore
200{
201 assert(m_xRealCore);
202
203 // potential to move in a separate function
204 css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
205 css::uno::Sequence<css::beans::PropertyValue> lRemoveArgs(2);
206 auto plRemoveArgs = lRemoveArgs.getArray();
207 plRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
208 plRemoveArgs[0].Value <<= false;
209 plRemoveArgs[1].Name = PROP_ENTRYID;
210
211 // work on a copied list only ...
212 // Reason: We will get notifications from the core for every
213 // changed or removed element. And that will change our m_lURLs list.
214 // That's not a good idea, if we use a stl iterator inbetween .-)
215 TURLList lURLs = m_lURLs;
216 for (const TURLInfo& rInfo : lURLs)
217 {
218 if (!rInfo.ShouldDiscard)
219 continue;
220
221 plRemoveArgs[1].Value <<= rInfo.ID;
222 m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
223 }
224}
225
227{
228 if (!m_xRealCore.is())
229 return;
230
231 css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
232 css::uno::Sequence< css::beans::PropertyValue > lRemoveArgs(2);
233 auto plRemoveArgs = lRemoveArgs.getArray();
234 plRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
235 plRemoveArgs[0].Value <<= false;
236 plRemoveArgs[1].Name = PROP_ENTRYID;
237 // lRemoveArgs[1].Value will be changed during next loop ...
238
239 // work on a copied list only ...
240 // Reason: We will get notifications from the core for every
241 // changed or removed element. And that will change our m_lURLs list.
242 // That's not a good idea, if we use a stl iterator inbetween .-)
243 TURLList lURLs = m_lURLs;
244 for (const TURLInfo& rInfo : lURLs)
245 {
246 plRemoveArgs[1].Value <<= rInfo.ID;
247 m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
248 }
249}
250
251
253{
254 if (!m_xRealCore.is())
255 return;
256
257 css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
258 css::uno::Sequence< css::beans::PropertyValue > lRemoveArgs(2);
259 auto plRemoveArgs = lRemoveArgs.getArray();
260 plRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
261 plRemoveArgs[0].Value <<= false;
262 plRemoveArgs[1].Name = PROP_ENTRYID;
263 // lRemoveArgs[1].Value will be changed during next loop ...
264
265 // work on a copied list only ...
266 // Reason: We will get notifications from the core for every
267 // changed or removed element. And that will change our m_lURLs list.
268 // That's not a good idea, if we use a stl iterator inbetween .-)
269 TURLList lURLs = m_lURLs;
270 for (const TURLInfo& rInfo : lURLs)
271 {
273 continue;
274
275 plRemoveArgs[1].Value <<= rInfo.ID;
276 m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
277 }
278}
279
280
281void RecoveryCore::setProgressHandler(const css::uno::Reference< css::task::XStatusIndicator >& xProgress)
282{
283 m_xProgress = xProgress;
284}
285
286
288{
289 m_pListener = pListener;
290}
291
292
294{
295 if (!m_xRealCore.is())
296 return;
297
299
300 css::uno::Sequence< css::beans::PropertyValue > lArgs{ comphelper::makePropertyValue(
301 PROP_DISPATCHASYNCHRON, false) };
302
303 m_xRealCore->dispatch(aURL, lArgs);
304}
305
306
308{
309 if (!m_xRealCore.is())
310 return;
311
313
314 css::uno::Sequence< css::beans::PropertyValue > lArgs{
317 };
318
319 m_xRealCore->dispatch(aURL, lArgs);
320}
321
322
324{
325 if (!m_xRealCore.is())
326 return;
327
329
331
332 css::uno::Sequence< css::beans::PropertyValue > lArgs{
335 };
336
337 m_xRealCore->dispatch(aURL, lArgs);
338}
339
340
342{
343 // ???
345
346 /* Attention:
347 Some of the following states can occur at the
348 same time. So we have to check for the "worst case" first!
349
350 DAMAGED -> INCOMPLETE -> HANDLED
351 */
352
353 // running ...
354 if (
355 (eDocState & EDocStates::TryLoadBackup ) ||
356 (eDocState & EDocStates::TryLoadOriginal)
357 )
358 eRecState = E_RECOVERY_IS_IN_PROGRESS;
359 // red
360 else if (eDocState & EDocStates::Damaged)
361 eRecState = E_RECOVERY_FAILED;
362 // yellow
363 else if (eDocState & EDocStates::Incomplete)
365 // green
366 else if (eDocState & EDocStates::Succeeded)
367 eRecState = E_SUCCESSFULLY_RECOVERED;
368
369 return eRecState;
370}
371
372
373void SAL_CALL RecoveryCore::statusChanged(const css::frame::FeatureStateEvent& aEvent)
374{
375 // a) special notification about start/stop async dispatch!
376 // FeatureDescriptor = "start" || "stop"
377 if (aEvent.FeatureDescriptor == RECOVERY_OPERATIONSTATE_START)
378 {
379 return;
380 }
381
382 if (aEvent.FeatureDescriptor == RECOVERY_OPERATIONSTATE_STOP)
383 {
384 if (m_pListener)
385 m_pListener->end();
386 return;
387 }
388
389 // b) normal notification about changed items
390 // FeatureDescriptor = "Update"
391 // State = List of information [seq< NamedValue >]
392 if (aEvent.FeatureDescriptor != RECOVERY_OPERATIONSTATE_UPDATE)
393 return;
394
396 TURLInfo aNew;
397
398 aNew.ID = lInfo.getUnpackedValueOrDefault(STATEPROP_ID , sal_Int32(0) );
399 aNew.DocState = static_cast<EDocStates>(lInfo.getUnpackedValueOrDefault(STATEPROP_STATE , sal_Int32(0) ));
400 aNew.OrgURL = lInfo.getUnpackedValueOrDefault(STATEPROP_ORGURL , OUString());
401 aNew.TempURL = lInfo.getUnpackedValueOrDefault(STATEPROP_TEMPURL , OUString());
404 aNew.DisplayName = lInfo.getUnpackedValueOrDefault(STATEPROP_TITLE , OUString());
405 aNew.Module = lInfo.getUnpackedValueOrDefault(STATEPROP_MODULE , OUString());
406
407 if (aNew.OrgURL.isEmpty()) {
408 // If there is no file URL, the window title is used for the display name.
409 // Remove any unwanted elements such as " - LibreOffice Writer".
410 sal_Int32 i = aNew.DisplayName.indexOf(" - ");
411 if (i > 0)
412 aNew.DisplayName = aNew.DisplayName.copy(0, i);
413 } else {
414 // If there is a file URL, parse out the filename part as the display name.
415 INetURLObject aOrgURL(aNew.OrgURL);
418 }
419
420 // search for already existing items and update her nState value ...
421 for (TURLInfo& aOld : m_lURLs)
422 {
423 if (aOld.ID == aNew.ID)
424 {
425 // change existing
426 aOld.DocState = aNew.DocState;
427 aOld.RecoveryState = RecoveryCore::mapDocState2RecoverState(aOld.DocState);
428 if (m_pListener)
429 {
431 m_pListener->stepNext(&aOld);
432 }
433 return;
434 }
435 }
436
437 // append as new one
438 // TODO think about matching Module name to a corresponding icon
439 OUString sURL = aNew.OrgURL;
440 if (sURL.isEmpty())
441 sURL = aNew.FactoryURL;
442 if (sURL.isEmpty())
443 sURL = aNew.TempURL;
444 if (sURL.isEmpty())
445 sURL = aNew.TemplateURL;
446 INetURLObject aURL(sURL);
448
449 /* set the right UI state for this item to NOT_RECOVERED_YET... because nDocState shows the state of
450 the last emergency save operation before and is interesting for the used recovery core service only...
451 for now! But if there is a further notification for this item (see lines above!) we must
452 map the doc state to an UI state. */
454
455 m_lURLs.push_back(aNew);
456
457 if (m_pListener)
459}
460
461
462void SAL_CALL RecoveryCore::disposing(const css::lang::EventObject& /*aEvent*/)
463{
464 m_xRealCore.clear();
465}
466
467
469{
470 // listening already initialized ?
471 if (m_xRealCore.is())
472 return;
473 m_xRealCore = css::frame::theAutoRecovery::get(m_xContext);
474
475 css::util::URL aURL;
478 else
480 css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
481 xParser->parseStrict(aURL);
482
483 /* Note: addStatusListener() call us synchronous back ... so we
484 will get the complete list of currently open documents! */
485 m_xRealCore->addStatusListener(static_cast< css::frame::XStatusListener* >(this), aURL);
486}
487
488
490{
491 // Ignore it, if this instance doesn't listen currently
492 if (!m_xRealCore.is())
493 return;
494
495 css::util::URL aURL;
498 else
500 css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
501 xParser->parseStrict(aURL);
502
503 m_xRealCore->removeStatusListener(static_cast< css::frame::XStatusListener* >(this), aURL);
504 m_xRealCore.clear();
505}
506
507
508css::util::URL RecoveryCore::impl_getParsedURL(const OUString& sURL)
509{
510 css::util::URL aURL;
511 aURL.Complete = sURL;
512
513 css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
514 xParser->parseStrict(aURL);
515
516 return aURL;
517}
518
520 : m_pProgressBar(pProgressBar)
521 , m_nRange(100)
522{
523}
524
526{
527}
528
530{
531 m_pProgressBar = nullptr;
532}
533
534void SAL_CALL PluginProgress::addEventListener(const css::uno::Reference< css::lang::XEventListener >& )
535{
536}
537
538void SAL_CALL PluginProgress::removeEventListener( const css::uno::Reference< css::lang::XEventListener >& )
539{
540}
541
542void SAL_CALL PluginProgress::start(const OUString&, sal_Int32 nRange)
543{
544 m_nRange = nRange;
545 if (m_pProgressBar)
547}
548
549void SAL_CALL PluginProgress::end()
550{
551 if (m_pProgressBar)
553}
554
555void SAL_CALL PluginProgress::setText(const OUString& rText)
556{
557 if (m_pProgressBar)
558 m_pProgressBar->set_text(rText);
559}
560
561void SAL_CALL PluginProgress::setValue(sal_Int32 nValue)
562{
563 if (m_pProgressBar)
565}
566
568{
569 if (m_pProgressBar)
571}
572
574 : GenericDialogController(pParent, "svx/ui/docrecoverysavedialog.ui", "DocRecoverySaveDialog")
575 , m_pCore(pCore)
576 , m_xFileListLB(m_xBuilder->weld_tree_view("filelist"))
577 , m_xOkBtn(m_xBuilder->weld_button("ok"))
578{
579 m_xFileListLB->set_size_request(-1, m_xFileListLB->get_height_rows(10));
580
581 // Prepare the office for the following crash save step.
582 // E.g. hide all open windows so the user can't influence our
583 // operation .-)
585
586 m_xOkBtn->connect_clicked(LINK(this, SaveDialog, OKButtonHdl));
587
588 // fill listbox with current open documents
589
591
592 for (const TURLInfo& rInfo : rURLs)
593 {
594 m_xFileListLB->append("", rInfo.DisplayName, rInfo.StandardImageId);
595 }
596}
597
599{
600}
601
603{
604 // start crash-save with progress
605 std::unique_ptr<SaveProgressDialog> xProgress(new SaveProgressDialog(m_xDialog.get(), m_pCore));
606 short nResult = xProgress->run();
607 xProgress.reset();
608
609 // if "CANCEL" => return "CANCEL"
610 // if "OK" => "AUTOLUNCH" always !
611 if (nResult == DLG_RET_OK)
612 nResult = DLG_RET_OK_AUTOLUNCH;
613
614 m_xDialog->response(nResult);
615}
616
618 : GenericDialogController(pParent, "svx/ui/docrecoveryprogressdialog.ui", "DocRecoveryProgressDialog")
619 , m_pCore(pCore)
620 , m_xProgressBar(m_xBuilder->weld_progress_bar("progress"))
621{
622 m_xProgressBar->set_size_request(m_xProgressBar->get_approximate_digit_width() * 50, -1);
624}
625
627{
628 css::uno::Reference<css::lang::XComponent> xComp(m_xProgress, css::uno::UNO_QUERY);
629 if (xComp)
630 xComp->dispose();
631}
632
634{
635 ::SolarMutexGuard aLock;
636
640 short nRet = DialogController::run();
641 m_pCore->setUpdateListener(nullptr);
642 return nRet;
643}
644
646{
647}
648
650{
651 /* TODO
652
653 if m_pCore would have a member m_mCurrentItem, you could see,
654 who is current, who is next ... You can show this information
655 in progress report FixText
656 */
657}
658
660{
661 m_xDialog->response(DLG_RET_OK);
662}
663
665{
666 std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(pParent,
667 VclMessageType::Question, VclButtonsType::YesNo, SvxResId(pRes)));
668 if (xQuery->run() == RET_YES)
669 return DLG_RET_OK;
670 else
671 return DLG_RET_CANCEL;
672}
673
675 : GenericDialogController(pParent, "svx/ui/docrecoveryrecoverdialog.ui", "DocRecoveryRecoverDialog")
676 , m_aTitleRecoveryInProgress(SvxResId(RID_SVXSTR_RECOVERY_INPROGRESS))
677 , m_aRecoveryOnlyFinish (SvxResId(RID_SVXSTR_RECOVERYONLY_FINISH))
678 , m_aRecoveryOnlyFinishDescr(SvxResId(RID_SVXSTR_RECOVERYONLY_FINISH_DESCR))
679 , m_pCore(pCore)
680 , m_eRecoveryState(RecoveryDialog::E_RECOVERY_PREPARED)
681 , m_bWaitForCore(false)
682 , m_bWasRecoveryStarted(false)
683// , m_aColumnOffset(0)
684 , m_aToggleCount(0)
685 , m_aSuccessRecovStr(SvxResId(RID_SVXSTR_SUCCESSRECOV))
686 , m_aOrigDocRecovStr(SvxResId(RID_SVXSTR_ORIGDOCRECOV))
687 , m_aRecovFailedStr(SvxResId(RID_SVXSTR_RECOVFAILED))
688 , m_aRecovInProgrStr(SvxResId(RID_SVXSTR_RECOVINPROGR))
689 , m_aNotRecovYetStr(SvxResId(RID_SVXSTR_NOTRECOVYET))
690 , m_aWillBeDiscStr(SvxResId(RID_SVXSTR_WILLDISCARD))
691 , m_xDescrFT(m_xBuilder->weld_label("desc"))
692 , m_xProgressBar(m_xBuilder->weld_progress_bar("progress"))
693 , m_xFileListLB(m_xBuilder->weld_tree_view("filelist"))
694 , m_xNextBtn(m_xBuilder->weld_button("next"))
695 , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
696{
697 const auto nWidth = m_xFileListLB->get_approximate_digit_width() * 80;
698 m_xFileListLB->set_size_request(nWidth, m_xFileListLB->get_height_rows(10));
699 m_xProgressBar->set_size_request(m_xProgressBar->get_approximate_digit_width() * 50, -1);
701
702 std::vector<int> aWidths;
703 aWidths.push_back(60 * nWidth / 100);
704 aWidths.push_back(5 * nWidth / 100);
705 m_xFileListLB->set_column_fixed_widths(aWidths);
706 m_xFileListLB->enable_toggle_buttons(weld::ColumnToggleType::Check);
707 m_xFileListLB->connect_toggled( LINK(this, RecoveryDialog, ToggleRowHdl) );
708
709 m_xNextBtn->set_sensitive(true);
710 m_xNextBtn->connect_clicked( LINK( this, RecoveryDialog, NextButtonHdl ) );
711 m_xCancelBtn->connect_clicked( LINK( this, RecoveryDialog, CancelButtonHdl ) );
712
713 // fill list box first time
714 TURLList& rURLList = m_pCore->getURLListAccess();
715 for (size_t i = 0, nCount = rURLList.size(); i < nCount; ++i)
716 {
717 const TURLInfo& rInfo = rURLList[i];
718 m_xFileListLB->append();
719 m_xFileListLB->set_toggle(i, TRISTATE_TRUE);
720 m_xFileListLB->set_id(i, weld::toId(&rInfo));
726 }
727
728 // mark first item
729 if (m_xFileListLB->n_children())
730 m_xFileListLB->set_cursor(0);
731}
732
734{
735 css::uno::Reference<css::lang::XComponent> xComp(m_xProgress, css::uno::UNO_QUERY);
736 if (xComp)
737 xComp->dispose();
738}
739
741{
742 ::SolarMutexGuard aSolarLock;
743
744 switch (m_eRecoveryState)
745 {
747 {
748 // user decided to start recovery ...
750 // do it asynchronous (to allow repaints)
751 // and wait for this asynchronous operation.
753 m_xNextBtn->set_sensitive(false);
754 m_xCancelBtn->set_sensitive(false);
758
759 m_bWaitForCore = true;
762
763 m_pCore->setUpdateListener(nullptr);
765 return execute();
766 }
767
769 {
770 // the core finished it's task.
771 // let the user decide the next step.
774 m_xNextBtn->set_sensitive(true);
775 m_xCancelBtn->set_sensitive(false);
776 return 0;
777 }
778
780 {
781 // All documents were recovered.
782 // User decided to step to the "next" wizard page.
783 // Do it ... but check first, if there exist some
784 // failed recovery documents. They must be saved to
785 // a user selected directory.
786 short nRet = DLG_RET_UNKNOWN;
787 BrokenRecoveryDialog aBrokenRecoveryDialog(m_xDialog.get(), m_pCore, !m_bWasRecoveryStarted);
788 OUString sSaveDir = aBrokenRecoveryDialog.getSaveDirURL(); // get the default dir
789 if (aBrokenRecoveryDialog.isExecutionNeeded())
790 {
791 nRet = aBrokenRecoveryDialog.run();
792 sSaveDir = aBrokenRecoveryDialog.getSaveDirURL();
793 }
794
795 switch(nRet)
796 {
797 // no broken temp files exists
798 // step to the next wizard page
799 case DLG_RET_UNKNOWN :
800 {
802 return DLG_RET_OK;
803 }
804
805 // user decided to save the broken temp files
806 // do and forget it
807 // step to the next wizard page
808 case DLG_RET_OK :
809 {
813 return DLG_RET_OK;
814 }
815
816 // user decided to ignore broken temp files.
817 // Ask it again ... may be this decision was wrong.
818 // Results:
819 // IGNORE => remove broken temp files
820 // => step to the next wizard page
821 // CANCEL => step back to the recovery page
822 case DLG_RET_CANCEL :
823 {
824 // TODO ask user ...
827 return DLG_RET_OK;
828 }
829 }
830
832 return DLG_RET_OK;
833 }
834
836 {
837 // "YES" => break recovery
838 // But there exist different states, where "cancel" can be called.
839 // Handle it different.
842 else
844 return execute();
845 }
846
849 {
850 // We have to check if there exists some temp. files.
851 // They should be saved to a user defined location.
852 // If no temp files exists or user decided to ignore it ...
853 // we have to remove all recovery/session data anyway!
854 short nRet = DLG_RET_UNKNOWN;
855 BrokenRecoveryDialog aBrokenRecoveryDialog(m_xDialog.get(), m_pCore, !m_bWasRecoveryStarted);
856 OUString sSaveDir = aBrokenRecoveryDialog.getSaveDirURL(); // get the default save location
857
858 // dialog itself checks if there is a need to copy files for this mode.
859 // It uses the information m_bWasRecoveryStarted doing so.
860 if (aBrokenRecoveryDialog.isExecutionNeeded())
861 {
862 nRet = aBrokenRecoveryDialog.run();
863 sSaveDir = aBrokenRecoveryDialog.getSaveDirURL();
864 }
865
866 // Possible states:
867 // a) nRet == DLG_RET_UNKNOWN
868 // dialog was not shown ...
869 // because there exists no temp file for copy.
870 // => remove all recovery data
871 // b) nRet == DLG_RET_OK
872 // dialog was shown ...
873 // user decided to save temp files
874 // => save all OR broken temp files (depends from the time, where cancel was called)
875 // => remove all recovery data
876 // c) nRet == DLG_RET_CANCEL
877 // dialog was shown ...
878 // user decided to ignore temp files
879 // => remove all recovery data
880 // => a)/c) are the same ... b) has one additional operation
881
882 // b)
883 if (nRet == DLG_RET_OK)
884 {
887 else
888 m_pCore->saveAllTempEntries(sSaveDir);
889 }
890
891 // a,b,c)
894 else
897
898 // THERE IS NO WAY BACK. see impl_askUserForWizardCancel()!
899 return DLG_RET_CANCEL;
900 }
901 }
902
903 // should never be reached .-)
904 OSL_FAIL("Should never be reached!");
905 return DLG_RET_OK;
906}
907
909{
910 int c = m_xFileListLB->n_children();
911 for (int i = 0; i < c; ++i)
912 {
913 TURLInfo* pInfo = weld::fromId<TURLInfo*>(m_xFileListLB->get_id(i));
914 if ( !pInfo )
915 continue;
916
918 OUString sStatus = impl_getStatusString( *pInfo );
919 if (!sStatus.isEmpty())
920 m_xFileListLB->set_text(i, sStatus, COLUMN_STATUSTEXT);
921 }
922}
923
925{
926 int c = m_xFileListLB->n_children();
927 for (int i=0; i < c; ++i)
928 {
929 TURLInfo* pInfo = weld::fromId<TURLInfo*>(m_xFileListLB->get_id(i));
930 if (pInfo->ID != pItem->ID)
931 continue;
932
933 m_xFileListLB->set_cursor(i);
934 m_xFileListLB->scroll_to_row(i);
935 break;
936 }
937}
938
940{
941 m_bWaitForCore = false;
942}
943
945{
946 switch (m_eRecoveryState)
947 {
950 execute();
951 break;
953 m_eRecoveryState = RecoveryDialog::E_RECOVERY_DONE;
954 execute();
955 break;
956 }
957
958 if (m_eRecoveryState == RecoveryDialog::E_RECOVERY_HANDLED)
959 {
960 m_xDialog->response(DLG_RET_OK);
961 }
962}
963
965{
966 switch (m_eRecoveryState)
967 {
969 if (impl_askUserForWizardCancel(m_xDialog.get(), RID_SVXSTR_QUERY_EXIT_RECOVERY) != DLG_RET_CANCEL)
970 {
971 m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED;
972 execute();
973 }
974 break;
976 m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED;
977 execute();
978 break;
979 }
980
981 if (m_eRecoveryState == RecoveryDialog::E_RECOVERY_HANDLED)
982 {
983 m_xDialog->response(RET_CANCEL);
984 }
985}
986
988{
989 int aIndex = m_xFileListLB->get_selected_index();
990 TriState eState = m_xFileListLB->get_toggle(aIndex);
991
992 if (m_bWasRecoveryStarted)
993 {
994 switch (eState)
995 {
996 case TRISTATE_FALSE:
997 eState = TRISTATE_TRUE;
998 break;
999 case TRISTATE_TRUE:
1000 eState = TRISTATE_FALSE;
1001 break;
1002 default:
1003 // should never happen
1004 assert(false);
1005 break;
1006 }
1007
1008 // revert toggle
1009 m_xFileListLB->set_toggle(aIndex, eState);
1010 }
1011 else
1012 {
1013 impl_updateItemDescription(aIndex, eState);
1014
1015 switch (eState)
1016 {
1017 case TRISTATE_FALSE:
1018 m_aToggleCount--;
1019 break;
1020 case TRISTATE_TRUE:
1021 m_aToggleCount++;
1022 break;
1023 default:
1024 // should never happen
1025 assert(false);
1026 break;
1027 }
1028
1029 m_xNextBtn->set_sensitive(m_aToggleCount != 0);
1030 }
1031}
1032
1034{
1035 OUString sStatus;
1036 switch ( rInfo.RecoveryState )
1037 {
1039 sStatus = m_aSuccessRecovStr;
1040 break;
1042 sStatus = m_aOrigDocRecovStr;
1043 break;
1044 case E_RECOVERY_FAILED :
1045 sStatus = m_aRecovFailedStr;
1046 break;
1048 sStatus = m_aRecovInProgrStr;
1049 break;
1050 case E_NOT_RECOVERED_YET :
1051 sStatus = m_aNotRecovYetStr;
1052 break;
1054 sStatus = m_aWillBeDiscStr;
1055 break;
1056 default:
1057 break;
1058 }
1059 return sStatus;
1060}
1061
1063{
1064 OUString sStatus;
1065 switch ( rInfo.RecoveryState )
1066 {
1068 sStatus = RID_SVXBMP_GREENCHECK;
1069 break;
1071 sStatus = RID_SVXBMP_YELLOWCHECK;
1072 break;
1073 case E_RECOVERY_FAILED :
1074 sStatus = RID_SVXBMP_REDCROSS;
1075 break;
1076 default:
1077 break;
1078 }
1079 return sStatus;
1080}
1081
1083{
1084 TURLInfo* pInfo = reinterpret_cast<TURLInfo*>(m_xFileListLB->get_id(row).toInt64());
1085 if (!pInfo)
1086 return;
1087
1088 switch (rState)
1089 {
1090 case TRISTATE_FALSE:
1092 pInfo->ShouldDiscard = true;
1093 break;
1094 case TRISTATE_TRUE:
1096 pInfo->ShouldDiscard = false;
1097 break;
1098 default:
1099 // should never happen
1100 assert(false);
1101 break;
1102 }
1103
1104 OUString sStatus = impl_getStatusString(*pInfo);
1105 if (!sStatus.isEmpty())
1106 m_xFileListLB->set_text(row, sStatus, COLUMN_STATUSTEXT);
1107}
1108
1110 RecoveryCore* pCore,
1111 bool bBeforeRecovery)
1112 : GenericDialogController(pParent, "svx/ui/docrecoverybrokendialog.ui", "DocRecoveryBrokenDialog")
1113 , m_pCore(pCore)
1114 , m_bBeforeRecovery(bBeforeRecovery)
1115 , m_bExecutionNeeded(false)
1116 , m_xFileListLB(m_xBuilder->weld_tree_view("filelist"))
1117 , m_xSaveDirED(m_xBuilder->weld_entry("savedir"))
1118 , m_xSaveDirBtn(m_xBuilder->weld_button("change"))
1119 , m_xOkBtn(m_xBuilder->weld_button("ok"))
1120 , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
1121{
1122 m_xSaveDirBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, SaveButtonHdl ) );
1123 m_xOkBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, OkButtonHdl ) );
1124 m_xCancelBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, CancelButtonHdl ) );
1125
1127 INetURLObject aObj( m_sSavePath );
1128 OUString sPath;
1129 osl::FileBase::getSystemPathFromFileURL(aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), sPath);
1130 m_xSaveDirED->set_text(sPath);
1131
1132 impl_refresh();
1133}
1134
1136{
1137}
1138
1140{
1141 m_bExecutionNeeded = false;
1142 TURLList& rURLList = m_pCore->getURLListAccess();
1143 for (const TURLInfo& rInfo : rURLList)
1144 {
1146 {
1147 // "Cancel" before recovery ->
1148 // search for any temp files!
1149 if (rInfo.TempURL.isEmpty())
1150 continue;
1151 }
1152 else
1153 {
1154 // "Cancel" after recovery ->
1155 // search for broken temp files
1157 continue;
1158 }
1159
1160 m_bExecutionNeeded = true;
1161
1162 m_xFileListLB->append(weld::toId(&rInfo), rInfo.DisplayName, rInfo.StandardImageId);
1163 }
1164 m_sSavePath.clear();
1165 m_xOkBtn->grab_focus();
1166}
1167
1169{
1170 return m_bExecutionNeeded;
1171}
1172
1174{
1175 return m_sSavePath;
1176}
1177
1179{
1180 OUString sPhysicalPath = comphelper::string::strip(m_xSaveDirED->get_text(), ' ');
1181 OUString sURL;
1182 osl::FileBase::getFileURLFromSystemPath( sPhysicalPath, sURL );
1183 m_sSavePath = sURL;
1184 while (m_sSavePath.isEmpty())
1185 impl_askForSavePath();
1186
1187 m_xDialog->response(DLG_RET_OK);
1188}
1189
1191{
1192 m_xDialog->response(RET_CANCEL);
1193}
1194
1196{
1197 impl_askForSavePath();
1198}
1199
1201{
1202 css::uno::Reference< css::ui::dialogs::XFolderPicker2 > xFolderPicker =
1204
1205 INetURLObject aURL(m_sSavePath, INetProtocol::File);
1206 xFolderPicker->setDisplayDirectory(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
1207 short nRet = xFolderPicker->execute();
1208 if (nRet == css::ui::dialogs::ExecutableDialogResults::OK)
1209 {
1210 m_sSavePath = xFolderPicker->getDirectory();
1211 OUString sPath;
1212 osl::FileBase::getSystemPathFromFileURL(m_sSavePath, sPath);
1213 m_xSaveDirED->set_text(sPath);
1214 }
1215}
1216
1217}
1218
1219/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XComponentContext > m_xContext
Reference< XExecutableDialog > m_xDialog
AnyEventRef aEvent
static void Yield()
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, const ILibreOfficeKitNotifier *pNotifier=nullptr)
static bool IsQuit()
OUString getName(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true, DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
static SVT_DLLPUBLIC OUString GetFileImageId(const INetURLObject &rURL)
const OUString & GetWorkPath() const
TValueType getUnpackedValueOrDefault(const OUString &sKey, const TValueType &aDefault) const
const OUString & getSaveDirURL() const
TODO.
BrokenRecoveryDialog(weld::Window *pParent, RecoveryCore *pCore, bool bBeforeRecovery)
TODO.
std::unique_ptr< weld::Button > m_xSaveDirBtn
std::unique_ptr< weld::Button > m_xCancelBtn
std::unique_ptr< weld::Entry > m_xSaveDirED
std::unique_ptr< weld::Button > m_xOkBtn
std::unique_ptr< weld::TreeView > m_xFileListLB
virtual void stepNext(TURLInfo *pItem)=0
PluginProgress(weld::ProgressBar *pProgressBar)
virtual void SAL_CALL addEventListener(const css::uno::Reference< css::lang::XEventListener > &xListener) override
virtual void SAL_CALL setValue(sal_Int32 nValue) override
virtual void SAL_CALL setText(const OUString &sText) override
virtual void SAL_CALL start(const OUString &sText, sal_Int32 nRange) override
virtual void SAL_CALL reset() override
weld::ProgressBar * m_pProgressBar
virtual void SAL_CALL dispose() override
virtual ~PluginProgress() override
virtual void SAL_CALL end() override
virtual void SAL_CALL removeEventListener(const css::uno::Reference< css::lang::XEventListener > &xListener) override
IRecoveryUpdateListener * m_pListener
TODO.
css::uno::Reference< css::task::XStatusIndicator > m_xProgress
TODO.
TURLList & getURLListAccess()
TODO.
Definition: docrecovery.cxx:77
css::uno::Reference< css::uno::XComponentContext > m_xContext
TODO.
virtual void SAL_CALL disposing(const css::lang::EventObject &aEvent) override
void saveBrokenTempEntries(const OUString &sSaveDir)
virtual ~RecoveryCore() override
TODO.
Definition: docrecovery.cxx:65
virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent &aEvent) override
void setUpdateListener(IRecoveryUpdateListener *pListener)
TODO.
void impl_stopListening()
stop listening on the internal EmergencySave/AutoRecovery core.
static ERecoveryState mapDocState2RecoverState(EDocStates eDocState)
TODO.
void impl_startListening()
starts listening on the internal EmergencySave/AutoRecovery core.
const css::uno::Reference< css::uno::XComponentContext > & getComponentContext() const
TODO.
Definition: docrecovery.cxx:71
bool m_bListenForSaving
knows the reason, why we listen on our internal m_xRealCore member.
css::util::URL impl_getParsedURL(const OUString &sURL)
TODO.
void setProgressHandler(const css::uno::Reference< css::task::XStatusIndicator > &xProgress)
TODO.
void saveAllTempEntries(const OUString &sSaveDir)
static bool isBrokenTempEntry(const TURLInfo &rInfo)
TODO.
Definition: docrecovery.cxx:83
RecoveryCore(css::uno::Reference< css::uno::XComponentContext > xContext, bool bUsedForSaving)
TODO.
Definition: docrecovery.cxx:55
css::uno::Reference< css::frame::XDispatch > m_xRealCore
TODO.
std::unique_ptr< weld::Button > m_xCancelBtn
std::unique_ptr< weld::TreeView > m_xFileListLB
virtual void stepNext(TURLInfo *pItem) override
virtual ~RecoveryDialog() override
RecoveryDialog(weld::Window *pParent, RecoveryCore *pCore)
TODO.
OUString impl_getStatusString(const TURLInfo &rInfo) const
virtual void updateItems() override
std::unique_ptr< weld::Button > m_xNextBtn
static OUString impl_getStatusImage(const TURLInfo &rInfo)
std::unique_ptr< weld::ProgressBar > m_xProgressBar
css::uno::Reference< css::task::XStatusIndicator > m_xProgress
std::unique_ptr< weld::Label > m_xDescrFT
virtual void end() override
void impl_updateItemDescription(int row, const TriState &rState)
SaveDialog(weld::Window *pParent, RecoveryCore *pCore)
create all child controls of this dialog.
std::unique_ptr< weld::Button > m_xOkBtn
virtual ~SaveDialog() override
std::unique_ptr< weld::TreeView > m_xFileListLB
virtual void updateItems() override
css::uno::Reference< css::task::XStatusIndicator > m_xProgress
std::unique_ptr< weld::ProgressBar > m_xProgressBar
SaveProgressDialog(weld::Window *pParent, RecoveryCore *pCore)
create all child controls of this dialog.
virtual short run() override
start the emergency save operation.
virtual void stepNext(TURLInfo *pItem) override
virtual short run()
std::shared_ptr< weld::Dialog > m_xDialog
virtual void set_text(const OUString &rText)=0
virtual void set_percentage(int value)=0
std::pair< const TreeIter &, int > iter_col
int nCount
OUString SvxResId(TranslateId aId)
Definition: dialmgr.cxx:24
URL aURL
#define COLUMN_DISPLAYNAME
Definition: docrecovery.cxx:51
#define COLUMN_STATUSTEXT
Definition: docrecovery.cxx:53
#define COLUMN_STATUSIMAGE
Definition: docrecovery.cxx:52
#define COLUMN_STANDARDIMAGE
Definition: docrecovery.cxx:50
constexpr OUStringLiteral RECOVERY_CMD_DO_PREPARE_EMERGENCY_SAVE
Definition: docrecovery.hxx:40
constexpr OUStringLiteral RECOVERY_CMD_DO_EMERGENCY_SAVE
Definition: docrecovery.hxx:41
constexpr OUStringLiteral STATEPROP_ORGURL
Definition: docrecovery.hxx:53
#define DLG_RET_OK
Definition: docrecovery.hxx:65
constexpr OUStringLiteral STATEPROP_TEMPURL
Definition: docrecovery.hxx:54
constexpr OUStringLiteral STATEPROP_TITLE
Definition: docrecovery.hxx:57
constexpr OUStringLiteral RECOVERY_CMD_DO_ENTRY_BACKUP
Definition: docrecovery.hxx:43
constexpr OUStringLiteral STATEPROP_MODULE
Definition: docrecovery.hxx:58
constexpr OUStringLiteral STATEPROP_STATE
Definition: docrecovery.hxx:52
constexpr OUStringLiteral RECOVERY_CMD_DO_RECOVERY
Definition: docrecovery.hxx:42
constexpr OUStringLiteral STATEPROP_ID
Definition: docrecovery.hxx:51
constexpr OUStringLiteral RECOVERY_CMD_DO_ENTRY_CLEANUP
Definition: docrecovery.hxx:44
#define DLG_RET_UNKNOWN
Definition: docrecovery.hxx:64
#define DLG_RET_OK_AUTOLUNCH
Definition: docrecovery.hxx:67
constexpr OUStringLiteral PROP_DISPATCHASYNCHRON
Definition: docrecovery.hxx:47
#define DLG_RET_CANCEL
Definition: docrecovery.hxx:66
#define RECOVERY_OPERATIONSTATE_UPDATE
Definition: docrecovery.hxx:62
#define RECOVERY_OPERATIONSTATE_START
Definition: docrecovery.hxx:60
constexpr OUStringLiteral PROP_SAVEPATH
Definition: docrecovery.hxx:48
constexpr OUStringLiteral PROP_STATUSINDICATOR
Definition: docrecovery.hxx:46
constexpr OUStringLiteral STATEPROP_TEMPLATEURL
Definition: docrecovery.hxx:56
constexpr OUStringLiteral STATEPROP_FACTORYURL
Definition: docrecovery.hxx:55
constexpr OUStringLiteral PROP_ENTRYID
Definition: docrecovery.hxx:49
#define RECOVERY_OPERATIONSTATE_STOP
Definition: docrecovery.hxx:61
EDocStates
Definition: docrecovery.hxx:71
@ Incomplete
the Auto/Emergency saved document is not really up-to-date (some changes can be missing)
@ Succeeded
the Auto/Emergency saved document was processed successfully
@ TryLoadBackup
an action was started (saving/loading) ... Can be interesting later if the process may be was interru...
@ Damaged
the Auto/Emergency saved document isn't usable any longer
std::deque< AttacherIndex_Impl > aIndex
sal_Int16 nValue
Definition: fmsrccfg.cxx:81
TriState
TRISTATE_FALSE
TRISTATE_TRUE
OString strip(const OString &rIn, char c)
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
int i
css::uno::Reference< css::ui::dialogs::XFolderPicker2 > createFolderPicker(const css::uno::Reference< css::uno::XComponentContext > &rContext, weld::Window *pPreferredParent)
::std::vector< TURLInfo > TURLList
static short impl_askUserForWizardCancel(weld::Widget *pParent, TranslateId pRes)
IMPL_LINK_NOARG(SaveDialog, OKButtonHdl, weld::Button &, void)
OUString toId(const void *pValue)
bool ShouldDiscard
user choice to discard
OUString TemplateURL
may be the document base on a template file !?
ERecoveryState RecoveryState
ui representation for DocState!
OUString FactoryURL
a may be existing factory URL (e.g. for untitled documents)
OUString DisplayName
the pure file name, without path, disc etcpp.
OUString TempURL
the full qualified URL of the temp. file (if it's exists)
EDocStates DocState
state info as e.g. VALID, CORRUPTED, NON EXISTING ...
OUString StandardImageId
standard icon
OUString OrgURL
the full qualified document URL
OUString Module
the application module, where this document was loaded
sal_Int32 ID
unique ID, which is specified by the underlying autorecovery core!
RET_CANCEL
RET_YES