/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star; struct SfxVersionInfo { OUString aName; OUString aComment; OUString aAuthor; DateTime aCreationDate; SfxVersionInfo(); }; class SfxVersionTableDtor { private: std::vector> aTableList; public: explicit SfxVersionTableDtor( const uno::Sequence < util::RevisionTag >& rInfo ); explicit SfxVersionTableDtor( const uno::Sequence < document::CmisVersion > & rInfo ); SfxVersionTableDtor(const SfxVersionTableDtor&) = delete; SfxVersionTableDtor& operator=(const SfxVersionTableDtor&) = delete; size_t size() const { return aTableList.size(); } SfxVersionInfo* at( size_t i ) const { return aTableList[ i ].get(); } }; SfxVersionTableDtor::SfxVersionTableDtor( const uno::Sequence < util::RevisionTag >& rInfo ) { for ( const auto& rItem : rInfo ) { std::unique_ptr pInfo(new SfxVersionInfo); pInfo->aName = rItem.Identifier; pInfo->aComment = rItem.Comment; pInfo->aAuthor = rItem.Author; pInfo->aCreationDate = DateTime( rItem.TimeStamp ); aTableList.push_back( std::move(pInfo) ); } } SfxVersionTableDtor::SfxVersionTableDtor( const uno::Sequence < document::CmisVersion >& rInfo ) { for ( const auto& rItem : rInfo ) { std::unique_ptr pInfo(new SfxVersionInfo); pInfo->aName = rItem.Id; pInfo->aComment = rItem.Comment; pInfo->aAuthor = rItem.Author; pInfo->aCreationDate = DateTime( rItem.TimeStamp ); aTableList.push_back( std::move(pInfo) ); } } SfxVersionInfo::SfxVersionInfo() : aCreationDate( DateTime::EMPTY ) { } namespace { void setColSizes(weld::TreeView& rVersionBox) { // recalculate the datetime column width int nWidestTime(rVersionBox.get_pixel_size(getWidestDateTime(Application::GetSettings().GetLocaleDataWrapper(), false)).Width()); int nW1 = rVersionBox.get_pixel_size(rVersionBox.get_column_title(1)).Width(); int nMax = std::max(nWidestTime, nW1) + 12; // max width + a little offset const int nRest = rVersionBox.get_preferred_size().Width() - nMax; std::set aAuthors; aAuthors.insert(SvtUserOptions().GetFullName()); for (int i = 0; i < rVersionBox.n_children(); ++i) { aAuthors.insert(weld::fromId(rVersionBox.get_id(i))->aAuthor); } int nMaxAuthorWidth = nRest/4; for (auto const& author : aAuthors) { nMaxAuthorWidth = std::max(nMaxAuthorWidth, rVersionBox.get_pixel_size(author).Width()); if (nMaxAuthorWidth > nRest/2) { nMaxAuthorWidth = nRest/2; break; } } rVersionBox.set_column_fixed_widths({ nMax, nMaxAuthorWidth }); } } SfxVersionDialog::SfxVersionDialog(weld::Window* pParent, SfxViewFrame* pVwFrame, bool bIsSaveVersionOnClose) : SfxDialogController(pParent, "sfx/ui/versionsofdialog.ui", "VersionsOfDialog") , m_pViewFrame(pVwFrame) , m_bIsSaveVersionOnClose(bIsSaveVersionOnClose) , m_xSaveButton(m_xBuilder->weld_button("save")) , m_xSaveCheckBox(m_xBuilder->weld_check_button("always")) , m_xOpenButton(m_xBuilder->weld_button("open")) , m_xViewButton(m_xBuilder->weld_button("show")) , m_xDeleteButton(m_xBuilder->weld_button("delete")) , m_xCompareButton(m_xBuilder->weld_button("compare")) , m_xCmisButton(m_xBuilder->weld_button("cmis")) , m_xVersionBox(m_xBuilder->weld_tree_view("versions")) { m_xVersionBox->set_size_request(m_xVersionBox->get_approximate_digit_width() * 90, m_xVersionBox->get_height_rows(15)); setColSizes(*m_xVersionBox); Link aClickLink = LINK( this, SfxVersionDialog, ButtonHdl_Impl ); m_xViewButton->connect_clicked( aClickLink ); m_xSaveButton->connect_clicked( aClickLink ); m_xDeleteButton->connect_clicked( aClickLink ); m_xCompareButton->connect_clicked( aClickLink ); m_xOpenButton->connect_clicked( aClickLink ); m_xSaveCheckBox->connect_toggled(LINK(this, SfxVersionDialog, ToggleHdl_Impl)); m_xCmisButton->connect_clicked( aClickLink ); m_xVersionBox->connect_changed( LINK( this, SfxVersionDialog, SelectHdl_Impl ) ); m_xVersionBox->connect_row_activated( LINK( this, SfxVersionDialog, DClickHdl_Impl ) ); m_xVersionBox->grab_focus(); // set dialog title (filename or docinfo title) OUString sText = m_xDialog->get_title() + " " + m_pViewFrame->GetObjectShell()->GetTitle(); m_xDialog->set_title(sText); Init_Impl(); } static OUString ConvertWhiteSpaces_Impl( const OUString& rText ) { // converted linebreaks and tabs to blanks; it's necessary for the display OUStringBuffer sConverted; const sal_Unicode* pChars = rText.getStr(); while ( *pChars ) { switch ( *pChars ) { case '\n' : case '\t' : sConverted.append(' '); break; default: sConverted.append(*pChars); } ++pChars; } return sConverted.makeStringAndClear(); } void SfxVersionDialog::Init_Impl() { SfxObjectShell *pObjShell = m_pViewFrame->GetObjectShell(); SfxMedium* pMedium = pObjShell->GetMedium(); uno::Sequence < util::RevisionTag > aVersions = pMedium->GetVersionList( true ); m_pTable.reset(new SfxVersionTableDtor( aVersions )); m_xVersionBox->freeze(); for (size_t n = 0; n < m_pTable->size(); ++n) { SfxVersionInfo *pInfo = m_pTable->at( n ); OUString aEntry = formatDateTime(pInfo->aCreationDate, Application::GetSettings().GetLocaleDataWrapper(), false); m_xVersionBox->append(weld::toId(pInfo), aEntry); auto nLastRow = m_xVersionBox->n_children() - 1; m_xVersionBox->set_text(nLastRow, pInfo->aAuthor, 1); m_xVersionBox->set_text(nLastRow, ConvertWhiteSpaces_Impl(pInfo->aComment), 2); } m_xVersionBox->thaw(); if (auto nCount = m_pTable->size()) m_xVersionBox->select(nCount - 1); m_xSaveCheckBox->set_active(m_bIsSaveVersionOnClose); bool bEnable = !pObjShell->IsReadOnly(); m_xSaveButton->set_sensitive( bEnable ); m_xSaveCheckBox->set_sensitive( bEnable ); m_xOpenButton->set_sensitive(false); m_xViewButton->set_sensitive(false); m_xDeleteButton->set_sensitive(false); m_xCompareButton->set_sensitive(false); if ( !officecfg::Office::Common::Misc::ExperimentalMode::get() ) m_xCmisButton->hide( ); uno::Reference xCmisDoc(pObjShell->GetModel(), uno::UNO_QUERY); if (xCmisDoc && xCmisDoc->isVersionable()) m_xCmisButton->set_sensitive(true); else m_xCmisButton->set_sensitive(false); SelectHdl_Impl(*m_xVersionBox); } SfxVersionDialog::~SfxVersionDialog() { } void SfxVersionDialog::Open_Impl() { SfxObjectShell *pObjShell = m_pViewFrame->GetObjectShell(); auto nPos = m_xVersionBox->get_selected_index(); SfxInt16Item aItem( SID_VERSION, nPos + 1); SfxStringItem aTarget( SID_TARGETNAME, "_blank" ); SfxStringItem aReferer( SID_REFERER, "private:user" ); SfxStringItem aFile( SID_FILE_NAME, pObjShell->GetMedium()->GetName() ); uno::Sequence< beans::NamedValue > aEncryptionData; if ( GetEncryptionData_Impl( &pObjShell->GetMedium()->GetItemSet(), aEncryptionData ) ) { // there is a password, it should be used during the opening SfxUnoAnyItem aEncryptionDataItem( SID_ENCRYPTIONDATA, uno::Any( aEncryptionData ) ); m_pViewFrame->GetDispatcher()->ExecuteList( SID_OPENDOC, SfxCallMode::ASYNCHRON, { &aFile, &aItem, &aTarget, &aReferer, &aEncryptionDataItem }); } else { m_pViewFrame->GetDispatcher()->ExecuteList( SID_OPENDOC, SfxCallMode::ASYNCHRON, { &aFile, &aItem, &aTarget, &aReferer }); } m_xDialog->response(RET_OK); } IMPL_LINK_NOARG(SfxVersionDialog, DClickHdl_Impl, weld::TreeView&, bool) { Open_Impl(); return true; } IMPL_LINK_NOARG(SfxVersionDialog, SelectHdl_Impl, weld::TreeView&, void) { bool bEnable = m_xVersionBox->get_selected_index() != -1; SfxObjectShell* pObjShell = m_pViewFrame->GetObjectShell(); m_xDeleteButton->set_sensitive(bEnable && !pObjShell->IsReadOnly()); m_xOpenButton->set_sensitive(bEnable); m_xViewButton->set_sensitive(bEnable); SfxPoolItemHolder aResult; m_pViewFrame->GetDispatcher()->QueryState(SID_DOCUMENT_MERGE, aResult); SfxItemState eState = m_pViewFrame->GetDispatcher()->QueryState(SID_DOCUMENT_COMPARE, aResult); m_xCompareButton->set_sensitive(bEnable && eState >= SfxItemState::DEFAULT); } IMPL_LINK(SfxVersionDialog, ButtonHdl_Impl, weld::Button&, rButton, void) { SfxObjectShell *pObjShell = m_pViewFrame->GetObjectShell(); int nEntry = m_xVersionBox->get_selected_index(); if (&rButton == m_xSaveButton.get()) { SfxVersionInfo aInfo; aInfo.aAuthor = SvtUserOptions().GetFullName(); SfxViewVersionDialog_Impl aDlg(m_xDialog.get(), aInfo, true); short nRet = aDlg.run(); if (nRet == RET_OK) { SfxStringItem aComment( SID_DOCINFO_COMMENTS, aInfo.aComment ); pObjShell->SetModified(); const SfxPoolItem* aItems[2]; aItems[0] = &aComment; aItems[1] = nullptr; m_pViewFrame->GetBindings().ExecuteSynchron( SID_SAVEDOC, aItems ); m_xVersionBox->freeze(); m_xVersionBox->clear(); m_xVersionBox->thaw(); Init_Impl(); } } else if (&rButton == m_xDeleteButton.get() && nEntry != -1) { SfxVersionInfo* pInfo = weld::fromId(m_xVersionBox->get_id(nEntry)); pObjShell->GetMedium()->RemoveVersion_Impl(pInfo->aName); pObjShell->SetModified(); m_xVersionBox->freeze(); m_xVersionBox->clear(); m_xVersionBox->thaw(); Init_Impl(); } else if (&rButton == m_xOpenButton.get() && nEntry != -1) { Open_Impl(); } else if (&rButton == m_xViewButton.get() && nEntry != -1) { SfxVersionInfo* pInfo = weld::fromId(m_xVersionBox->get_id(nEntry)); SfxViewVersionDialog_Impl aDlg(m_xDialog.get(), *pInfo, false); aDlg.run(); } else if (&rButton == m_xCompareButton.get() && nEntry != -1) { SfxAllItemSet aSet( pObjShell->GetPool() ); aSet.Put(SfxInt16Item(SID_VERSION, nEntry + 1)); aSet.Put(SfxStringItem(SID_FILE_NAME, pObjShell->GetMedium()->GetName())); SfxItemSet& rSet = pObjShell->GetMedium()->GetItemSet(); const SfxStringItem* pFilterItem = rSet.GetItem(SID_FILTER_NAME, false); const SfxStringItem* pFilterOptItem = rSet.GetItem(SID_FILE_FILTEROPTIONS, false); if ( pFilterItem ) aSet.Put( *pFilterItem ); if ( pFilterOptItem ) aSet.Put( *pFilterOptItem ); m_pViewFrame->GetDispatcher()->Execute( SID_DOCUMENT_COMPARE, SfxCallMode::ASYNCHRON, aSet ); m_xDialog->response(RET_CLOSE); } else if (&rButton == m_xCmisButton.get()) { SfxCmisVersionsDialog aDlg(m_xDialog.get(), m_pViewFrame); aDlg.run(); } } IMPL_LINK(SfxVersionDialog, ToggleHdl_Impl, weld::Toggleable&, rButton, void) { if (&rButton == m_xSaveCheckBox.get()) { m_bIsSaveVersionOnClose = m_xSaveCheckBox->get_active(); } } SfxViewVersionDialog_Impl::SfxViewVersionDialog_Impl(weld::Window *pParent, SfxVersionInfo& rInfo, bool bEdit) : SfxDialogController(pParent, "sfx/ui/versioncommentdialog.ui", "VersionCommentDialog") , m_rInfo(rInfo) , m_xDateTimeText(m_xBuilder->weld_label("timestamp")) , m_xSavedByText(m_xBuilder->weld_label("author")) , m_xEdit(m_xBuilder->weld_text_view("textview")) , m_xOKButton(m_xBuilder->weld_button("ok")) , m_xCancelButton(m_xBuilder->weld_button("cancel")) , m_xCloseButton(m_xBuilder->weld_button("close")) { OUString sAuthor = rInfo.aAuthor.isEmpty() ? SfxResId(STR_NO_NAME_SET) : rInfo.aAuthor; const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() ); m_xDateTimeText->set_label(m_xDateTimeText->get_label() + formatDateTime(rInfo.aCreationDate, rLocaleWrapper, false)); m_xSavedByText->set_label(m_xSavedByText->get_label() + sAuthor); m_xEdit->set_text(rInfo.aComment); m_xEdit->set_size_request(40 * m_xEdit->get_approximate_digit_width(), 7 * m_xEdit->get_text_height()); m_xOKButton->connect_clicked(LINK(this, SfxViewVersionDialog_Impl, ButtonHdl)); if (!bEdit) { m_xOKButton->hide(); m_xCancelButton->hide(); m_xEdit->set_editable(false); m_xDialog->set_title(SfxResId(STR_VIEWVERSIONCOMMENT)); m_xCloseButton->grab_focus(); } else { m_xDateTimeText->hide(); m_xCloseButton->hide(); m_xEdit->grab_focus(); } } IMPL_LINK(SfxViewVersionDialog_Impl, ButtonHdl, weld::Button&, rButton, void) { assert(&rButton == m_xOKButton.get()); (void)rButton; m_rInfo.aComment = m_xEdit->get_text(); m_xDialog->response(RET_OK); } SfxCmisVersionsDialog::SfxCmisVersionsDialog(weld::Window* pParent, SfxViewFrame* pVwFrame) : SfxDialogController(pParent, "sfx/ui/versionscmis.ui", "VersionsCmisDialog") , m_pViewFrame(pVwFrame) , m_xVersionBox(m_xBuilder->weld_tree_view("versions")) { m_xVersionBox->set_size_request(m_xVersionBox->get_approximate_digit_width() * 90, m_xVersionBox->get_height_rows(15)); setColSizes(*m_xVersionBox); m_xVersionBox->grab_focus(); OUString sText = m_xDialog->get_title() + " " + m_pViewFrame->GetObjectShell()->GetTitle(); m_xDialog->set_title(sText); LoadVersions(); } SfxCmisVersionsDialog::~SfxCmisVersionsDialog() { } void SfxCmisVersionsDialog::LoadVersions() { SfxObjectShell *pObjShell = m_pViewFrame->GetObjectShell(); uno::Sequence < document::CmisVersion > aVersions = pObjShell->GetCmisVersions( ); m_pTable.reset(new SfxVersionTableDtor( aVersions )); for (size_t n = 0; n < m_pTable->size(); ++n) { SfxVersionInfo *pInfo = m_pTable->at( n ); OUString aEntry = formatDateTime(pInfo->aCreationDate, Application::GetSettings().GetLocaleDataWrapper(), false); m_xVersionBox->append(weld::toId(pInfo), aEntry); auto nLastRow = m_xVersionBox->n_children() - 1; m_xVersionBox->set_text(nLastRow, pInfo->aAuthor, 1); m_xVersionBox->set_text(nLastRow, ConvertWhiteSpaces_Impl(pInfo->aComment), 2); } if (auto nCount = m_pTable->size()) m_xVersionBox->select(nCount - 1); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */