/* -*- 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 <sal/config.h>
#include <com/sun/star/document/XCmisDocument.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/util/RevisionTag.hpp>
#include <com/sun/star/beans/NamedValue.hpp>
#include <officecfg/Office/Common.hxx>
#include <unotools/localedatawrapper.hxx>
#include <svl/intitem.hxx>
#include <svl/stritem.hxx>
#include <svl/itemset.hxx>
#include <unotools/useroptions.hxx>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <tools/datetime.hxx>
#include <versdlg.hxx>
#include <sfx2/strings.hrc>
#include <sfx2/dialoghelper.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/sfxresid.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/sfxsids.hrc>
#include <sfx2/dispatch.hxx>
#include <sfx2/sfxuno.hxx>
#include <memory>
#include <vector>
using namespace com::sun::star;
struct SfxVersionInfo
{
OUString aName;
OUString aComment;
OUString aAuthor;
DateTime aCreationDate;
SfxVersionInfo();
};
class SfxVersionTableDtor
{
private:
std::vector<std::unique_ptr<SfxVersionInfo>> 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<SfxVersionInfo> 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<SfxVersionInfo> 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<OUString> aAuthors;
aAuthors.insert(SvtUserOptions().GetFullName());
for (int i = 0; i < rVersionBox.n_children(); ++i)
{
aAuthors.insert(weld::fromId<SfxVersionInfo*>(rVersionBox.get_id(i))->aAuthor);
}
int nMaxAuthorWidth = nRest/4;
for (auto const& author : aAuthors)
{
nMaxAuthorWidth = std::max<int>(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, u"sfx/ui/versionsofdialog.ui"_ustr, u"VersionsOfDialog"_ustr)
, m_pViewFrame(pVwFrame)
, m_bIsSaveVersionOnClose(bIsSaveVersionOnClose)
, m_xSaveButton(m_xBuilder->weld_button(u"save"_ustr))
, m_xSaveCheckBox(m_xBuilder->weld_check_button(u"always"_ustr))
, m_xOpenButton(m_xBuilder->weld_button(u"open"_ustr))
, m_xViewButton(m_xBuilder->weld_button(u"show"_ustr))
, m_xDeleteButton(m_xBuilder->weld_button(u"delete"_ustr))
, m_xCompareButton(m_xBuilder->weld_button(u"compare"_ustr))
, m_xCmisButton(m_xBuilder->weld_button(u"cmis"_ustr))
, m_xVersionBox(m_xBuilder->weld_tree_view(u"versions"_ustr))
{
m_xVersionBox->set_size_request(m_xVersionBox->get_approximate_digit_width() * 90,
m_xVersionBox->get_height_rows(15));
setColSizes(*m_xVersionBox);
Link<weld::Button&,void> 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<document::XCmisDocument> 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, u"_blank"_ustr );
SfxStringItem aReferer( SID_REFERER, u"private:user"_ustr );
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<SfxVersionInfo*>(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<SfxVersionInfo*>(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, u"sfx/ui/versioncommentdialog.ui"_ustr, u"VersionCommentDialog"_ustr)
, m_rInfo(rInfo)
, m_xDateTimeText(m_xBuilder->weld_label(u"timestamp"_ustr))
, m_xSavedByText(m_xBuilder->weld_label(u"author"_ustr))
, m_xEdit(m_xBuilder->weld_text_view(u"textview"_ustr))
, m_xOKButton(m_xBuilder->weld_button(u"ok"_ustr))
, m_xCancelButton(m_xBuilder->weld_button(u"cancel"_ustr))
, m_xCloseButton(m_xBuilder->weld_button(u"close"_ustr))
{
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, u"sfx/ui/versionscmis.ui"_ustr, u"VersionsCmisDialog"_ustr)
, m_pViewFrame(pVwFrame)
, m_xVersionBox(m_xBuilder->weld_tree_view(u"versions"_ustr))
{
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: */
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'ExecuteList' is required to be utilized.
↑ V530 The return value of function 'ExecuteList' is required to be utilized.
↑ V530 The return value of function 'ExecuteSynchron' is required to be utilized.
↑ V530 The return value of function 'Execute' is required to be utilized.