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 
26 #include <comphelper/string.hxx>
27 #include <svtools/imagemgr.hxx>
28 #include <tools/urlobj.hxx>
29 #include <vcl/weld.hxx>
30 #include <vcl/svapp.hxx>
31 
32 #include <com/sun/star/util/URL.hpp>
33 #include <com/sun/star/util/XURLTransformer.hpp>
34 #include <com/sun/star/frame/theAutoRecovery.hpp>
35 #include <com/sun/star/ui/dialogs/FolderPicker.hpp>
36 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
37 #include <com/sun/star/util/URLTransformer.hpp>
38 #include <osl/file.hxx>
39 #include <unotools/pathoptions.hxx>
40 
42 {
43 
44 using namespace ::osl;
45 
46 RecoveryCore::RecoveryCore(const css::uno::Reference< css::uno::XComponentContext >& rxContext,
47  bool bUsedForSaving)
48  : m_xContext ( rxContext )
49  , m_pListener ( nullptr )
50  , m_bListenForSaving(bUsedForSaving)
51 {
53 }
54 
55 
57 {
59 }
60 
61 
62 const css::uno::Reference< css::uno::XComponentContext >& RecoveryCore::getComponentContext() const
63 {
64  return m_xContext;
65 }
66 
67 
69 {
70  return m_lURLs;
71 }
72 
73 
75 {
76  if (rInfo.TempURL.isEmpty())
77  return false;
78 
79  // Note: If the original files was recovery ... but a temp file
80  // exists ... an error inside the temp file exists!
81  if (
82  (rInfo.RecoveryState != E_RECOVERY_FAILED ) &&
84  )
85  return false;
86 
87  return true;
88 }
89 
90 
91 void RecoveryCore::saveBrokenTempEntries(const OUString& rPath)
92 {
93  if (rPath.isEmpty())
94  return;
95 
96  if (!m_xRealCore.is())
97  return;
98 
99  // prepare all needed parameters for the following dispatch() request.
100  css::util::URL aCopyURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_BACKUP);
101  css::uno::Sequence< css::beans::PropertyValue > lCopyArgs(3);
102  lCopyArgs[0].Name = PROP_DISPATCHASYNCHRON;
103  lCopyArgs[0].Value <<= false;
104  lCopyArgs[1].Name = PROP_SAVEPATH;
105  lCopyArgs[1].Value <<= rPath;
106  lCopyArgs[2].Name = PROP_ENTRYID;
107  // lCopyArgs[2].Value will be changed during next loop...
108 
109  // work on a copied list only...
110  // Reason: We will get notifications from the core for every
111  // changed or removed element. And that will change our m_lURLs list.
112  // That's not a good idea, if we use a stl iterator inbetween .-)
113  TURLList lURLs = m_lURLs;
114  for (const TURLInfo& rInfo : lURLs)
115  {
117  continue;
118 
119  lCopyArgs[2].Value <<= rInfo.ID;
120  m_xRealCore->dispatch(aCopyURL, lCopyArgs);
121  }
122 }
123 
124 
125 void RecoveryCore::saveAllTempEntries(const OUString& rPath)
126 {
127  if (rPath.isEmpty())
128  return;
129 
130  if (!m_xRealCore.is())
131  return;
132 
133  // prepare all needed parameters for the following dispatch() request.
134  css::util::URL aCopyURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_BACKUP);
135  css::uno::Sequence< css::beans::PropertyValue > lCopyArgs(3);
136  lCopyArgs[0].Name = PROP_DISPATCHASYNCHRON;
137  lCopyArgs[0].Value <<= false;
138  lCopyArgs[1].Name = PROP_SAVEPATH;
139  lCopyArgs[1].Value <<= rPath;
140  lCopyArgs[2].Name = PROP_ENTRYID;
141  // lCopyArgs[2].Value will be changed during next loop ...
142 
143  // work on a copied list only ...
144  // Reason: We will get notifications from the core for every
145  // changed or removed element. And that will change our m_lURLs list.
146  // That's not a good idea, if we use a stl iterator inbetween .-)
147  TURLList lURLs = m_lURLs;
148  for (const TURLInfo& rInfo : lURLs)
149  {
150  if (rInfo.TempURL.isEmpty())
151  continue;
152 
153  lCopyArgs[2].Value <<= rInfo.ID;
154  m_xRealCore->dispatch(aCopyURL, lCopyArgs);
155  }
156 }
157 
158 
160 {
161  if (!m_xRealCore.is())
162  return;
163 
164  css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
165  css::uno::Sequence< css::beans::PropertyValue > lRemoveArgs(2);
166  lRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
167  lRemoveArgs[0].Value <<= false;
168  lRemoveArgs[1].Name = PROP_ENTRYID;
169  // lRemoveArgs[1].Value will be changed during next loop ...
170 
171  // work on a copied list only ...
172  // Reason: We will get notifications from the core for every
173  // changed or removed element. And that will change our m_lURLs list.
174  // That's not a good idea, if we use a stl iterator inbetween .-)
175  TURLList lURLs = m_lURLs;
176  for (const TURLInfo& rInfo : lURLs)
177  {
179  continue;
180 
181  lRemoveArgs[1].Value <<= rInfo.ID;
182  m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
183  }
184 }
185 
186 
188 {
189  if (!m_xRealCore.is())
190  return;
191 
192  css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
193  css::uno::Sequence< css::beans::PropertyValue > lRemoveArgs(2);
194  lRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
195  lRemoveArgs[0].Value <<= false;
196  lRemoveArgs[1].Name = PROP_ENTRYID;
197  // lRemoveArgs[1].Value will be changed during next loop ...
198 
199  // work on a copied list only ...
200  // Reason: We will get notifications from the core for every
201  // changed or removed element. And that will change our m_lURLs list.
202  // That's not a good idea, if we use a stl iterator inbetween .-)
203  TURLList lURLs = m_lURLs;
204  for (const TURLInfo& rInfo : lURLs)
205  {
206  lRemoveArgs[1].Value <<= rInfo.ID;
207  m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
208  }
209 }
210 
211 
213 {
214  if (!m_xRealCore.is())
215  return;
216 
217  css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
218  css::uno::Sequence< css::beans::PropertyValue > lRemoveArgs(2);
219  lRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
220  lRemoveArgs[0].Value <<= false;
221  lRemoveArgs[1].Name = PROP_ENTRYID;
222  // lRemoveArgs[1].Value will be changed during next loop ...
223 
224  // work on a copied list only ...
225  // Reason: We will get notifications from the core for every
226  // changed or removed element. And that will change our m_lURLs list.
227  // That's not a good idea, if we use a stl iterator inbetween .-)
228  TURLList lURLs = m_lURLs;
229  for (const TURLInfo& rInfo : lURLs)
230  {
232  continue;
233 
234  lRemoveArgs[1].Value <<= rInfo.ID;
235  m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
236  }
237 }
238 
239 
240 void RecoveryCore::setProgressHandler(const css::uno::Reference< css::task::XStatusIndicator >& xProgress)
241 {
242  m_xProgress = xProgress;
243 }
244 
245 
247 {
248  m_pListener = pListener;
249 }
250 
251 
253 {
254  if (!m_xRealCore.is())
255  return;
256 
258 
259  css::uno::Sequence< css::beans::PropertyValue > lArgs(1);
260  lArgs[0].Name = PROP_DISPATCHASYNCHRON;
261  lArgs[0].Value <<= false;
262 
263  m_xRealCore->dispatch(aURL, lArgs);
264 }
265 
266 
268 {
269  if (!m_xRealCore.is())
270  return;
271 
273 
274  css::uno::Sequence< css::beans::PropertyValue > lArgs(2);
275  lArgs[0].Name = PROP_STATUSINDICATOR;
276  lArgs[0].Value <<= m_xProgress;
277  lArgs[1].Name = PROP_DISPATCHASYNCHRON;
278  lArgs[1].Value <<= true;
279 
280  m_xRealCore->dispatch(aURL, lArgs);
281 }
282 
283 
285 {
286  if (!m_xRealCore.is())
287  return;
288 
290 
291  css::uno::Sequence< css::beans::PropertyValue > lArgs(2);
292  lArgs[0].Name = PROP_STATUSINDICATOR;
293  lArgs[0].Value <<= m_xProgress;
294  lArgs[1].Name = PROP_DISPATCHASYNCHRON;
295  lArgs[1].Value <<= true;
296 
297  m_xRealCore->dispatch(aURL, lArgs);
298 }
299 
300 
302 {
303  // ???
305 
306  /* Attention:
307  Some of the following states can occur at the
308  same time. So we have to check for the "worst case" first!
309 
310  DAMAGED -> INCOMPLETE -> HANDLED
311  */
312 
313  // running ...
314  if (
315  (eDocState & EDocStates::TryLoadBackup ) ||
316  (eDocState & EDocStates::TryLoadOriginal)
317  )
318  eRecState = E_RECOVERY_IS_IN_PROGRESS;
319  // red
320  else if (eDocState & EDocStates::Damaged)
321  eRecState = E_RECOVERY_FAILED;
322  // yellow
323  else if (eDocState & EDocStates::Incomplete)
324  eRecState = E_ORIGINAL_DOCUMENT_RECOVERED;
325  // green
326  else if (eDocState & EDocStates::Succeeded)
327  eRecState = E_SUCCESSFULLY_RECOVERED;
328 
329  return eRecState;
330 }
331 
332 
333 void SAL_CALL RecoveryCore::statusChanged(const css::frame::FeatureStateEvent& aEvent)
334 {
335  // a) special notification about start/stop async dispatch!
336  // FeatureDescriptor = "start" || "stop"
337  if (aEvent.FeatureDescriptor == RECOVERY_OPERATIONSTATE_START)
338  {
339  return;
340  }
341 
342  if (aEvent.FeatureDescriptor == RECOVERY_OPERATIONSTATE_STOP)
343  {
344  if (m_pListener)
345  m_pListener->end();
346  return;
347  }
348 
349  // b) normal notification about changed items
350  // FeatureDescriptor = "Update"
351  // State = List of information [seq< NamedValue >]
352  if (aEvent.FeatureDescriptor != RECOVERY_OPERATIONSTATE_UPDATE)
353  return;
354 
355  ::comphelper::SequenceAsHashMap lInfo(aEvent.State);
356  TURLInfo aNew;
357 
358  aNew.ID = lInfo.getUnpackedValueOrDefault(STATEPROP_ID , sal_Int32(0) );
359  aNew.DocState = static_cast<EDocStates>(lInfo.getUnpackedValueOrDefault(STATEPROP_STATE , sal_Int32(0) ));
360  aNew.OrgURL = lInfo.getUnpackedValueOrDefault(STATEPROP_ORGURL , OUString());
361  aNew.TempURL = lInfo.getUnpackedValueOrDefault(STATEPROP_TEMPURL , OUString());
362  aNew.FactoryURL = lInfo.getUnpackedValueOrDefault(STATEPROP_FACTORYURL , OUString());
364  aNew.DisplayName = lInfo.getUnpackedValueOrDefault(STATEPROP_TITLE , OUString());
365  aNew.Module = lInfo.getUnpackedValueOrDefault(STATEPROP_MODULE , OUString());
366 
367  if (aNew.OrgURL.isEmpty()) {
368  // If there is no file URL, the window title is used for the display name.
369  // Remove any unwanted elements such as " - LibreOffice Writer".
370  sal_Int32 i = aNew.DisplayName.indexOf(" - ");
371  if (i > 0)
372  aNew.DisplayName = aNew.DisplayName.copy(0, i);
373  } else {
374  // If there is a file URL, parse out the filename part as the display name.
375  INetURLObject aOrgURL(aNew.OrgURL);
376  aNew.DisplayName = aOrgURL.getName(INetURLObject::LAST_SEGMENT, true,
378  }
379 
380  // search for already existing items and update her nState value ...
381  for (TURLInfo& aOld : m_lURLs)
382  {
383  if (aOld.ID == aNew.ID)
384  {
385  // change existing
386  aOld.DocState = aNew.DocState;
387  aOld.RecoveryState = RecoveryCore::mapDocState2RecoverState(aOld.DocState);
388  if (m_pListener)
389  {
391  m_pListener->stepNext(&aOld);
392  }
393  return;
394  }
395  }
396 
397  // append as new one
398  // TODO think about matching Module name to a corresponding icon
399  OUString sURL = aNew.OrgURL;
400  if (sURL.isEmpty())
401  sURL = aNew.FactoryURL;
402  if (sURL.isEmpty())
403  sURL = aNew.TempURL;
404  if (sURL.isEmpty())
405  sURL = aNew.TemplateURL;
406  INetURLObject aURL(sURL);
408 
409  /* set the right UI state for this item to NOT_RECOVERED_YET... because nDocState shows the state of
410  the last emergency save operation before and is interesting for the used recovery core service only...
411  for now! But if there is a further notification for this item (see lines above!) we must
412  map the doc state to an UI state. */
414 
415  m_lURLs.push_back(aNew);
416 
417  if (m_pListener)
419 }
420 
421 
422 void SAL_CALL RecoveryCore::disposing(const css::lang::EventObject& /*aEvent*/)
423 {
424  m_xRealCore.clear();
425 }
426 
427 
429 {
430  // listening already initialized ?
431  if (m_xRealCore.is())
432  return;
433  m_xRealCore = css::frame::theAutoRecovery::get(m_xContext);
434 
435  css::util::URL aURL;
436  if (m_bListenForSaving)
437  aURL.Complete = RECOVERY_CMD_DO_EMERGENCY_SAVE;
438  else
439  aURL.Complete = RECOVERY_CMD_DO_RECOVERY;
440  css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
441  xParser->parseStrict(aURL);
442 
443  /* Note: addStatusListener() call us synchronous back ... so we
444  will get the complete list of currently open documents! */
445  m_xRealCore->addStatusListener(static_cast< css::frame::XStatusListener* >(this), aURL);
446 }
447 
448 
450 {
451  // Ignore it, if this instance doesn't listen currently
452  if (!m_xRealCore.is())
453  return;
454 
455  css::util::URL aURL;
456  if (m_bListenForSaving)
457  aURL.Complete = RECOVERY_CMD_DO_EMERGENCY_SAVE;
458  else
459  aURL.Complete = RECOVERY_CMD_DO_RECOVERY;
460  css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
461  xParser->parseStrict(aURL);
462 
463  m_xRealCore->removeStatusListener(static_cast< css::frame::XStatusListener* >(this), aURL);
464  m_xRealCore.clear();
465 }
466 
467 
468 css::util::URL RecoveryCore::impl_getParsedURL(const OUString& sURL)
469 {
470  css::util::URL aURL;
471  aURL.Complete = sURL;
472 
473  css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
474  xParser->parseStrict(aURL);
475 
476  return aURL;
477 }
478 
480  : m_pProgressBar(pProgressBar)
481  , m_nRange(100)
482 {
483 }
484 
486 {
487 }
488 
489 void SAL_CALL PluginProgress::dispose()
490 {
491  m_pProgressBar = nullptr;
492 }
493 
494 void SAL_CALL PluginProgress::addEventListener(const css::uno::Reference< css::lang::XEventListener >& )
495 {
496 }
497 
498 void SAL_CALL PluginProgress::removeEventListener( const css::uno::Reference< css::lang::XEventListener >& )
499 {
500 }
501 
502 void SAL_CALL PluginProgress::start(const OUString&, sal_Int32 nRange)
503 {
504  m_nRange = nRange;
505  if (m_pProgressBar)
507 }
508 
509 void SAL_CALL PluginProgress::end()
510 {
511  if (m_pProgressBar)
513 }
514 
515 void SAL_CALL PluginProgress::setText(const OUString& rText)
516 {
517  if (m_pProgressBar)
518  m_pProgressBar->set_text(rText);
519 }
520 
521 void SAL_CALL PluginProgress::setValue(sal_Int32 nValue)
522 {
523  if (m_pProgressBar)
524  m_pProgressBar->set_percentage((nValue * 100) / m_nRange);
525 }
526 
527 void SAL_CALL PluginProgress::reset()
528 {
529  if (m_pProgressBar)
531 }
532 
534  : GenericDialogController(pParent, "svx/ui/docrecoverysavedialog.ui", "DocRecoverySaveDialog")
535  , m_pCore(pCore)
536  , m_xFileListLB(m_xBuilder->weld_tree_view("filelist"))
537  , m_xOkBtn(m_xBuilder->weld_button("ok"))
538 {
539  m_xFileListLB->set_size_request(-1, m_xFileListLB->get_height_rows(10));
540 
541  // Prepare the office for the following crash save step.
542  // E.g. hide all open windows so the user can't influence our
543  // operation .-)
545 
546  m_xOkBtn->connect_clicked(LINK(this, SaveDialog, OKButtonHdl));
547 
548  // fill listbox with current open documents
549 
550  TURLList& rURLs = m_pCore->getURLListAccess();
551 
552  for (const TURLInfo& rInfo : rURLs)
553  {
554  m_xFileListLB->append("", rInfo.DisplayName, rInfo.StandardImageId);
555  }
556 }
557 
559 {
560 }
561 
563 {
564  // start crash-save with progress
565  std::unique_ptr<SaveProgressDialog> xProgress(new SaveProgressDialog(m_xDialog.get(), m_pCore));
566  short nResult = xProgress->run();
567  xProgress.reset();
568 
569  // if "CANCEL" => return "CANCEL"
570  // if "OK" => "AUTOLUNCH" always !
571  if (nResult == DLG_RET_OK)
572  nResult = DLG_RET_OK_AUTOLUNCH;
573 
574  m_xDialog->response(nResult);
575 }
576 
578  : GenericDialogController(pParent, "svx/ui/docrecoveryprogressdialog.ui", "DocRecoveryProgressDialog")
579  , m_pCore(pCore)
580  , m_xProgressBar(m_xBuilder->weld_progress_bar("progress"))
581 {
582  m_xProgressBar->set_size_request(m_xProgressBar->get_approximate_digit_width() * 50, -1);
583  PluginProgress* pProgress = new PluginProgress(m_xProgressBar.get());
584  m_xProgress.set(static_cast< css::task::XStatusIndicator* >(pProgress), css::uno::UNO_QUERY_THROW);
585 }
586 
588 {
589  css::uno::Reference<css::lang::XComponent> xComp(m_xProgress, css::uno::UNO_QUERY);
590  if (xComp)
591  xComp->dispose();
592 }
593 
595 {
597 
599  m_pCore->setUpdateListener(this);
601  short nRet = DialogController::run();
602  m_pCore->setUpdateListener(nullptr);
603  return nRet;
604 }
605 
607 {
608 }
609 
611 {
612  /* TODO
613 
614  if m_pCore would have a member m_mCurrentItem, you could see,
615  who is current, who is next ... You can show this information
616  in progress report FixText
617  */
618 }
619 
621 {
622  m_xDialog->response(DLG_RET_OK);
623 }
624 
625 static short impl_askUserForWizardCancel(weld::Widget* pParent, const char* pRes)
626 {
627  std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(pParent,
628  VclMessageType::Question, VclButtonsType::YesNo, SvxResId(pRes)));
629  if (xQuery->run() == RET_YES)
630  return DLG_RET_OK;
631  else
632  return DLG_RET_CANCEL;
633 }
634 
636  : GenericDialogController(pParent, "svx/ui/docrecoveryrecoverdialog.ui", "DocRecoveryRecoverDialog")
637  , m_aTitleRecoveryInProgress(SvxResId(RID_SVXSTR_RECOVERY_INPROGRESS))
638  , m_aRecoveryOnlyFinish (SvxResId(RID_SVXSTR_RECOVERYONLY_FINISH))
639  , m_aRecoveryOnlyFinishDescr(SvxResId(RID_SVXSTR_RECOVERYONLY_FINISH_DESCR))
640  , m_pCore(pCore)
641  , m_eRecoveryState(RecoveryDialog::E_RECOVERY_PREPARED)
642  , m_bWaitForCore(false)
643  , m_bWasRecoveryStarted(false)
644  , m_aSuccessRecovStr(SvxResId(RID_SVXSTR_SUCCESSRECOV))
645  , m_aOrigDocRecovStr(SvxResId(RID_SVXSTR_ORIGDOCRECOV))
646  , m_aRecovFailedStr(SvxResId(RID_SVXSTR_RECOVFAILED))
647  , m_aRecovInProgrStr(SvxResId(RID_SVXSTR_RECOVINPROGR))
648  , m_aNotRecovYetStr(SvxResId(RID_SVXSTR_NOTRECOVYET))
649  , m_xDescrFT(m_xBuilder->weld_label("desc"))
650  , m_xProgressBar(m_xBuilder->weld_progress_bar("progress"))
651  , m_xFileListLB(m_xBuilder->weld_tree_view("filelist"))
652  , m_xNextBtn(m_xBuilder->weld_button("next"))
653  , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
654 {
655  const auto nWidth = m_xFileListLB->get_approximate_digit_width() * 70;
656  m_xFileListLB->set_size_request(nWidth, m_xFileListLB->get_height_rows(10));
657  m_xProgressBar->set_size_request(m_xProgressBar->get_approximate_digit_width() * 50, -1);
658  PluginProgress* pProgress = new PluginProgress(m_xProgressBar.get());
659  m_xProgress.set(static_cast< css::task::XStatusIndicator* >(pProgress), css::uno::UNO_QUERY_THROW);
660 
661  std::vector<int> aWidths;
662  aWidths.push_back(m_xFileListLB->get_checkbox_column_width());
663  aWidths.push_back(60 * nWidth / 100);
664  aWidths.push_back(m_xFileListLB->get_checkbox_column_width());
665  m_xFileListLB->set_column_fixed_widths(aWidths);
666 
667  m_xNextBtn->set_sensitive(true);
668  m_xNextBtn->connect_clicked( LINK( this, RecoveryDialog, NextButtonHdl ) );
669  m_xCancelBtn->connect_clicked( LINK( this, RecoveryDialog, CancelButtonHdl ) );
670 
671  // fill list box first time
672  TURLList& rURLList = m_pCore->getURLListAccess();
673  for (size_t i = 0, nCount = rURLList.size(); i < nCount; ++i)
674  {
675  const TURLInfo& rInfo = rURLList[i];
676  m_xFileListLB->append();
677  m_xFileListLB->set_id(i, OUString::number(reinterpret_cast<sal_IntPtr>(&rInfo)));
678  m_xFileListLB->set_image(i, rInfo.StandardImageId, 0);
679  m_xFileListLB->set_text(i, rInfo.DisplayName, 1);
680  m_xFileListLB->set_image(i, impl_getStatusImage(rInfo), 2);
681  m_xFileListLB->set_text(i, impl_getStatusString(rInfo), 3);
682  }
683 
684  // mark first item
685  if (m_xFileListLB->n_children())
686  m_xFileListLB->set_cursor(0);
687 }
688 
690 {
691  css::uno::Reference<css::lang::XComponent> xComp(m_xProgress, css::uno::UNO_QUERY);
692  if (xComp)
693  xComp->dispose();
694 }
695 
697 {
698  ::SolarMutexGuard aSolarLock;
699 
700  switch (m_eRecoveryState)
701  {
703  {
704  // user decided to start recovery ...
705  m_bWasRecoveryStarted = true;
706  // do it asynchronous (to allow repaints)
707  // and wait for this asynchronous operation.
709  m_xNextBtn->set_sensitive(false);
710  m_xCancelBtn->set_sensitive(false);
712  m_pCore->setUpdateListener(this);
713  m_pCore->doRecovery();
714 
715  m_bWaitForCore = true;
716  while(m_bWaitForCore)
718 
719  m_pCore->setUpdateListener(nullptr);
721  return execute();
722  }
723 
725  {
726  // the core finished it's task.
727  // let the user decide the next step.
729  m_xNextBtn->set_label(m_aRecoveryOnlyFinish);
730  m_xNextBtn->set_sensitive(true);
731  m_xCancelBtn->set_sensitive(false);
732  return 0;
733  }
734 
736  {
737  // All documents were recovered.
738  // User decided to step to the "next" wizard page.
739  // Do it ... but check first, if there exist some
740  // failed recovery documents. They must be saved to
741  // a user selected directory.
742  short nRet = DLG_RET_UNKNOWN;
743  BrokenRecoveryDialog aBrokenRecoveryDialog(m_xDialog.get(), m_pCore, !m_bWasRecoveryStarted);
744  OUString sSaveDir = aBrokenRecoveryDialog.getSaveDirURL(); // get the default dir
745  if (aBrokenRecoveryDialog.isExecutionNeeded())
746  {
747  nRet = aBrokenRecoveryDialog.run();
748  sSaveDir = aBrokenRecoveryDialog.getSaveDirURL();
749  }
750 
751  switch(nRet)
752  {
753  // no broken temp files exists
754  // step to the next wizard page
755  case DLG_RET_UNKNOWN :
756  {
758  return DLG_RET_OK;
759  }
760 
761  // user decided to save the broken temp files
762  // do and forget it
763  // step to the next wizard page
764  case DLG_RET_OK :
765  {
766  m_pCore->saveBrokenTempEntries(sSaveDir);
769  return DLG_RET_OK;
770  }
771 
772  // user decided to ignore broken temp files.
773  // Ask it again ... may be this decision was wrong.
774  // Results:
775  // IGNORE => remove broken temp files
776  // => step to the next wizard page
777  // CANCEL => step back to the recovery page
778  case DLG_RET_CANCEL :
779  {
780  // TODO ask user ...
783  return DLG_RET_OK;
784  }
785  }
786 
788  return DLG_RET_OK;
789  }
790 
792  {
793  // "YES" => break recovery
794  // But there exist different states, where "cancel" can be called.
795  // Handle it different.
798  else
800  return execute();
801  }
802 
805  {
806  // We have to check if there exists some temp. files.
807  // They should be saved to a user defined location.
808  // If no temp files exists or user decided to ignore it ...
809  // we have to remove all recovery/session data anyway!
810  short nRet = DLG_RET_UNKNOWN;
811  BrokenRecoveryDialog aBrokenRecoveryDialog(m_xDialog.get(), m_pCore, !m_bWasRecoveryStarted);
812  OUString sSaveDir = aBrokenRecoveryDialog.getSaveDirURL(); // get the default save location
813 
814  // dialog itself checks if there is a need to copy files for this mode.
815  // It uses the information m_bWasRecoveryStarted doing so.
816  if (aBrokenRecoveryDialog.isExecutionNeeded())
817  {
818  nRet = aBrokenRecoveryDialog.run();
819  sSaveDir = aBrokenRecoveryDialog.getSaveDirURL();
820  }
821 
822  // Possible states:
823  // a) nRet == DLG_RET_UNKNOWN
824  // dialog was not shown ...
825  // because there exists no temp file for copy.
826  // => remove all recovery data
827  // b) nRet == DLG_RET_OK
828  // dialog was shown ...
829  // user decided to save temp files
830  // => save all OR broken temp files (depends from the time, where cancel was called)
831  // => remove all recovery data
832  // c) nRet == DLG_RET_CANCEL
833  // dialog was shown ...
834  // user decided to ignore temp files
835  // => remove all recovery data
836  // => a)/c) are the same ... b) has one additional operation
837 
838  // b)
839  if (nRet == DLG_RET_OK)
840  {
842  m_pCore->saveBrokenTempEntries(sSaveDir);
843  else
844  m_pCore->saveAllTempEntries(sSaveDir);
845  }
846 
847  // a,b,c)
850  else
853 
854  // THERE IS NO WAY BACK. see impl_askUserForWizardCancel()!
855  return DLG_RET_CANCEL;
856  }
857  }
858 
859  // should never be reached .-)
860  OSL_FAIL("Should never be reached!");
861  return DLG_RET_OK;
862 }
863 
865 {
866  int c = m_xFileListLB->n_children();
867  for (int i = 0; i < c; ++i)
868  {
869  TURLInfo* pInfo = reinterpret_cast<TURLInfo*>(m_xFileListLB->get_id(i).toInt64());
870  if ( !pInfo )
871  continue;
872 
873  m_xFileListLB->set_image(i, impl_getStatusImage(*pInfo), 2);
874  OUString sStatus = impl_getStatusString( *pInfo );
875  if (!sStatus.isEmpty())
876  m_xFileListLB->set_text(i, sStatus, 3);
877  }
878 }
879 
881 {
882  int c = m_xFileListLB->n_children();
883  for (int i=0; i < c; ++i)
884  {
885  TURLInfo* pInfo = reinterpret_cast<TURLInfo*>(m_xFileListLB->get_id(i).toInt64());
886  if (pInfo->ID != pItem->ID)
887  continue;
888 
889  m_xFileListLB->set_cursor(i);
890  m_xFileListLB->scroll_to_row(i);
891  break;
892  }
893 }
894 
896 {
897  m_bWaitForCore = false;
898 }
899 
901 {
902  switch (m_eRecoveryState)
903  {
905  m_eRecoveryState = RecoveryDialog::E_RECOVERY_IN_PROGRESS;
906  execute();
907  break;
909  m_eRecoveryState = RecoveryDialog::E_RECOVERY_DONE;
910  execute();
911  break;
912  }
913 
914  if (m_eRecoveryState == RecoveryDialog::E_RECOVERY_HANDLED)
915  {
916  m_xDialog->response(DLG_RET_OK);
917  }
918 }
919 
920 IMPL_LINK_NOARG(RecoveryDialog, CancelButtonHdl, weld::Button&, void)
921 {
922  switch (m_eRecoveryState)
923  {
925  if (impl_askUserForWizardCancel(m_xDialog.get(), RID_SVXSTR_QUERY_EXIT_RECOVERY) != DLG_RET_CANCEL)
926  {
927  m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED;
928  execute();
929  }
930  break;
932  m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED;
933  execute();
934  break;
935  }
936 
937  if (m_eRecoveryState == RecoveryDialog::E_RECOVERY_HANDLED)
938  {
939  m_xDialog->response(RET_CANCEL);
940  }
941 }
942 
943 OUString RecoveryDialog::impl_getStatusString( const TURLInfo& rInfo ) const
944 {
945  OUString sStatus;
946  switch ( rInfo.RecoveryState )
947  {
949  sStatus = m_aSuccessRecovStr;
950  break;
952  sStatus = m_aOrigDocRecovStr;
953  break;
954  case E_RECOVERY_FAILED :
955  sStatus = m_aRecovFailedStr;
956  break;
958  sStatus = m_aRecovInProgrStr;
959  break;
960  case E_NOT_RECOVERED_YET :
961  sStatus = m_aNotRecovYetStr;
962  break;
963  default:
964  break;
965  }
966  return sStatus;
967 }
968 
970 {
971  OUString sStatus;
972  switch ( rInfo.RecoveryState )
973  {
975  sStatus = RID_SVXBMP_GREENCHECK;
976  break;
978  sStatus = RID_SVXBMP_YELLOWCHECK;
979  break;
980  case E_RECOVERY_FAILED :
981  sStatus = RID_SVXBMP_REDCROSS;
982  break;
983  default:
984  break;
985  }
986  return sStatus;
987 }
988 
990  RecoveryCore* pCore,
991  bool bBeforeRecovery)
992  : GenericDialogController(pParent, "svx/ui/docrecoverybrokendialog.ui", "DocRecoveryBrokenDialog")
993  , m_pCore(pCore)
994  , m_bBeforeRecovery(bBeforeRecovery)
995  , m_bExecutionNeeded(false)
996  , m_xFileListLB(m_xBuilder->weld_tree_view("filelist"))
997  , m_xSaveDirED(m_xBuilder->weld_entry("savedir"))
998  , m_xSaveDirBtn(m_xBuilder->weld_button("change"))
999  , m_xOkBtn(m_xBuilder->weld_button("ok"))
1000  , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
1001 {
1002  m_xSaveDirBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, SaveButtonHdl ) );
1003  m_xOkBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, OkButtonHdl ) );
1004  m_xCancelBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, CancelButtonHdl ) );
1005 
1007  INetURLObject aObj( m_sSavePath );
1008  OUString sPath;
1009  osl::FileBase::getSystemPathFromFileURL(aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), sPath);
1010  m_xSaveDirED->set_text(sPath);
1011 
1012  impl_refresh();
1013 }
1014 
1016 {
1017 }
1018 
1020 {
1021  m_bExecutionNeeded = false;
1022  TURLList& rURLList = m_pCore->getURLListAccess();
1023  for (const TURLInfo& rInfo : rURLList)
1024  {
1025  if (m_bBeforeRecovery)
1026  {
1027  // "Cancel" before recovery ->
1028  // search for any temp files!
1029  if (rInfo.TempURL.isEmpty())
1030  continue;
1031  }
1032  else
1033  {
1034  // "Cancel" after recovery ->
1035  // search for broken temp files
1036  if (!RecoveryCore::isBrokenTempEntry(rInfo))
1037  continue;
1038  }
1039 
1040  m_bExecutionNeeded = true;
1041 
1042  m_xFileListLB->append(OUString::number(reinterpret_cast<sal_IntPtr>(&rInfo)), rInfo.DisplayName, rInfo.StandardImageId);
1043  }
1044  m_sSavePath.clear();
1045  m_xOkBtn->grab_focus();
1046 }
1047 
1049 {
1050  return m_bExecutionNeeded;
1051 }
1052 
1054 {
1055  return m_sSavePath;
1056 }
1057 
1059 {
1060  OUString sPhysicalPath = comphelper::string::strip(m_xSaveDirED->get_text(), ' ');
1061  OUString sURL;
1062  osl::FileBase::getFileURLFromSystemPath( sPhysicalPath, sURL );
1063  m_sSavePath = sURL;
1064  while (m_sSavePath.isEmpty())
1065  impl_askForSavePath();
1066 
1067  m_xDialog->response(DLG_RET_OK);
1068 }
1069 
1071 {
1072  m_xDialog->response(RET_CANCEL);
1073 }
1074 
1076 {
1077  impl_askForSavePath();
1078 }
1079 
1081 {
1082  css::uno::Reference< css::ui::dialogs::XFolderPicker2 > xFolderPicker =
1083  css::ui::dialogs::FolderPicker::create( m_pCore->getComponentContext() );
1084 
1085  INetURLObject aURL(m_sSavePath, INetProtocol::File);
1086  xFolderPicker->setDisplayDirectory(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
1087  short nRet = xFolderPicker->execute();
1088  if (nRet == css::ui::dialogs::ExecutableDialogResults::OK)
1089  {
1090  m_sSavePath = xFolderPicker->getDirectory();
1091  OUString sPath;
1092  osl::FileBase::getSystemPathFromFileURL(m_sSavePath, sPath);
1093  m_xSaveDirED->set_text(sPath);
1094  }
1095 }
1096 
1097 }
1098 
1099 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::shared_ptr< weld::Dialog > m_xDialog
SaveDialog(weld::Window *pParent, RecoveryCore *pCore)
create all child controls of this dialog.
URL aURL
virtual ~RecoveryCore() override
TODO.
Definition: docrecovery.cxx:56
virtual void stepNext(TURLInfo *pItem) override
#define DLG_RET_UNKNOWN
Definition: docrecovery.hxx:64
virtual void SAL_CALL removeEventListener(const css::uno::Reference< css::lang::XEventListener > &xListener) override
virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent &aEvent) override
#define RECOVERY_CMD_DO_ENTRY_BACKUP
Definition: docrecovery.hxx:43
RecoveryDialog(weld::Window *pParent, RecoveryCore *pCore)
TODO.
OUString OrgURL
the full qualified document URL
EDocStates DocState
state info as e.g. VALID, CORRUPTED, NON EXISTING ...
virtual void SAL_CALL setText(const OUString &sText) override
std::unique_ptr< weld::Button > m_xSaveDirBtn
void saveAllTempEntries(const OUString &sSaveDir)
IMPL_LINK_NOARG(SaveDialog, OKButtonHdl, weld::Button &, void)
virtual void updateItems() override
OUString Module
the application module, where this document was loaded
#define PROP_ENTRYID
Definition: docrecovery.hxx:49
virtual ~PluginProgress() override
weld::ProgressBar * m_pProgressBar
css::uno::Reference< css::task::XStatusIndicator > m_xProgress
TODO.
RET_CANCEL
virtual void SAL_CALL setValue(sal_Int32 nValue) override
OUString StandardImageId
standard icon
virtual ~SaveDialog() override
virtual void SAL_CALL start(const OUString &sText, sal_Int32 nRange) override
#define RECOVERY_OPERATIONSTATE_UPDATE
Definition: docrecovery.hxx:62
#define DLG_RET_OK_AUTOLUNCH
Definition: docrecovery.hxx:67
void saveBrokenTempEntries(const OUString &sSaveDir)
Definition: docrecovery.cxx:91
RET_YES
#define DLG_RET_CANCEL
Definition: docrecovery.hxx:66
OUString SvxResId(const char *pId)
Definition: dialmgr.cxx:28
static void Yield()
static ERecoveryState mapDocState2RecoverState(EDocStates eDocState)
TODO.
virtual void SAL_CALL disposing(const css::lang::EventObject &aEvent) override
#define STATEPROP_FACTORYURL
Definition: docrecovery.hxx:55
::std::vector< TURLInfo > TURLList
int nCount
virtual void stepNext(TURLInfo *pItem) override
virtual void SAL_CALL end() override
std::unique_ptr< weld::Button > m_xCancelBtn
OUString impl_getStatusString(const TURLInfo &rInfo) const
#define STATEPROP_TEMPLATEURL
Definition: docrecovery.hxx:56
virtual ~RecoveryDialog() override
std::unique_ptr< weld::TreeView > m_xFileListLB
virtual void SAL_CALL dispose() override
sal_Int32 ID
unique ID, which is specified by the underlying autorecovery core!
RecoveryCore(const css::uno::Reference< css::uno::XComponentContext > &rxContext, bool bUsedForSaving)
TODO.
Definition: docrecovery.cxx:46
#define STATEPROP_TEMPURL
Definition: docrecovery.hxx:54
std::unique_ptr< weld::Entry > m_xSaveDirED
std::unique_ptr< weld::ProgressBar > m_xProgressBar
std::unique_ptr< weld::ProgressBar > m_xProgressBar
#define PROP_SAVEPATH
Definition: docrecovery.hxx:48
TValueType getUnpackedValueOrDefault(const OUString &sKey, const TValueType &aDefault) const
css::uno::Reference< css::uno::XComponentContext > m_xContext
TODO.
#define STATEPROP_STATE
Definition: docrecovery.hxx:52
OUString FactoryURL
a may be existing factory URL (e.g. for untitled documents)
int i
#define DLG_RET_OK
Definition: docrecovery.hxx:65
#define STATEPROP_TITLE
Definition: docrecovery.hxx:57
Mutex aLock
OUString getName(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true, DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
virtual void updateItems() override
#define STATEPROP_ORGURL
Definition: docrecovery.hxx:53
const OUString & getSaveDirURL() const
TODO.
OUString TemplateURL
may be the document base on a template file !?
const css::uno::Reference< css::uno::XComponentContext > & getComponentContext() const
TODO.
Definition: docrecovery.cxx:62
ERecoveryState RecoveryState
ui representation for DocState!
EDocStates
Definition: docrecovery.hxx:70
virtual void stepNext(TURLInfo *pItem)=0
SaveProgressDialog(weld::Window *pParent, RecoveryCore *pCore)
create all child controls of this dialog.
std::unique_ptr< weld::Button > m_xNextBtn
static bool isBrokenTempEntry(const TURLInfo &rInfo)
TODO.
Definition: docrecovery.cxx:74
void impl_startListening()
starts listening on the internal EmergencySave/AutoRecovery core.
css::uno::Reference< css::task::XStatusIndicator > m_xProgress
css::uno::Reference< css::task::XStatusIndicator > m_xProgress
#define RECOVERY_CMD_DO_PREPARE_EMERGENCY_SAVE
Definition: docrecovery.hxx:40
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
void setUpdateListener(IRecoveryUpdateListener *pListener)
TODO.
const OUString & GetWorkPath() const
virtual void set_text(const OUString &rText)=0
#define PROP_DISPATCHASYNCHRON
Definition: docrecovery.hxx:47
BrokenRecoveryDialog(weld::Window *pParent, RecoveryCore *pCore, bool bBeforeRecovery)
TODO.
static short impl_askUserForWizardCancel(weld::Widget *pParent, const char *pRes)
virtual short run() override
start the emergency save operation.
#define PROP_STATUSINDICATOR
Definition: docrecovery.hxx:46
css::util::URL impl_getParsedURL(const OUString &sURL)
TODO.
std::unique_ptr< weld::Button > m_xCancelBtn
OString strip(const OString &rIn, char c)
#define STATEPROP_ID
Definition: docrecovery.hxx:51
#define RECOVERY_CMD_DO_EMERGENCY_SAVE
Definition: docrecovery.hxx:41
PluginProgress(weld::ProgressBar *pProgressBar)
the Auto/Emergency saved document is not really up-to-date (some changes can be missing) ...
Reference< XExecutableDialog > m_xDialog
an action was started (saving/loading) ...
virtual void end() override
OUString TempURL
the full qualified URL of the temp. file (if it's exists)
#define RECOVERY_CMD_DO_RECOVERY
Definition: docrecovery.hxx:42
IRecoveryUpdateListener * m_pListener
TODO.
std::unique_ptr< weld::Button > m_xOkBtn
std::unique_ptr< weld::Button > m_xOkBtn
#define RECOVERY_OPERATIONSTATE_START
Definition: docrecovery.hxx:60
#define STATEPROP_MODULE
Definition: docrecovery.hxx:58
#define RECOVERY_OPERATIONSTATE_STOP
Definition: docrecovery.hxx:61
if(!pCandidateA->getEnd().equal(pCandidateB->getStart()))
std::unique_ptr< weld::Label > m_xDescrFT
Reference< XComponentContext > m_xContext
static OUString impl_getStatusImage(const TURLInfo &rInfo)
virtual void set_percentage(int value)=0
std::unique_ptr< weld::TreeView > m_xFileListLB
OUString DisplayName
the pure file name, without path, disc etcpp.
virtual void SAL_CALL reset() override
the Auto/Emergency saved document was processed successfully
std::unique_ptr< weld::TreeView > m_xFileListLB
TURLList & getURLListAccess()
TODO.
Definition: docrecovery.cxx:68
static SVT_DLLPUBLIC OUString GetFileImageId(const INetURLObject &rURL)
void impl_stopListening()
stop listening on the internal EmergencySave/AutoRecovery core.
bool m_bListenForSaving
knows the reason, why we listen on our internal m_xRealCore member.
the Auto/Emergency saved document isn't usable any longer
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, bool bMobile=false)
virtual void SAL_CALL addEventListener(const css::uno::Reference< css::lang::XEventListener > &xListener) override
sal_Int16 nValue
Definition: fmsrccfg.cxx:81
#define RECOVERY_CMD_DO_ENTRY_CLEANUP
Definition: docrecovery.hxx:44
void setProgressHandler(const css::uno::Reference< css::task::XStatusIndicator > &xProgress)
TODO.
css::uno::Reference< css::frame::XDispatch > m_xRealCore
TODO.