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