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