Resolves: tdf#141625 give enough space to see full date+time
[LibreOffice.git] / sfx2 / source / dialog / versdlg.cxx
blob53ea62b0eccd1580c6d3418b20fcfe4182d8a78f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <com/sun/star/document/XCmisDocument.hpp>
23 #include <com/sun/star/frame/XModel.hpp>
24 #include <com/sun/star/util/RevisionTag.hpp>
25 #include <com/sun/star/beans/NamedValue.hpp>
27 #include <officecfg/Office/Common.hxx>
28 #include <unotools/localedatawrapper.hxx>
29 #include <svl/intitem.hxx>
30 #include <svl/stritem.hxx>
31 #include <svl/itemset.hxx>
32 #include <unotools/useroptions.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/settings.hxx>
35 #include <tools/datetime.hxx>
37 #include <versdlg.hxx>
38 #include <sfx2/strings.hrc>
39 #include <sfx2/dialoghelper.hxx>
40 #include <sfx2/viewfrm.hxx>
41 #include <sfx2/sfxresid.hxx>
42 #include <sfx2/docfile.hxx>
43 #include <sfx2/objsh.hxx>
44 #include <sfx2/sfxsids.hrc>
45 #include <sfx2/dispatch.hxx>
47 #include <sfx2/sfxuno.hxx>
48 #include <memory>
49 #include <vector>
51 using namespace com::sun::star;
53 struct SfxVersionInfo
55 OUString aName;
56 OUString aComment;
57 OUString aAuthor;
58 DateTime aCreationDate;
60 SfxVersionInfo();
63 class SfxVersionTableDtor
65 private:
66 std::vector<std::unique_ptr<SfxVersionInfo>> aTableList;
67 public:
68 explicit SfxVersionTableDtor( const uno::Sequence < util::RevisionTag >& rInfo );
69 explicit SfxVersionTableDtor( const uno::Sequence < document::CmisVersion > & rInfo );
70 SfxVersionTableDtor(const SfxVersionTableDtor&) = delete;
71 SfxVersionTableDtor& operator=(const SfxVersionTableDtor&) = delete;
73 size_t size() const
74 { return aTableList.size(); }
76 SfxVersionInfo* at( size_t i ) const
77 { return aTableList[ i ].get(); }
80 SfxVersionTableDtor::SfxVersionTableDtor( const uno::Sequence < util::RevisionTag >& rInfo )
82 for ( const auto& rItem : rInfo )
84 std::unique_ptr<SfxVersionInfo> pInfo(new SfxVersionInfo);
85 pInfo->aName = rItem.Identifier;
86 pInfo->aComment = rItem.Comment;
87 pInfo->aAuthor = rItem.Author;
89 pInfo->aCreationDate = DateTime( rItem.TimeStamp );
90 aTableList.push_back( std::move(pInfo) );
94 SfxVersionTableDtor::SfxVersionTableDtor( const uno::Sequence < document::CmisVersion >& rInfo )
96 for ( const auto& rItem : rInfo )
98 std::unique_ptr<SfxVersionInfo> pInfo(new SfxVersionInfo);
99 pInfo->aName = rItem.Id;
100 pInfo->aComment = rItem.Comment;
101 pInfo->aAuthor = rItem.Author;
103 pInfo->aCreationDate = DateTime( rItem.TimeStamp );
104 aTableList.push_back( std::move(pInfo) );
108 SfxVersionInfo::SfxVersionInfo()
109 : aCreationDate( DateTime::EMPTY )
113 namespace
115 void setColSizes(weld::TreeView& rVersionBox)
117 // recalculate the datetime column width
118 int nWidestTime(rVersionBox.get_pixel_size(getWidestDateTime(Application::GetSettings().GetLocaleDataWrapper(), false)).Width());
119 int nW1 = rVersionBox.get_pixel_size(rVersionBox.get_column_title(1)).Width();
121 int nMax = std::max(nWidestTime, nW1) + 12; // max width + a little offset
122 const int nRest = rVersionBox.get_preferred_size().Width() - nMax;
124 std::set<OUString> aAuthors;
125 aAuthors.insert(SvtUserOptions().GetFullName());
127 for (int i = 0; i < rVersionBox.n_children(); ++i)
129 aAuthors.insert(reinterpret_cast<SfxVersionInfo*>(rVersionBox.get_id(i).toInt64())->aAuthor);
132 int nMaxAuthorWidth = nRest/4;
133 for (auto const& author : aAuthors)
135 nMaxAuthorWidth = std::max<int>(nMaxAuthorWidth, rVersionBox.get_pixel_size(author).Width());
136 if (nMaxAuthorWidth > nRest/2)
138 nMaxAuthorWidth = nRest/2;
139 break;
143 rVersionBox.set_column_fixed_widths({ nMax, nMaxAuthorWidth });
147 SfxVersionDialog::SfxVersionDialog(weld::Window* pParent, SfxViewFrame* pVwFrame, bool bIsSaveVersionOnClose)
148 : SfxDialogController(pParent, "sfx/ui/versionsofdialog.ui", "VersionsOfDialog")
149 , m_pViewFrame(pVwFrame)
150 , m_bIsSaveVersionOnClose(bIsSaveVersionOnClose)
151 , m_xSaveButton(m_xBuilder->weld_button("save"))
152 , m_xSaveCheckBox(m_xBuilder->weld_check_button("always"))
153 , m_xOpenButton(m_xBuilder->weld_button("open"))
154 , m_xViewButton(m_xBuilder->weld_button("show"))
155 , m_xDeleteButton(m_xBuilder->weld_button("delete"))
156 , m_xCompareButton(m_xBuilder->weld_button("compare"))
157 , m_xCmisButton(m_xBuilder->weld_button("cmis"))
158 , m_xVersionBox(m_xBuilder->weld_tree_view("versions"))
160 m_xVersionBox->set_size_request(m_xVersionBox->get_approximate_digit_width() * 90,
161 m_xVersionBox->get_height_rows(15));
162 setColSizes(*m_xVersionBox);
164 Link<weld::Button&,void> aClickLink = LINK( this, SfxVersionDialog, ButtonHdl_Impl );
165 m_xViewButton->connect_clicked( aClickLink );
166 m_xSaveButton->connect_clicked( aClickLink );
167 m_xDeleteButton->connect_clicked( aClickLink );
168 m_xCompareButton->connect_clicked( aClickLink );
169 m_xOpenButton->connect_clicked( aClickLink );
170 m_xSaveCheckBox->connect_toggled(LINK(this, SfxVersionDialog, ToggleHdl_Impl));
171 m_xCmisButton->connect_clicked( aClickLink );
173 m_xVersionBox->connect_changed( LINK( this, SfxVersionDialog, SelectHdl_Impl ) );
174 m_xVersionBox->connect_row_activated( LINK( this, SfxVersionDialog, DClickHdl_Impl ) );
176 m_xVersionBox->grab_focus();
178 // set dialog title (filename or docinfo title)
179 OUString sText = m_xDialog->get_title() +
180 " " + m_pViewFrame->GetObjectShell()->GetTitle();
181 m_xDialog->set_title(sText);
183 Init_Impl();
186 static OUString ConvertWhiteSpaces_Impl( const OUString& rText )
188 // converted linebreaks and tabs to blanks; it's necessary for the display
189 OUStringBuffer sConverted;
190 const sal_Unicode* pChars = rText.getStr();
191 while ( *pChars )
193 switch ( *pChars )
195 case '\n' :
196 case '\t' :
197 sConverted.append(' ');
198 break;
200 default:
201 sConverted.append(*pChars);
204 ++pChars;
207 return sConverted.makeStringAndClear();
210 void SfxVersionDialog::Init_Impl()
212 SfxObjectShell *pObjShell = m_pViewFrame->GetObjectShell();
213 SfxMedium* pMedium = pObjShell->GetMedium();
214 uno::Sequence < util::RevisionTag > aVersions = pMedium->GetVersionList( true );
215 m_pTable.reset(new SfxVersionTableDtor( aVersions ));
216 m_xVersionBox->freeze();
217 for (size_t n = 0; n < m_pTable->size(); ++n)
219 SfxVersionInfo *pInfo = m_pTable->at( n );
220 OUString aEntry = formatDateTime(pInfo->aCreationDate, Application::GetSettings().GetLocaleDataWrapper(), false);
221 m_xVersionBox->append(OUString::number(reinterpret_cast<sal_Int64>(pInfo)), aEntry);
222 auto nLastRow = m_xVersionBox->n_children() - 1;
223 m_xVersionBox->set_text(nLastRow, pInfo->aAuthor, 1);
224 m_xVersionBox->set_text(nLastRow, ConvertWhiteSpaces_Impl(pInfo->aComment), 2);
226 m_xVersionBox->thaw();
228 if (auto nCount = m_pTable->size())
229 m_xVersionBox->select(nCount - 1);
231 m_xSaveCheckBox->set_active(m_bIsSaveVersionOnClose);
233 bool bEnable = !pObjShell->IsReadOnly();
234 m_xSaveButton->set_sensitive( bEnable );
235 m_xSaveCheckBox->set_sensitive( bEnable );
237 m_xOpenButton->set_sensitive(false);
238 m_xViewButton->set_sensitive(false);
239 m_xDeleteButton->set_sensitive(false);
240 m_xCompareButton->set_sensitive(false);
242 if ( !officecfg::Office::Common::Misc::ExperimentalMode::get() )
243 m_xCmisButton->hide( );
244 uno::Reference<document::XCmisDocument> xCmisDoc(pObjShell->GetModel(), uno::UNO_QUERY);
245 if (xCmisDoc && xCmisDoc->isVersionable())
246 m_xCmisButton->set_sensitive(true);
247 else
248 m_xCmisButton->set_sensitive(false);
250 SelectHdl_Impl(*m_xVersionBox);
253 SfxVersionDialog::~SfxVersionDialog()
257 void SfxVersionDialog::Open_Impl()
259 SfxObjectShell *pObjShell = m_pViewFrame->GetObjectShell();
261 auto nPos = m_xVersionBox->get_selected_index();
262 SfxInt16Item aItem( SID_VERSION, nPos + 1);
263 SfxStringItem aTarget( SID_TARGETNAME, "_blank" );
264 SfxStringItem aReferer( SID_REFERER, "private:user" );
265 SfxStringItem aFile( SID_FILE_NAME, pObjShell->GetMedium()->GetName() );
267 uno::Sequence< beans::NamedValue > aEncryptionData;
268 if ( GetEncryptionData_Impl( pObjShell->GetMedium()->GetItemSet(), aEncryptionData ) )
270 // there is a password, it should be used during the opening
271 SfxUnoAnyItem aEncryptionDataItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData ) );
272 m_pViewFrame->GetDispatcher()->ExecuteList(
273 SID_OPENDOC, SfxCallMode::ASYNCHRON,
274 { &aFile, &aItem, &aTarget, &aReferer, &aEncryptionDataItem });
276 else
278 m_pViewFrame->GetDispatcher()->ExecuteList(
279 SID_OPENDOC, SfxCallMode::ASYNCHRON,
280 { &aFile, &aItem, &aTarget, &aReferer });
283 m_xDialog->response(RET_OK);
286 IMPL_LINK_NOARG(SfxVersionDialog, DClickHdl_Impl, weld::TreeView&, bool)
288 Open_Impl();
289 return true;
292 IMPL_LINK_NOARG(SfxVersionDialog, SelectHdl_Impl, weld::TreeView&, void)
294 bool bEnable = m_xVersionBox->get_selected_index() != -1;
295 SfxObjectShell* pObjShell = m_pViewFrame->GetObjectShell();
296 m_xDeleteButton->set_sensitive(bEnable && !pObjShell->IsReadOnly());
297 m_xOpenButton->set_sensitive(bEnable);
298 m_xViewButton->set_sensitive(bEnable);
300 const SfxPoolItem *pDummy=nullptr;
301 m_pViewFrame->GetDispatcher()->QueryState( SID_DOCUMENT_MERGE, pDummy );
302 SfxItemState eState = m_pViewFrame->GetDispatcher()->QueryState( SID_DOCUMENT_COMPARE, pDummy );
303 m_xCompareButton->set_sensitive(bEnable && eState >= SfxItemState::DEFAULT);
306 IMPL_LINK(SfxVersionDialog, ButtonHdl_Impl, weld::Button&, rButton, void)
308 SfxObjectShell *pObjShell = m_pViewFrame->GetObjectShell();
310 int nEntry = m_xVersionBox->get_selected_index();
312 if (&rButton == m_xSaveButton.get())
314 SfxVersionInfo aInfo;
315 aInfo.aAuthor = SvtUserOptions().GetFullName();
316 SfxViewVersionDialog_Impl aDlg(m_xDialog.get(), aInfo, true);
317 short nRet = aDlg.run();
318 if (nRet == RET_OK)
320 SfxStringItem aComment( SID_DOCINFO_COMMENTS, aInfo.aComment );
321 pObjShell->SetModified();
322 const SfxPoolItem* aItems[2];
323 aItems[0] = &aComment;
324 aItems[1] = nullptr;
325 m_pViewFrame->GetBindings().ExecuteSynchron( SID_SAVEDOC, aItems );
326 m_xVersionBox->freeze();
327 m_xVersionBox->clear();
328 m_xVersionBox->thaw();
329 Init_Impl();
332 else if (&rButton == m_xDeleteButton.get() && nEntry != -1)
334 SfxVersionInfo* pInfo = reinterpret_cast<SfxVersionInfo*>(m_xVersionBox->get_id(nEntry).toInt64());
335 pObjShell->GetMedium()->RemoveVersion_Impl(pInfo->aName);
336 pObjShell->SetModified();
337 m_xVersionBox->freeze();
338 m_xVersionBox->clear();
339 m_xVersionBox->thaw();
340 Init_Impl();
342 else if (&rButton == m_xOpenButton.get() && nEntry != -1)
344 Open_Impl();
346 else if (&rButton == m_xViewButton.get() && nEntry != -1)
348 SfxVersionInfo* pInfo = reinterpret_cast<SfxVersionInfo*>(m_xVersionBox->get_id(nEntry).toInt64());
349 SfxViewVersionDialog_Impl aDlg(m_xDialog.get(), *pInfo, false);
350 aDlg.run();
352 else if (&rButton == m_xCompareButton.get() && nEntry != -1)
354 SfxAllItemSet aSet( pObjShell->GetPool() );
355 aSet.Put(SfxInt16Item(SID_VERSION, nEntry + 1));
356 aSet.Put(SfxStringItem(SID_FILE_NAME, pObjShell->GetMedium()->GetName()));
358 SfxItemSet* pSet = pObjShell->GetMedium()->GetItemSet();
359 const SfxStringItem* pFilterItem = SfxItemSet::GetItem<SfxStringItem>(pSet, SID_FILTER_NAME, false);
360 const SfxStringItem* pFilterOptItem = SfxItemSet::GetItem<SfxStringItem>(pSet, SID_FILE_FILTEROPTIONS, false);
361 if ( pFilterItem )
362 aSet.Put( *pFilterItem );
363 if ( pFilterOptItem )
364 aSet.Put( *pFilterOptItem );
366 m_pViewFrame->GetDispatcher()->Execute( SID_DOCUMENT_COMPARE, SfxCallMode::ASYNCHRON, aSet );
367 m_xDialog->response(RET_CLOSE);
369 else if (&rButton == m_xCmisButton.get())
371 SfxCmisVersionsDialog aDlg(m_xDialog.get(), m_pViewFrame);
372 aDlg.run();
376 IMPL_LINK(SfxVersionDialog, ToggleHdl_Impl, weld::Toggleable&, rButton, void)
378 if (&rButton == m_xSaveCheckBox.get())
380 m_bIsSaveVersionOnClose = m_xSaveCheckBox->get_active();
384 SfxViewVersionDialog_Impl::SfxViewVersionDialog_Impl(weld::Window *pParent, SfxVersionInfo& rInfo, bool bEdit)
385 : SfxDialogController(pParent, "sfx/ui/versioncommentdialog.ui", "VersionCommentDialog")
386 , m_rInfo(rInfo)
387 , m_xDateTimeText(m_xBuilder->weld_label("timestamp"))
388 , m_xSavedByText(m_xBuilder->weld_label("author"))
389 , m_xEdit(m_xBuilder->weld_text_view("textview"))
390 , m_xOKButton(m_xBuilder->weld_button("ok"))
391 , m_xCancelButton(m_xBuilder->weld_button("cancel"))
392 , m_xCloseButton(m_xBuilder->weld_button("close"))
394 OUString sAuthor = rInfo.aAuthor.isEmpty() ? SfxResId(STR_NO_NAME_SET) : rInfo.aAuthor;
396 const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
397 m_xDateTimeText->set_label(m_xDateTimeText->get_label() + formatDateTime(rInfo.aCreationDate, rLocaleWrapper, false));
398 m_xSavedByText->set_label(m_xSavedByText->get_label() + sAuthor);
399 m_xEdit->set_text(rInfo.aComment);
400 m_xEdit->set_size_request(40 * m_xEdit->get_approximate_digit_width(),
401 7 * m_xEdit->get_text_height());
402 m_xOKButton->connect_clicked(LINK(this, SfxViewVersionDialog_Impl, ButtonHdl));
404 if (!bEdit)
406 m_xOKButton->hide();
407 m_xCancelButton->hide();
408 m_xEdit->set_editable(false);
409 m_xDialog->set_title(SfxResId(STR_VIEWVERSIONCOMMENT));
410 m_xCloseButton->grab_focus();
412 else
414 m_xDateTimeText->hide();
415 m_xCloseButton->hide();
416 m_xEdit->grab_focus();
420 IMPL_LINK(SfxViewVersionDialog_Impl, ButtonHdl, weld::Button&, rButton, void)
422 assert(&rButton == m_xOKButton.get());
423 (void)rButton;
424 m_rInfo.aComment = m_xEdit->get_text();
425 m_xDialog->response(RET_OK);
428 SfxCmisVersionsDialog::SfxCmisVersionsDialog(weld::Window* pParent, SfxViewFrame* pVwFrame)
429 : SfxDialogController(pParent, "sfx/ui/versionscmis.ui", "VersionsCmisDialog")
430 , m_pViewFrame(pVwFrame)
431 , m_xOpenButton(m_xBuilder->weld_button("open"))
432 , m_xViewButton(m_xBuilder->weld_button("show"))
433 , m_xDeleteButton(m_xBuilder->weld_button("delete"))
434 , m_xCompareButton(m_xBuilder->weld_button("compare"))
435 , m_xVersionBox(m_xBuilder->weld_tree_view("versions"))
437 m_xVersionBox->set_size_request(m_xVersionBox->get_approximate_digit_width() * 90,
438 m_xVersionBox->get_height_rows(15));
439 setColSizes(*m_xVersionBox);
441 m_xVersionBox->grab_focus();
443 OUString sText = m_xDialog->get_title() +
444 " " + m_pViewFrame->GetObjectShell()->GetTitle();
445 m_xDialog->set_title(sText);
447 LoadVersions();
450 SfxCmisVersionsDialog::~SfxCmisVersionsDialog()
454 void SfxCmisVersionsDialog::LoadVersions()
456 SfxObjectShell *pObjShell = m_pViewFrame->GetObjectShell();
457 uno::Sequence < document::CmisVersion > aVersions = pObjShell->GetCmisVersions( );
458 m_pTable.reset(new SfxVersionTableDtor( aVersions ));
459 for (size_t n = 0; n < m_pTable->size(); ++n)
461 SfxVersionInfo *pInfo = m_pTable->at( n );
462 OUString aEntry = formatDateTime(pInfo->aCreationDate, Application::GetSettings().GetLocaleDataWrapper(), false);
463 m_xVersionBox->append(OUString::number(reinterpret_cast<sal_Int64>(pInfo)), aEntry);
464 auto nLastRow = m_xVersionBox->n_children() - 1;
465 m_xVersionBox->set_text(nLastRow, pInfo->aAuthor, 1);
466 m_xVersionBox->set_text(nLastRow, ConvertWhiteSpaces_Impl(pInfo->aComment), 2);
469 if (auto nCount = m_pTable->size())
470 m_xVersionBox->select(nCount - 1);
473 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */