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 }
590 
592 {
594 
596  m_pCore->setUpdateListener(this);
598  short nRet = DialogController::run();
599  m_pCore->setUpdateListener(nullptr);
600  return nRet;
601 }
602 
604 {
605 }
606 
608 {
609  /* TODO
610 
611  if m_pCore would have a member m_mCurrentItem, you could see,
612  who is current, who is next ... You can show this information
613  in progress report FixText
614  */
615 }
616 
618 {
619  m_xDialog->response(DLG_RET_OK);
620 }
621 
622 static short impl_askUserForWizardCancel(weld::Widget* pParent, const char* pRes)
623 {
624  std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(pParent,
625  VclMessageType::Question, VclButtonsType::YesNo, SvxResId(pRes)));
626  if (xQuery->run() == RET_YES)
627  return DLG_RET_OK;
628  else
629  return DLG_RET_CANCEL;
630 }
631 
633  : GenericDialogController(pParent, "svx/ui/docrecoveryrecoverdialog.ui", "DocRecoveryRecoverDialog")
634  , m_aTitleRecoveryInProgress(SvxResId(RID_SVXSTR_RECOVERY_INPROGRESS))
635  , m_aRecoveryOnlyFinish (SvxResId(RID_SVXSTR_RECOVERYONLY_FINISH))
636  , m_aRecoveryOnlyFinishDescr(SvxResId(RID_SVXSTR_RECOVERYONLY_FINISH_DESCR))
637  , m_pCore(pCore)
638  , m_eRecoveryState(RecoveryDialog::E_RECOVERY_PREPARED)
639  , m_bWaitForCore(false)
640  , m_bWasRecoveryStarted(false)
641  , m_aSuccessRecovStr(SvxResId(RID_SVXSTR_SUCCESSRECOV))
642  , m_aOrigDocRecovStr(SvxResId(RID_SVXSTR_ORIGDOCRECOV))
643  , m_aRecovFailedStr(SvxResId(RID_SVXSTR_RECOVFAILED))
644  , m_aRecovInProgrStr(SvxResId(RID_SVXSTR_RECOVINPROGR))
645  , m_aNotRecovYetStr(SvxResId(RID_SVXSTR_NOTRECOVYET))
646  , m_xDescrFT(m_xBuilder->weld_label("desc"))
647  , m_xProgressBar(m_xBuilder->weld_progress_bar("progress"))
648  , m_xFileListLB(m_xBuilder->weld_tree_view("filelist"))
649  , m_xNextBtn(m_xBuilder->weld_button("next"))
650  , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
651 {
652  const auto nWidth = m_xFileListLB->get_approximate_digit_width() * 70;
653  m_xFileListLB->set_size_request(nWidth, m_xFileListLB->get_height_rows(10));
654  m_xProgressBar->set_size_request(m_xProgressBar->get_approximate_digit_width() * 50, -1);
655  PluginProgress* pProgress = new PluginProgress(m_xProgressBar.get());
656  m_xProgress.set(static_cast< css::task::XStatusIndicator* >(pProgress), css::uno::UNO_QUERY_THROW);
657 
658  std::vector<int> aWidths;
659  aWidths.push_back(m_xFileListLB->get_checkbox_column_width());
660  aWidths.push_back(60 * nWidth / 100);
661  aWidths.push_back(m_xFileListLB->get_checkbox_column_width());
662  m_xFileListLB->set_column_fixed_widths(aWidths);
663 
664  m_xNextBtn->set_sensitive(true);
665  m_xNextBtn->connect_clicked( LINK( this, RecoveryDialog, NextButtonHdl ) );
666  m_xCancelBtn->connect_clicked( LINK( this, RecoveryDialog, CancelButtonHdl ) );
667 
668  // fill list box first time
669  TURLList& rURLList = m_pCore->getURLListAccess();
670  for (size_t i = 0, nCount = rURLList.size(); i < nCount; ++i)
671  {
672  const TURLInfo& rInfo = rURLList[i];
673  m_xFileListLB->append();
674  m_xFileListLB->set_id(i, OUString::number(reinterpret_cast<sal_IntPtr>(&rInfo)));
675  m_xFileListLB->set_image(i, rInfo.StandardImageId, 0);
676  m_xFileListLB->set_text(i, rInfo.DisplayName, 1);
677  m_xFileListLB->set_image(i, impl_getStatusImage(rInfo), 2);
678  m_xFileListLB->set_text(i, impl_getStatusString(rInfo), 3);
679  }
680 
681  // mark first item
682  if (m_xFileListLB->n_children())
683  m_xFileListLB->set_cursor(0);
684 }
685 
687 {
688 }
689 
691 {
692  ::SolarMutexGuard aSolarLock;
693 
694  switch (m_eRecoveryState)
695  {
697  {
698  // user decided to start recovery ...
699  m_bWasRecoveryStarted = true;
700  // do it asynchronous (to allow repaints)
701  // and wait for this asynchronous operation.
703  m_xNextBtn->set_sensitive(false);
704  m_xCancelBtn->set_sensitive(false);
706  m_pCore->setUpdateListener(this);
707  m_pCore->doRecovery();
708 
709  m_bWaitForCore = true;
710  while(m_bWaitForCore)
712 
713  m_pCore->setUpdateListener(nullptr);
715  return execute();
716  }
717 
719  {
720  // the core finished it's task.
721  // let the user decide the next step.
723  m_xNextBtn->set_label(m_aRecoveryOnlyFinish);
724  m_xNextBtn->set_sensitive(true);
725  m_xCancelBtn->set_sensitive(false);
726  return 0;
727  }
728 
730  {
731  // All documents were recovered.
732  // User decided to step to the "next" wizard page.
733  // Do it ... but check first, if there exist some
734  // failed recovery documents. They must be saved to
735  // a user selected directory.
736  short nRet = DLG_RET_UNKNOWN;
737  BrokenRecoveryDialog aBrokenRecoveryDialog(m_xDialog.get(), m_pCore, !m_bWasRecoveryStarted);
738  OUString sSaveDir = aBrokenRecoveryDialog.getSaveDirURL(); // get the default dir
739  if (aBrokenRecoveryDialog.isExecutionNeeded())
740  {
741  nRet = aBrokenRecoveryDialog.run();
742  sSaveDir = aBrokenRecoveryDialog.getSaveDirURL();
743  }
744 
745  switch(nRet)
746  {
747  // no broken temp files exists
748  // step to the next wizard page
749  case DLG_RET_UNKNOWN :
750  {
752  return DLG_RET_OK;
753  }
754 
755  // user decided to save the broken temp files
756  // do and forget it
757  // step to the next wizard page
758  case DLG_RET_OK :
759  {
760  m_pCore->saveBrokenTempEntries(sSaveDir);
763  return DLG_RET_OK;
764  }
765 
766  // user decided to ignore broken temp files.
767  // Ask it again ... may be this decision was wrong.
768  // Results:
769  // IGNORE => remove broken temp files
770  // => step to the next wizard page
771  // CANCEL => step back to the recovery page
772  case DLG_RET_CANCEL :
773  {
774  // TODO ask user ...
777  return DLG_RET_OK;
778  }
779  }
780 
782  return DLG_RET_OK;
783  }
784 
786  {
787  // "YES" => break recovery
788  // But there exist different states, where "cancel" can be called.
789  // Handle it different.
792  else
794  return execute();
795  }
796 
799  {
800  // We have to check if there exists some temp. files.
801  // They should be saved to a user defined location.
802  // If no temp files exists or user decided to ignore it ...
803  // we have to remove all recovery/session data anyway!
804  short nRet = DLG_RET_UNKNOWN;
805  BrokenRecoveryDialog aBrokenRecoveryDialog(m_xDialog.get(), m_pCore, !m_bWasRecoveryStarted);
806  OUString sSaveDir = aBrokenRecoveryDialog.getSaveDirURL(); // get the default save location
807 
808  // dialog itself checks if there is a need to copy files for this mode.
809  // It uses the information m_bWasRecoveryStarted doing so.
810  if (aBrokenRecoveryDialog.isExecutionNeeded())
811  {
812  nRet = aBrokenRecoveryDialog.run();
813  sSaveDir = aBrokenRecoveryDialog.getSaveDirURL();
814  }
815 
816  // Possible states:
817  // a) nRet == DLG_RET_UNKNOWN
818  // dialog was not shown ...
819  // because there exists no temp file for copy.
820  // => remove all recovery data
821  // b) nRet == DLG_RET_OK
822  // dialog was shown ...
823  // user decided to save temp files
824  // => save all OR broken temp files (depends from the time, where cancel was called)
825  // => remove all recovery data
826  // c) nRet == DLG_RET_CANCEL
827  // dialog was shown ...
828  // user decided to ignore temp files
829  // => remove all recovery data
830  // => a)/c) are the same ... b) has one additional operation
831 
832  // b)
833  if (nRet == DLG_RET_OK)
834  {
836  m_pCore->saveBrokenTempEntries(sSaveDir);
837  else
838  m_pCore->saveAllTempEntries(sSaveDir);
839  }
840 
841  // a,b,c)
844  else
847 
848  // THERE IS NO WAY BACK. see impl_askUserForWizardCancel()!
849  return DLG_RET_CANCEL;
850  }
851  }
852 
853  // should never be reached .-)
854  OSL_FAIL("Should never be reached!");
855  return DLG_RET_OK;
856 }
857 
859 {
860  int c = m_xFileListLB->n_children();
861  for (int i = 0; i < c; ++i)
862  {
863  TURLInfo* pInfo = reinterpret_cast<TURLInfo*>(m_xFileListLB->get_id(i).toInt64());
864  if ( !pInfo )
865  continue;
866 
867  m_xFileListLB->set_image(i, impl_getStatusImage(*pInfo), 2);
868  OUString sStatus = impl_getStatusString( *pInfo );
869  if (!sStatus.isEmpty())
870  m_xFileListLB->set_text(i, sStatus, 3);
871  }
872 }
873 
875 {
876  int c = m_xFileListLB->n_children();
877  for (int i=0; i < c; ++i)
878  {
879  TURLInfo* pInfo = reinterpret_cast<TURLInfo*>(m_xFileListLB->get_id(i).toInt64());
880  if (pInfo->ID != pItem->ID)
881  continue;
882 
883  m_xFileListLB->set_cursor(i);
884  m_xFileListLB->scroll_to_row(i);
885  break;
886  }
887 }
888 
890 {
891  m_bWaitForCore = false;
892 }
893 
895 {
896  switch (m_eRecoveryState)
897  {
899  m_eRecoveryState = RecoveryDialog::E_RECOVERY_IN_PROGRESS;
900  execute();
901  break;
903  m_eRecoveryState = RecoveryDialog::E_RECOVERY_DONE;
904  execute();
905  break;
906  }
907 
908  if (m_eRecoveryState == RecoveryDialog::E_RECOVERY_HANDLED)
909  {
910  m_xDialog->response(DLG_RET_OK);
911  }
912 }
913 
914 IMPL_LINK_NOARG(RecoveryDialog, CancelButtonHdl, weld::Button&, void)
915 {
916  switch (m_eRecoveryState)
917  {
919  if (impl_askUserForWizardCancel(m_xDialog.get(), RID_SVXSTR_QUERY_EXIT_RECOVERY) != DLG_RET_CANCEL)
920  {
921  m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED;
922  execute();
923  }
924  break;
926  m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED;
927  execute();
928  break;
929  }
930 
931  if (m_eRecoveryState == RecoveryDialog::E_RECOVERY_HANDLED)
932  {
933  m_xDialog->response(RET_CANCEL);
934  }
935 }
936 
937 OUString RecoveryDialog::impl_getStatusString( const TURLInfo& rInfo ) const
938 {
939  OUString sStatus;
940  switch ( rInfo.RecoveryState )
941  {
943  sStatus = m_aSuccessRecovStr;
944  break;
946  sStatus = m_aOrigDocRecovStr;
947  break;
948  case E_RECOVERY_FAILED :
949  sStatus = m_aRecovFailedStr;
950  break;
952  sStatus = m_aRecovInProgrStr;
953  break;
954  case E_NOT_RECOVERED_YET :
955  sStatus = m_aNotRecovYetStr;
956  break;
957  default:
958  break;
959  }
960  return sStatus;
961 }
962 
964 {
965  OUString sStatus;
966  switch ( rInfo.RecoveryState )
967  {
969  sStatus = RID_SVXBMP_GREENCHECK;
970  break;
972  sStatus = RID_SVXBMP_YELLOWCHECK;
973  break;
974  case E_RECOVERY_FAILED :
975  sStatus = RID_SVXBMP_REDCROSS;
976  break;
977  default:
978  break;
979  }
980  return sStatus;
981 }
982 
984  RecoveryCore* pCore,
985  bool bBeforeRecovery)
986  : GenericDialogController(pParent, "svx/ui/docrecoverybrokendialog.ui", "DocRecoveryBrokenDialog")
987  , m_pCore(pCore)
988  , m_bBeforeRecovery(bBeforeRecovery)
989  , m_bExecutionNeeded(false)
990  , m_xFileListLB(m_xBuilder->weld_tree_view("filelist"))
991  , m_xSaveDirED(m_xBuilder->weld_entry("savedir"))
992  , m_xSaveDirBtn(m_xBuilder->weld_button("change"))
993  , m_xOkBtn(m_xBuilder->weld_button("ok"))
994  , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
995 {
996  m_xSaveDirBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, SaveButtonHdl ) );
997  m_xOkBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, OkButtonHdl ) );
998  m_xCancelBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, CancelButtonHdl ) );
999 
1001  INetURLObject aObj( m_sSavePath );
1002  OUString sPath;
1003  osl::FileBase::getSystemPathFromFileURL(aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), sPath);
1004  m_xSaveDirED->set_text(sPath);
1005 
1006  impl_refresh();
1007 }
1008 
1010 {
1011 }
1012 
1014 {
1015  m_bExecutionNeeded = false;
1016  TURLList& rURLList = m_pCore->getURLListAccess();
1017  for (const TURLInfo& rInfo : rURLList)
1018  {
1019  if (m_bBeforeRecovery)
1020  {
1021  // "Cancel" before recovery ->
1022  // search for any temp files!
1023  if (rInfo.TempURL.isEmpty())
1024  continue;
1025  }
1026  else
1027  {
1028  // "Cancel" after recovery ->
1029  // search for broken temp files
1030  if (!RecoveryCore::isBrokenTempEntry(rInfo))
1031  continue;
1032  }
1033 
1034  m_bExecutionNeeded = true;
1035 
1036  m_xFileListLB->append(OUString::number(reinterpret_cast<sal_IntPtr>(&rInfo)), rInfo.DisplayName, rInfo.StandardImageId);
1037  }
1038  m_sSavePath.clear();
1039  m_xOkBtn->grab_focus();
1040 }
1041 
1043 {
1044  return m_bExecutionNeeded;
1045 }
1046 
1048 {
1049  return m_sSavePath;
1050 }
1051 
1053 {
1054  OUString sPhysicalPath = comphelper::string::strip(m_xSaveDirED->get_text(), ' ');
1055  OUString sURL;
1056  osl::FileBase::getFileURLFromSystemPath( sPhysicalPath, sURL );
1057  m_sSavePath = sURL;
1058  while (m_sSavePath.isEmpty())
1059  impl_askForSavePath();
1060 
1061  m_xDialog->response(DLG_RET_OK);
1062 }
1063 
1065 {
1066  m_xDialog->response(RET_CANCEL);
1067 }
1068 
1070 {
1071  impl_askForSavePath();
1072 }
1073 
1075 {
1076  css::uno::Reference< css::ui::dialogs::XFolderPicker2 > xFolderPicker =
1077  css::ui::dialogs::FolderPicker::create( m_pCore->getComponentContext() );
1078 
1079  INetURLObject aURL(m_sSavePath, INetProtocol::File);
1080  xFolderPicker->setDisplayDirectory(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
1081  short nRet = xFolderPicker->execute();
1082  if (nRet == css::ui::dialogs::ExecutableDialogResults::OK)
1083  {
1084  m_sSavePath = xFolderPicker->getDirectory();
1085  OUString sPath;
1086  osl::FileBase::getSystemPathFromFileURL(m_sSavePath, sPath);
1087  m_xSaveDirED->set_text(sPath);
1088  }
1089 }
1090 
1091 }
1092 
1093 /* 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
if(nullptr==pCandidateA||nullptr==pCandidateB)
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
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage)
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
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
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.