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