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