sw: add Comments Panel in sidebar
This commit adds a sidebar deck for comments. It has all the functionalities of the old comments shown via annotation window. Change-Id: Ibab0e21a54c097d0f42bddb1d07da74319970135 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167840 Tested-by: Jenkins Reviewed-by: Sarper Akdemir <sarper.akdemir@allotropia.de>
This commit is contained in:
committed by
Sarper Akdemir
parent
59c123d62a
commit
be16c6cf5c
@@ -20,6 +20,8 @@ TOOLS_DLLPUBLIC OUString DateTimeToOUString(const DateTime& rDateTime);
|
||||
// This function converts a 'Date' object to an 'OString' object in ISO-8601 representation
|
||||
TOOLS_DLLPUBLIC OString DateToOString(const Date& rDate);
|
||||
|
||||
TOOLS_DLLPUBLIC OString TimeToOString(const tools::Time& rTime);
|
||||
|
||||
// This function converts a 'Date' object to an 'OUString' object in DD/MM/YYYY format
|
||||
TOOLS_DLLPUBLIC OUString DateToDDMMYYYYOUString(const Date& rDate);
|
||||
|
||||
|
||||
@@ -81,6 +81,29 @@
|
||||
</prop>
|
||||
</node>
|
||||
|
||||
<node oor:name="CommentsDeck" oor:op="replace">
|
||||
<prop oor:name="Title" oor:type="xs:string">
|
||||
<value xml:lang="en-US">Comments</value>
|
||||
</prop>
|
||||
<prop oor:name="IsExperimental" oor:type="xs:boolean">
|
||||
<value>true</value>
|
||||
</prop>
|
||||
<prop oor:name="Id" oor:type="xs:string">
|
||||
<value>CommentsDeck</value>
|
||||
</prop>
|
||||
<prop oor:name="IconURL" oor:type="xs:string">
|
||||
<value>private:graphicrepository/cmd/lc_showannotations.png</value>
|
||||
</prop>
|
||||
<prop oor:name="ContextList">
|
||||
<value oor:separator=";">
|
||||
WriterVariants, any, visible ;
|
||||
</value>
|
||||
</prop>
|
||||
<prop oor:name="OrderIndex" oor:type="xs:int">
|
||||
<value>900</value>
|
||||
</prop>
|
||||
</node>
|
||||
|
||||
<node oor:name="A11yCheckDeck" oor:op="replace">
|
||||
<prop oor:name="Title" oor:type="xs:string">
|
||||
<value xml:lang="en-US">Accessibility Check</value>
|
||||
@@ -618,6 +641,41 @@
|
||||
</prop>
|
||||
</node>
|
||||
|
||||
<node oor:name="CommentsPanel" oor:op="replace">
|
||||
<prop oor:name="Title" oor:type="xs:string">
|
||||
<value xml:lang="en-US">Comments</value>
|
||||
</prop>
|
||||
<prop oor:name="IsExperimental" oor:type="xs:boolean">
|
||||
<value>true</value>
|
||||
</prop>
|
||||
<prop oor:name="TitleBarIsOptional" oor:type="xs:boolean">
|
||||
<value>true</value>
|
||||
</prop>
|
||||
<prop oor:name="Id" oor:type="xs:string">
|
||||
<value>CommentsPanel</value>
|
||||
</prop>
|
||||
<prop oor:name="DeckId" oor:type="xs:string">
|
||||
<value>CommentsDeck</value>
|
||||
</prop>
|
||||
<prop oor:name="DefaultMenuCommand">
|
||||
<value></value>
|
||||
</prop>
|
||||
<prop oor:name="ContextList">
|
||||
<value oor:separator=";">
|
||||
WriterVariants, any, visible ;
|
||||
</value>
|
||||
</prop>
|
||||
<prop oor:name="ImplementationURL" oor:type="xs:string">
|
||||
<value>private:resource/toolpanel/SwPanelFactory/CommentsPanel</value>
|
||||
</prop>
|
||||
<prop oor:name="OrderIndex" oor:type="xs:int">
|
||||
<value>100</value>
|
||||
</prop>
|
||||
<prop oor:name="WantsAWT" oor:type="xs:boolean">
|
||||
<value>false</value>
|
||||
</prop>
|
||||
</node>
|
||||
|
||||
<node oor:name="A11yCheckIssuesPanel" oor:op="replace">
|
||||
<prop oor:name="Title" oor:type="xs:string">
|
||||
<value xml:lang="en-US">Accessibility Issues</value>
|
||||
|
||||
@@ -735,6 +735,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
|
||||
sw/source/uibase/sidebar/ThemePanel \
|
||||
sw/source/uibase/sidebar/SwPanelFactory \
|
||||
sw/source/uibase/sidebar/WriterInspectorTextPanel \
|
||||
sw/source/uibase/sidebar/CommentsPanel \
|
||||
sw/source/uibase/sidebar/A11yCheckIssuesPanel \
|
||||
sw/source/uibase/sidebar/QuickFindPanel \
|
||||
sw/source/uibase/table/chartins \
|
||||
|
||||
@@ -285,6 +285,9 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/swriter,\
|
||||
sw/uiconfig/swriter/ui/pagestylespanel \
|
||||
sw/uiconfig/swriter/ui/pageheaderpanel \
|
||||
sw/uiconfig/swriter/ui/pagefooterpanel \
|
||||
sw/uiconfig/swriter/ui/commentspanel \
|
||||
sw/uiconfig/swriter/ui/commentsthread \
|
||||
sw/uiconfig/swriter/ui/commentwidget \
|
||||
sw/uiconfig/swriter/ui/a11ycheckissuespanel \
|
||||
sw/uiconfig/swriter/ui/poseditbox \
|
||||
sw/uiconfig/swriter/ui/sidebarwrap \
|
||||
|
||||
@@ -71,6 +71,7 @@ class SAL_DLLPUBLIC_RTTI SwAnnotationWin final : public InterimItemWindow
|
||||
void Delete();
|
||||
void GotoPos();
|
||||
const SwPostItField* GetPostItField() const { return mpField; }
|
||||
SwFormatField* GetFormatField() const { return mpFormatField; }
|
||||
void UpdateText(const OUString& aText);
|
||||
|
||||
OUString GetAuthor() const;
|
||||
|
||||
@@ -82,7 +82,8 @@ struct FieldShadowState
|
||||
}
|
||||
};
|
||||
|
||||
class SAL_DLLPUBLIC_RTTI SwPostItMgr final : public SfxListener
|
||||
class SAL_DLLPUBLIC_RTTI SwPostItMgr final : public SfxListener,
|
||||
public SfxBroadcaster
|
||||
{
|
||||
private:
|
||||
SwView* mpView;
|
||||
@@ -141,9 +142,11 @@ class SAL_DLLPUBLIC_RTTI SwPostItMgr final : public SfxListener
|
||||
typedef std::vector< std::unique_ptr<SwSidebarItem> >::const_iterator const_iterator;
|
||||
const_iterator begin() const { return mvPostItFields.begin(); }
|
||||
const_iterator end() const { return mvPostItFields.end(); }
|
||||
const std::vector<std::unique_ptr<SwSidebarItem>>& GetPostItFields() { return mvPostItFields; }
|
||||
|
||||
void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
|
||||
|
||||
std::vector<SwFormatField*> UpdatePostItsParentInfo();
|
||||
void LayoutPostIts();
|
||||
bool CalcRects();
|
||||
|
||||
@@ -169,6 +172,8 @@ class SAL_DLLPUBLIC_RTTI SwPostItMgr final : public SfxListener
|
||||
void ToggleResolved(sal_uInt32 nPostItId);
|
||||
void ToggleResolvedForThread(sal_uInt32 nPostItId);
|
||||
|
||||
sw::annotation::SwAnnotationWin* GetRemovedAnnotationWin(const SfxBroadcaster* pBroadcast);
|
||||
|
||||
void ExecuteFormatAllDialog(SwView& rView);
|
||||
void FormatAll(const SfxItemSet &rNewAttr);
|
||||
|
||||
|
||||
@@ -319,6 +319,17 @@ SwSidebarItem* SwPostItMgr::InsertItem(SfxBroadcaster* pItem, bool bCheckExisten
|
||||
return pAnnotationItem;
|
||||
}
|
||||
|
||||
sw::annotation::SwAnnotationWin* SwPostItMgr::GetRemovedAnnotationWin( const SfxBroadcaster* pBroadcast )
|
||||
{
|
||||
auto i = std::find_if(mvPostItFields.begin(), mvPostItFields.end(),
|
||||
[&pBroadcast](const std::unique_ptr<SwSidebarItem>& pField) { return pField->GetBroadcaster() == pBroadcast; });
|
||||
if (i != mvPostItFields.end())
|
||||
{
|
||||
return (*i)->mpPostIt;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SwPostItMgr::RemoveItem( SfxBroadcaster* pBroadcast )
|
||||
{
|
||||
EndListening(*pBroadcast);
|
||||
@@ -400,6 +411,7 @@ void SwPostItMgr::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
|
||||
mbLayout = true;
|
||||
break;
|
||||
}
|
||||
this->Broadcast(rHint);
|
||||
RemoveItem(pField);
|
||||
|
||||
// If LOK has disabled tiled annotations, emit annotation callbacks
|
||||
@@ -430,6 +442,7 @@ void SwPostItMgr::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
|
||||
{
|
||||
postItField->mpPostIt->SetPostItText();
|
||||
mbLayout = true;
|
||||
this->Forward(rBC, rHint);
|
||||
}
|
||||
|
||||
// If LOK has disabled tiled annotations, emit annotation callbacks
|
||||
@@ -821,6 +834,9 @@ void SwPostItMgr::LayoutPostIts()
|
||||
if (pPostIt)
|
||||
pPostIt->HideNote();
|
||||
}
|
||||
SwFormatField* pFormatField = &(pItem->GetFormatField());
|
||||
SwFormatFieldHintWhich nWhich = SwFormatFieldHintWhich::INSERTED;
|
||||
this->Broadcast(SwFormatFieldHint(pFormatField, nWhich, mpView));
|
||||
}
|
||||
|
||||
if (!aVisiblePostItList.empty() && ShowNotes())
|
||||
@@ -1331,9 +1347,8 @@ bool SwPostItMgr::LayoutByPage(std::vector<SwAnnotationWin*> &aVisiblePostItList
|
||||
return bScrollbars;
|
||||
}
|
||||
|
||||
void SwPostItMgr::AddPostIts(const bool bCheckExistence, const bool bFocus)
|
||||
std::vector<SwFormatField*> SwPostItMgr::UpdatePostItsParentInfo()
|
||||
{
|
||||
const bool bEmpty = mvPostItFields.empty();
|
||||
IDocumentRedlineAccess const& rIDRA(mpWrtShell->getIDocumentRedlineAccess());
|
||||
SwFieldType* pType = mpView->GetDocShell()->GetDoc()->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Postit, OUString(),false);
|
||||
std::vector<SwFormatField*> vFormatFields;
|
||||
@@ -1361,6 +1376,14 @@ void SwPostItMgr::AddPostIts(const bool bCheckExistence, const bool bFocus)
|
||||
}
|
||||
}
|
||||
}
|
||||
return vFormatFields;
|
||||
}
|
||||
|
||||
|
||||
void SwPostItMgr::AddPostIts(const bool bCheckExistence, const bool bFocus)
|
||||
{
|
||||
const bool bEmpty = mvPostItFields.empty();
|
||||
std::vector<SwFormatField*> vFormatFields = UpdatePostItsParentInfo();
|
||||
|
||||
for(auto pFormatField : vFormatFields)
|
||||
InsertItem(pFormatField, bCheckExistence, bFocus);
|
||||
|
||||
@@ -0,0 +1,443 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||
/*
|
||||
* 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 <sfx2/bindings.hxx>
|
||||
|
||||
#include <PostItMgr.hxx>
|
||||
#include <postithelper.hxx>
|
||||
#include <AnnotationWin.hxx>
|
||||
#include <fmtfld.hxx>
|
||||
#include <docufld.hxx>
|
||||
#include <swmodule.hxx>
|
||||
#include <vcl/svapp.hxx>
|
||||
#include <rtl/ustring.hxx>
|
||||
#include <xmloff/xmlmetae.hxx>
|
||||
#include <tools/datetimeutils.hxx>
|
||||
#include <swtypes.hxx>
|
||||
#include <view.hxx>
|
||||
#include <wrtsh.hxx>
|
||||
#include <tools/date.hxx>
|
||||
#include <tools/datetime.hxx>
|
||||
#include <tools/time.hxx>
|
||||
#include <unotools/localedatawrapper.hxx>
|
||||
#include <unotools/syslocale.hxx>
|
||||
#include <tools/link.hxx>
|
||||
#include <editeng/outliner.hxx>
|
||||
#include <editeng/editeng.hxx>
|
||||
|
||||
#include <strings.hrc>
|
||||
#include <cmdid.h>
|
||||
|
||||
#include "CommentsPanel.hxx"
|
||||
|
||||
#include <com/sun/star/lang/IllegalArgumentException.hpp>
|
||||
|
||||
namespace sw::sidebar
|
||||
{
|
||||
Comment::Comment(weld::Container* pParent, CommentsPanel& rCommentsPanel)
|
||||
: mxBuilder(Application::CreateBuilder(pParent, "modules/swriter/ui/commentwidget.ui"))
|
||||
, mxContainer(mxBuilder->weld_container("Comment"))
|
||||
, mxAuthor(mxBuilder->weld_label("authorlabel"))
|
||||
, mxDate(mxBuilder->weld_label("datelabel"))
|
||||
, mxTime(mxBuilder->weld_label("timelabel"))
|
||||
, mxReply(mxBuilder->weld_button("replybutton"))
|
||||
, mxResolve(mxBuilder->weld_check_button("resolvebutton"))
|
||||
, mxTextView(mxBuilder->weld_text_view("textview"))
|
||||
, mrCommentsPanel(rCommentsPanel)
|
||||
, maDate(Date::EMPTY)
|
||||
, maTime(tools::Time::EMPTY)
|
||||
, mbResolved(false)
|
||||
{
|
||||
mxTextView->connect_focus_out(LINK(this, Comment, OnFocusOut));
|
||||
mxResolve->connect_toggled(LINK(this, Comment, ResolveClicked));
|
||||
mxReply->connect_clicked(LINK(this, Comment, ReplyClicked));
|
||||
}
|
||||
|
||||
Comment::~Comment() {}
|
||||
|
||||
void Comment::InitControls(const SwPostItField* pPostItField)
|
||||
{
|
||||
if (!pPostItField)
|
||||
return;
|
||||
msText = pPostItField->GetText();
|
||||
msAuthor = pPostItField->GetPar1();
|
||||
msInitials = pPostItField->GetInitials();
|
||||
msName = pPostItField->GetName();
|
||||
maDate = Date(pPostItField->GetDateTime().GetDate());
|
||||
maTime = tools::Time(pPostItField->GetDateTime().GetTime());
|
||||
mbResolved = pPostItField->GetResolved();
|
||||
|
||||
// Format date and time according to the system locale
|
||||
const SvtSysLocale aSysLocale;
|
||||
const LocaleDataWrapper& rLocalData = aSysLocale.GetLocaleData();
|
||||
OUString sMeta;
|
||||
if (maDate.IsValidAndGregorian())
|
||||
{
|
||||
sMeta = rLocalData.getDate(maDate);
|
||||
}
|
||||
else
|
||||
{
|
||||
sMeta = SwResId(STR_NODATE);
|
||||
}
|
||||
if (mxDate->get_label() != sMeta)
|
||||
{
|
||||
mxDate->set_label(sMeta);
|
||||
}
|
||||
if (pPostItField->GetTime().GetTime() != 0)
|
||||
{
|
||||
sMeta = " " + rLocalData.getTime(pPostItField->GetTime(), false);
|
||||
}
|
||||
if (mxTime->get_label() != sMeta)
|
||||
{
|
||||
mxTime->set_label(sMeta);
|
||||
}
|
||||
|
||||
mxAuthor->set_label(msAuthor);
|
||||
mxAuthor->set_tooltip_text(msAuthor);
|
||||
mxResolve->set_active(mbResolved);
|
||||
mxTextView->set_text(msText);
|
||||
}
|
||||
|
||||
IMPL_LINK_NOARG(Comment, OnFocusOut, weld::Widget&, void) { mrCommentsPanel.EditComment(this); }
|
||||
|
||||
IMPL_LINK_NOARG(Comment, ResolveClicked, weld::Toggleable&, void)
|
||||
{
|
||||
mrCommentsPanel.ToggleResolved(this);
|
||||
}
|
||||
|
||||
IMPL_LINK_NOARG(Comment, ReplyClicked, weld::Button&, void) { mrCommentsPanel.ReplyComment(this); }
|
||||
|
||||
Thread::Thread(weld::Container* pParent)
|
||||
: mxBuilder(Application::CreateBuilder(pParent, "modules/swriter/ui/commentsthread.ui"))
|
||||
, mxContainer(mxBuilder->weld_container("Thread"))
|
||||
, mxCommentBox(mxBuilder->weld_box("comments_box"))
|
||||
, mxText(mxBuilder->weld_label("commentedtext"))
|
||||
{
|
||||
// mxContainer->set_size_request(-1, mxContainer->get_preferred_size().Height());
|
||||
}
|
||||
|
||||
Thread::~Thread() {}
|
||||
|
||||
std::unique_ptr<PanelLayout> CommentsPanel::Create(weld::Widget* pParent)
|
||||
{
|
||||
if (pParent == nullptr)
|
||||
throw ::com::sun::star::lang::IllegalArgumentException(
|
||||
"no parent window given to CommentsPanel::Create", nullptr, 0);
|
||||
return std::make_unique<CommentsPanel>(pParent);
|
||||
}
|
||||
|
||||
CommentsPanel::CommentsPanel(weld::Widget* pParent)
|
||||
: PanelLayout(pParent, "CommentsPanel", "modules/swriter/ui/commentspanel.ui")
|
||||
, mpPostItMgr(nullptr)
|
||||
, mxFilterAuthor(m_xBuilder->weld_combo_box("filter_author"))
|
||||
, mxFilterTime(m_xBuilder->weld_combo_box("filter_time"))
|
||||
, mxShowTime(m_xBuilder->weld_check_button("show_time"))
|
||||
, mxShowResolved(m_xBuilder->weld_check_button("show_resolved"))
|
||||
, mxShowReference(m_xBuilder->weld_check_button("show_reference"))
|
||||
, mxSortbyPosition(m_xBuilder->weld_radio_button("sortby_position"))
|
||||
, mxSortbyTime(m_xBuilder->weld_radio_button("sortby_time"))
|
||||
, mxThreadsContainer(m_xBuilder->weld_box("comment_threads"))
|
||||
{
|
||||
SwView* pView = GetActiveView();
|
||||
if (!pView)
|
||||
return;
|
||||
SwWrtShell& rSh = pView->GetWrtShell();
|
||||
mpPostItMgr = rSh.GetPostItMgr();
|
||||
populateComments();
|
||||
|
||||
StartListening(*mpPostItMgr);
|
||||
}
|
||||
|
||||
void CommentsPanel::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
|
||||
{
|
||||
if (rHint.GetId() == SfxHintId::SwFormatField)
|
||||
{
|
||||
const SwFormatFieldHint* pFormatHint = static_cast<const SwFormatFieldHint*>(&rHint);
|
||||
const SwFormatField* pField = pFormatHint->GetField();
|
||||
switch (pFormatHint->Which())
|
||||
{
|
||||
case SwFormatFieldHintWhich::INSERTED:
|
||||
{
|
||||
if (!pField)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// get field to be inserted from hint
|
||||
if (pField->IsFieldInDoc())
|
||||
{
|
||||
addComment(pField);
|
||||
}
|
||||
else
|
||||
{
|
||||
OSL_FAIL("Inserted field not in document!");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SwFormatFieldHintWhich::REMOVED:
|
||||
case SwFormatFieldHintWhich::REDLINED_DELETION:
|
||||
{
|
||||
sw::annotation::SwAnnotationWin* pAnnotationWin
|
||||
= mpPostItMgr->GetRemovedAnnotationWin(pField);
|
||||
deleteComment(pAnnotationWin);
|
||||
break;
|
||||
}
|
||||
case SwFormatFieldHintWhich::FOCUS:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case SwFormatFieldHintWhich::CHANGED:
|
||||
case SwFormatFieldHintWhich::RESOLVED:
|
||||
{
|
||||
SwFormatField* pFormatField = dynamic_cast<SwFormatField*>(&rBC);
|
||||
SwPostItField* pPostItField = static_cast<SwPostItField*>(pFormatField->GetField());
|
||||
sw::annotation::SwAnnotationWin* pAnnotationWin
|
||||
= mpPostItMgr->GetAnnotationWin(pPostItField);
|
||||
setResolvedStatus(pAnnotationWin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sw::annotation::SwAnnotationWin* CommentsPanel::getRootCommentWin(const SwFormatField* pFormatField)
|
||||
{
|
||||
if (!pFormatField)
|
||||
return nullptr;
|
||||
const SwPostItField* pPostItField = static_cast<const SwPostItField*>(pFormatField->GetField());
|
||||
sw::annotation::SwAnnotationWin* pAnnotationWin = mpPostItMgr->GetAnnotationWin(pPostItField);
|
||||
if (!pAnnotationWin)
|
||||
return nullptr;
|
||||
sw::annotation::SwAnnotationWin* pRootNote = pAnnotationWin->GetTopReplyNote();
|
||||
return pRootNote;
|
||||
}
|
||||
|
||||
sal_uInt32 CommentsPanel::getPostItId(sw::annotation::SwAnnotationWin* pAnnotationWin)
|
||||
{
|
||||
const SwPostItField* pField = pAnnotationWin->GetPostItField();
|
||||
return pField->GetPostItId();
|
||||
}
|
||||
|
||||
sw::annotation::SwAnnotationWin* CommentsPanel::getAnnotationWin(Comment* pComment)
|
||||
{
|
||||
sal_uInt32 nPostItId = 0;
|
||||
for (auto & [ rId, rComment ] : mpCommentsMap)
|
||||
{
|
||||
if (rComment.get() != pComment)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
nPostItId = rId;
|
||||
break;
|
||||
}
|
||||
auto& vPostItFields = mpPostItMgr->GetPostItFields();
|
||||
SwPostItField* pPostItField = nullptr;
|
||||
for (auto& pItem : vPostItFields)
|
||||
{
|
||||
SwFormatField* pFormatField = &pItem->GetFormatField();
|
||||
SwPostItField* pField = static_cast<SwPostItField*>(pFormatField->GetField());
|
||||
if (pField->GetPostItId() == nPostItId)
|
||||
{
|
||||
pPostItField = pField;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return mpPostItMgr->GetAnnotationWin(pPostItField);
|
||||
}
|
||||
|
||||
void CommentsPanel::populateComments()
|
||||
{
|
||||
if (!mpPostItMgr)
|
||||
return;
|
||||
std::vector<SwFormatField*> vFormatFields = mpPostItMgr->UpdatePostItsParentInfo();
|
||||
|
||||
for (auto pFormatField : vFormatFields)
|
||||
{
|
||||
sw::annotation::SwAnnotationWin* pRootNote = getRootCommentWin(pFormatField);
|
||||
if (!pRootNote)
|
||||
continue;
|
||||
sal_uInt32 nPostItId = getPostItId(pRootNote);
|
||||
|
||||
if (mpThreadsMap.find(nPostItId) != mpThreadsMap.end())
|
||||
continue; // Skip if root comment is already present
|
||||
|
||||
auto pThread = std::make_unique<Thread>(mxThreadsContainer.get());
|
||||
mxThreadsContainer->reorder_child(pThread->get_widget(), mnThreads++);
|
||||
|
||||
for (sw::annotation::SwAnnotationWin* pCurrent = pRootNote;;)
|
||||
{
|
||||
sal_uInt32 nId = getPostItId(pCurrent);
|
||||
auto pComment = std::make_unique<Comment>(pThread->getCommentBoxWidget(), *this);
|
||||
pThread->getCommentBoxWidget()->reorder_child(pComment->get_widget(),
|
||||
pThread->mnComments++);
|
||||
pComment->InitControls(pCurrent->GetPostItField());
|
||||
mpCommentsMap[nId] = std::move(pComment);
|
||||
sw::annotation::SwAnnotationWin* next
|
||||
= mpPostItMgr->GetNextPostIt(KEY_PAGEDOWN, pCurrent);
|
||||
if (!next || next->GetTopReplyNote() != pRootNote)
|
||||
break;
|
||||
pCurrent = next;
|
||||
}
|
||||
mpThreadsMap[nPostItId] = std::move(pThread);
|
||||
}
|
||||
}
|
||||
|
||||
void CommentsPanel::addComment(const SwFormatField* pField)
|
||||
{
|
||||
// Get id of the note
|
||||
const SwPostItField* pPostItField = static_cast<const SwPostItField*>(pField->GetField());
|
||||
sal_uInt32 nNoteId = pPostItField->GetPostItId();
|
||||
|
||||
if (mpCommentsMap.contains(nNoteId))
|
||||
return;
|
||||
|
||||
// Get id of the root note
|
||||
sw::annotation::SwAnnotationWin* pRootNote = getRootCommentWin(pField);
|
||||
if (!pRootNote)
|
||||
return;
|
||||
sal_uInt32 nRootId = getPostItId(pRootNote);
|
||||
|
||||
sw::annotation::SwAnnotationWin* pNote
|
||||
= mpPostItMgr->GetAnnotationWin(static_cast<const SwPostItField*>(pField->GetField()));
|
||||
// If comment is added to an existing thread
|
||||
if (mpThreadsMap.find(nRootId) != mpThreadsMap.end())
|
||||
{
|
||||
auto& pThread = mpThreadsMap[nRootId];
|
||||
auto pComment = std::make_unique<Comment>(pThread->getCommentBoxWidget(), *this);
|
||||
pThread->getCommentBoxWidget()->reorder_child(pComment->get_widget(),
|
||||
pThread->mnComments++);
|
||||
pComment->InitControls(pNote->GetPostItField());
|
||||
mpCommentsMap[nNoteId] = std::move(pComment);
|
||||
}
|
||||
// If a new thread is created
|
||||
else
|
||||
{
|
||||
auto pThread = std::make_unique<Thread>(mxThreadsContainer.get());
|
||||
mxThreadsContainer->reorder_child(pThread->get_widget(), mnThreads++);
|
||||
auto pComment = std::make_unique<Comment>(pThread->getCommentBoxWidget(), *this);
|
||||
pThread->getCommentBoxWidget()->reorder_child(pComment->get_widget(),
|
||||
pThread->mnComments++);
|
||||
mpThreadsMap[nRootId] = std::move(pThread);
|
||||
pComment->InitControls(pNote->GetPostItField());
|
||||
mpCommentsMap[nNoteId] = std::move(pComment);
|
||||
}
|
||||
}
|
||||
|
||||
void CommentsPanel::deleteComment(sw::annotation::SwAnnotationWin* pAnnotationWin)
|
||||
{
|
||||
if (!pAnnotationWin)
|
||||
return;
|
||||
sal_uInt32 nId = getPostItId(pAnnotationWin);
|
||||
SwFormatField* pFormatField = pAnnotationWin->GetFormatField();
|
||||
sw::annotation::SwAnnotationWin* pRootNote = nullptr;
|
||||
// If the root comment is deleted, the new root comment of the thread should be the next comment in the thread
|
||||
// but due to a bug `getRootCommentWin` returns root comment of some other/random thread so we completely lose
|
||||
// access to the current thread.
|
||||
if (mpThreadsMap.find(nId) != mpThreadsMap.end())
|
||||
{
|
||||
pRootNote = pAnnotationWin;
|
||||
}
|
||||
else
|
||||
{
|
||||
pRootNote = getRootCommentWin(pFormatField);
|
||||
}
|
||||
|
||||
sal_uInt32 nRootId = getPostItId(pRootNote);
|
||||
|
||||
if (mpThreadsMap.find(nRootId) == mpThreadsMap.end())
|
||||
return;
|
||||
auto& pComment = mpCommentsMap[nId];
|
||||
auto& pThread = mpThreadsMap[nRootId];
|
||||
if (!pComment)
|
||||
return;
|
||||
|
||||
pThread->getCommentBoxWidget()->move(pComment->get_widget(), nullptr);
|
||||
mpCommentsMap.erase(nId);
|
||||
|
||||
// If the last comment in the thread is deleted, delete the thread
|
||||
if (--pThread->mnComments == 0)
|
||||
{
|
||||
mxThreadsContainer->move(pThread->get_widget(), nullptr);
|
||||
if (mpThreadsMap.find(nRootId) != mpThreadsMap.end())
|
||||
mpThreadsMap.erase(nRootId);
|
||||
}
|
||||
}
|
||||
|
||||
void CommentsPanel::setResolvedStatus(sw::annotation::SwAnnotationWin* pAnnotationWin)
|
||||
{
|
||||
sal_uInt32 nId = getPostItId(pAnnotationWin);
|
||||
if (mpCommentsMap.find(nId) == mpCommentsMap.end())
|
||||
return;
|
||||
auto& pComment = mpCommentsMap[nId];
|
||||
if (!pComment)
|
||||
return;
|
||||
SwPostItField* pPostItField = const_cast<SwPostItField*>(pAnnotationWin->GetPostItField());
|
||||
if (pPostItField->GetResolved() == pComment->mbResolved)
|
||||
{
|
||||
editComment(pPostItField, pComment.get());
|
||||
return;
|
||||
}
|
||||
pComment->mbResolved = pPostItField->GetResolved();
|
||||
pComment->mxResolve->set_active(pComment->mbResolved);
|
||||
}
|
||||
|
||||
void CommentsPanel::editComment(SwPostItField* pPostItField, Comment* pComment)
|
||||
{
|
||||
OUString sText = pPostItField->GetText();
|
||||
pComment->SetCommentText(sText);
|
||||
pComment->mxTextView->set_text(sText);
|
||||
}
|
||||
|
||||
void CommentsPanel::EditComment(Comment* pComment)
|
||||
{
|
||||
if (!pComment)
|
||||
return;
|
||||
const OUString sText = pComment->mxTextView->get_text();
|
||||
|
||||
sw::annotation::SwAnnotationWin* pWin = getAnnotationWin(pComment);
|
||||
Outliner* pOutliner = pWin->GetOutliner();
|
||||
pOutliner->Clear();
|
||||
pOutliner->SetText(sText, pOutliner->GetParagraph(0));
|
||||
}
|
||||
|
||||
void CommentsPanel::ToggleResolved(Comment* pComment)
|
||||
{
|
||||
if (!pComment)
|
||||
return;
|
||||
sw::annotation::SwAnnotationWin* pWin = getAnnotationWin(pComment);
|
||||
pWin->ToggleResolved();
|
||||
}
|
||||
|
||||
void CommentsPanel::ReplyComment(Comment* pComment)
|
||||
{
|
||||
if (!pComment)
|
||||
return;
|
||||
sw::annotation::SwAnnotationWin* pWin = getAnnotationWin(pComment);
|
||||
pWin->ExecuteCommand(FN_REPLY);
|
||||
}
|
||||
|
||||
CommentsPanel::~CommentsPanel() {}
|
||||
|
||||
void CommentsPanel::NotifyItemUpdate(const sal_uInt16 /*nSid*/, const SfxItemState /* eState */,
|
||||
const SfxPoolItem* pState)
|
||||
{
|
||||
if (!pState) //disposed
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||
/*
|
||||
* 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 .
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <sfx2/sidebar/PanelLayout.hxx>
|
||||
#include <sfx2/sidebar/ControllerItem.hxx>
|
||||
#include <AnnotationWin.hxx>
|
||||
#include <svl/poolitem.hxx>
|
||||
#include <tools/link.hxx>
|
||||
#include <vcl/weld.hxx>
|
||||
#include <PostItMgr.hxx>
|
||||
#include <postithelper.hxx>
|
||||
#include <view.hxx>
|
||||
#include <tools/date.hxx>
|
||||
#include <tools/datetime.hxx>
|
||||
#include <tools/time.hxx>
|
||||
|
||||
class SwWrtShell;
|
||||
class SwView;
|
||||
class SwPostItField;
|
||||
class SwFormatField;
|
||||
class SwAnnotationWin;
|
||||
class SfxBroadcaster;
|
||||
class SwPostItMgr;
|
||||
class SwSidebarItem;
|
||||
|
||||
namespace sw::sidebar
|
||||
{
|
||||
class CommentsPanel;
|
||||
class Comment final
|
||||
{
|
||||
friend class CommentsPanel;
|
||||
|
||||
private:
|
||||
std::unique_ptr<weld::Builder> mxBuilder;
|
||||
std::unique_ptr<weld::Container> mxContainer;
|
||||
std::unique_ptr<weld::Label> mxAuthor;
|
||||
std::unique_ptr<weld::Label> mxDate;
|
||||
std::unique_ptr<weld::Label> mxTime;
|
||||
std::unique_ptr<weld::Button> mxReply;
|
||||
std::unique_ptr<weld::CheckButton> mxResolve;
|
||||
std::unique_ptr<weld::TextView> mxTextView;
|
||||
|
||||
sw::sidebar::CommentsPanel& mrCommentsPanel;
|
||||
OUString msText;
|
||||
OUString msAuthor;
|
||||
OUString msInitials; //Initials of Author.
|
||||
OUString msName; //Name of the comment
|
||||
Date maDate;
|
||||
tools::Time maTime;
|
||||
|
||||
public:
|
||||
Comment(weld::Container* pParent, CommentsPanel& rCommentsPanel);
|
||||
~Comment();
|
||||
weld::Widget* get_widget() const { return mxContainer.get(); }
|
||||
|
||||
DECL_LINK(ReplyClicked, weld::Button&, void);
|
||||
DECL_LINK(ResolveClicked, weld::Toggleable&, void);
|
||||
DECL_LINK(OnFocusOut, weld::Widget&, void);
|
||||
|
||||
bool mbResolved;
|
||||
|
||||
void InitControls(const SwPostItField* pPostItField);
|
||||
void SetCommentText(OUString sText) { msText = sText; }
|
||||
};
|
||||
|
||||
class Thread final
|
||||
{
|
||||
friend class CommentsPanel;
|
||||
|
||||
private:
|
||||
std::unique_ptr<weld::Builder> mxBuilder;
|
||||
std::unique_ptr<weld::Container> mxContainer;
|
||||
std::unique_ptr<weld::Box> mxCommentBox;
|
||||
std::unique_ptr<weld::Label> mxText;
|
||||
|
||||
public:
|
||||
Thread(weld::Container* pParent);
|
||||
~Thread();
|
||||
weld::Widget* get_widget() const { return mxContainer.get(); }
|
||||
weld::Box* getCommentBoxWidget() const { return mxCommentBox.get(); }
|
||||
|
||||
sal_uInt16 mnComments = 0;
|
||||
};
|
||||
|
||||
class CommentsPanel : public PanelLayout,
|
||||
public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface,
|
||||
public SfxListener
|
||||
{
|
||||
public:
|
||||
static std::unique_ptr<PanelLayout> Create(weld::Widget* pParent);
|
||||
|
||||
virtual void NotifyItemUpdate(const sal_uInt16 nSId, const SfxItemState eState,
|
||||
const SfxPoolItem* pState) override;
|
||||
|
||||
virtual void GetControlState(const sal_uInt16 /*nSId*/,
|
||||
boost::property_tree::ptree& /*rState*/) override{};
|
||||
|
||||
CommentsPanel(weld::Widget* pParent);
|
||||
virtual ~CommentsPanel() override;
|
||||
|
||||
void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
|
||||
|
||||
void EditComment(Comment* pComment);
|
||||
|
||||
void ToggleResolved(Comment* pComment);
|
||||
|
||||
void ReplyComment(Comment* pComment);
|
||||
|
||||
private:
|
||||
SwPostItMgr* mpPostItMgr;
|
||||
|
||||
std::unordered_map<sal_uInt32, std::unique_ptr<Thread>> mpThreadsMap;
|
||||
std::unordered_map<sal_uInt32, std::unique_ptr<Comment>> mpCommentsMap;
|
||||
std::unique_ptr<weld::ComboBox> mxFilterAuthor;
|
||||
std::unique_ptr<weld::ComboBox> mxFilterTime;
|
||||
std::unique_ptr<weld::CheckButton> mxShowTime;
|
||||
std::unique_ptr<weld::CheckButton> mxShowResolved;
|
||||
std::unique_ptr<weld::CheckButton> mxShowReference;
|
||||
std::unique_ptr<weld::RadioButton> mxSortbyPosition;
|
||||
std::unique_ptr<weld::RadioButton> mxSortbyTime;
|
||||
std::unique_ptr<weld::Box> mxThreadsContainer;
|
||||
|
||||
sal_uInt16 mnThreads = 0;
|
||||
|
||||
sw::annotation::SwAnnotationWin* getRootCommentWin(const SwFormatField* pField);
|
||||
static sal_uInt32 getPostItId(sw::annotation::SwAnnotationWin* pAnnotationWin);
|
||||
sw::annotation::SwAnnotationWin* getAnnotationWin(Comment* pComment);
|
||||
|
||||
void populateComments();
|
||||
void addComment(const SwFormatField* pField);
|
||||
void deleteComment(sw::annotation::SwAnnotationWin* pAnnotationWin);
|
||||
void setResolvedStatus(sw::annotation::SwAnnotationWin* pAnnotationWin);
|
||||
static void editComment(SwPostItField* pPostItField, Comment* pComment);
|
||||
};
|
||||
|
||||
} //end of namespace sw::sidebar
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <com/sun/star/ui/XUIElementFactory.hpp>
|
||||
|
||||
#include "A11yCheckIssuesPanel.hxx"
|
||||
#include "CommentsPanel.hxx"
|
||||
#include "ThemePanel.hxx"
|
||||
#include "StylePresetsPanel.hxx"
|
||||
#include "PageStylesPanel.hxx"
|
||||
@@ -40,6 +41,7 @@
|
||||
#include <comphelper/namedvaluecollection.hxx>
|
||||
#include <comphelper/compbase.hxx>
|
||||
#include <cppuhelper/supportsservice.hxx>
|
||||
#include <officecfg/Office/Common.hxx>
|
||||
|
||||
|
||||
using namespace css;
|
||||
@@ -198,6 +200,15 @@ Reference<ui::XUIElement> SAL_CALL SwPanelFactory::createUIElement (
|
||||
xElement = sfx2::sidebar::SidebarPanelBase::Create(
|
||||
rsResourceURL, xFrame, std::move(xPanel), ui::LayoutSize(-1,-1,-1));
|
||||
}
|
||||
else if (rsResourceURL.endsWith("/CommentsPanel"))
|
||||
{
|
||||
if (officecfg::Office::Common::Misc::ExperimentalMode::get())
|
||||
{
|
||||
std::unique_ptr<PanelLayout> xPanel = sw::sidebar::CommentsPanel::Create(pParent);
|
||||
xElement = sfx2::sidebar::SidebarPanelBase::Create(
|
||||
rsResourceURL, xFrame, std::move(xPanel), ui::LayoutSize(-1,-1,-1));
|
||||
}
|
||||
}
|
||||
else if (rsResourceURL.endsWith("/A11yCheckIssuesPanel"))
|
||||
{
|
||||
std::unique_ptr<PanelLayout> xPanel = sw::sidebar::A11yCheckIssuesPanel::Create(pParent, pBindings);
|
||||
|
||||
@@ -0,0 +1,306 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.40.0 -->
|
||||
<interface domain="sw">
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<!-- n-columns=1 n-rows=1 -->
|
||||
<object class="GtkGrid" id="CommentsPanel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<child>
|
||||
<!-- n-columns=1 n-rows=2 -->
|
||||
<object class="GtkGrid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="border-width">6</property>
|
||||
<child>
|
||||
<object class="GtkExpander" id="options">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="expanded">True</property>
|
||||
<child>
|
||||
<!-- n-columns=2 n-rows=3 -->
|
||||
<object class="GtkGrid" id="grid1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="row-spacing">6</property>
|
||||
<property name="column-spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label_sortby">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes" context="commentspanel|label_sortby">Sort by:</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">sortby_options</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<!-- n-columns=2 n-rows=1 -->
|
||||
<object class="GtkGrid" id="sortby_options">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="sortby_position">
|
||||
<property name="label" translatable="yes" context="commentspanel|radiobutton_position">Position</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="sortby_time">
|
||||
<property name="label" translatable="yes" context="commentspanel|radiobutton_time">Time</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label_show">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes" context="commentspanel|label_show">Show:</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">show_options</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<!-- n-columns=3 n-rows=1 -->
|
||||
<object class="GtkGrid" id="show_options">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="show_time">
|
||||
<property name="label" translatable="yes" context="commentspanel|checkbutton_time">Time</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="show_resolved">
|
||||
<property name="label" translatable="yes" context="commentspanel|checkbutton_resolved">Resolved</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="show_reference">
|
||||
<property name="label" translatable="yes" context="commentspanel|checkbutton_reference">Reference</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">2</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label_filter">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes" context="commentspanel|label_filter">Filter:</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">filter_options</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<!-- n-columns=2 n-rows=2 -->
|
||||
<object class="GtkGrid" id="filter_options">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="row-spacing">3</property>
|
||||
<property name="column-spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label_author">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes" context="commentspanel|label_author">Author</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">filter_author</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label_time">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes" context="commentspanel|label_time">Time</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">filter_time</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="filter_author">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="filter_time">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel" id="options_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes" context="commentspanel|options_label">Options</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="ultrabold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<child>
|
||||
<object class="GtkViewport">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="comment_threads">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="baseline-position">top</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.40.0 -->
|
||||
<interface domain="sw">
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<!-- n-columns=1 n-rows=1 -->
|
||||
<object class="GtkGrid" id="Thread">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkExpander">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="expanded">True</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="comments_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel" id="commentedtext">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes" context="commentspanel|referencetext">commentedtext</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.40.0 -->
|
||||
<interface domain="sw">
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<!-- n-columns=1 n-rows=1 -->
|
||||
<object class="GtkGrid" id="Comment">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkExpander">
|
||||
<property name="height-request">-1</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="expanded">True</property>
|
||||
<property name="label-fill">True</property>
|
||||
<property name="resize-toplevel">True</property>
|
||||
<child>
|
||||
<!-- n-columns=1 n-rows=2 -->
|
||||
<object class="GtkGrid">
|
||||
<property name="height-request">-1</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<child>
|
||||
<!-- n-columns=5 n-rows=1 -->
|
||||
<object class="GtkGrid" id="grid1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="column-homogeneous">True</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="authorlabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes" context="commentspanel|authorlabel">author</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="datelabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes" context="commentspanel|datelabel">date</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="replybutton">
|
||||
<property name="label" translatable="yes" context="commentspanel|replybutton">Reply</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">3</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="timelabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes" context="commentspanel|timelabel">time</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">2</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="resolvebutton">
|
||||
<property name="label" translatable="yes" context="commentspanel|resolvebutton"> </property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">4</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="height-request">100</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkViewport">
|
||||
<property name="height-request">100</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="height-request">100</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkTextView" id="textview">
|
||||
<property name="height-request">100</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel" id="collapsecommentbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes" context="commentspanel|collapsecommentbutton">collapse</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">textview</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -74,6 +74,12 @@ OString DateToOString( const Date& rDate )
|
||||
return DateTimeToOString( DateTime( rDate, aTime ) );
|
||||
}
|
||||
|
||||
OString TimeToOString( const tools::Time& rTime )
|
||||
{
|
||||
Date aDate( Date::EMPTY );
|
||||
return DateTimeToOString( DateTime( aDate, rTime ) );
|
||||
}
|
||||
|
||||
OUString DateToDDMMYYYYOUString( const Date& rDate )
|
||||
{
|
||||
OUStringBuffer aBuffer( 25 );
|
||||
|
||||
Reference in New Issue
Block a user