summaryrefslogtreecommitdiff
path: root/sw/source/uibase/misc
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/uibase/misc')
-rw-r--r--sw/source/uibase/misc/glosdoc.cxx671
-rw-r--r--sw/source/uibase/misc/glshell.cxx276
-rw-r--r--sw/source/uibase/misc/numberingtypelistbox.cxx164
-rw-r--r--sw/source/uibase/misc/redlndlg.cxx1206
-rw-r--r--sw/source/uibase/misc/redlndlg.hrc28
-rw-r--r--sw/source/uibase/misc/redlndlg.src85
-rw-r--r--sw/source/uibase/misc/swruler.cxx302
7 files changed, 2732 insertions, 0 deletions
diff --git a/sw/source/uibase/misc/glosdoc.cxx b/sw/source/uibase/misc/glosdoc.cxx
new file mode 100644
index 000000000000..55489082adea
--- /dev/null
+++ b/sw/source/uibase/misc/glosdoc.cxx
@@ -0,0 +1,671 @@
+/* -*- 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 <algorithm>
+
+#include <com/sun/star/container/XNamed.hpp>
+
+#include <unotools/transliterationwrapper.hxx>
+
+#ifndef __RSC //autogen
+#include <tools/errinf.hxx>
+#endif
+#include <osl/diagnose.h>
+#include <svl/urihelper.hxx>
+#include <svl/fstathelper.hxx>
+#include <unotools/pathoptions.hxx>
+#include <unotools/tempfile.hxx>
+#include <comphelper/string.hxx>
+#include <swtypes.hxx>
+#include <uitool.hxx>
+#include <glosdoc.hxx>
+#include <shellio.hxx>
+#include <swunohelper.hxx>
+
+#include <unoatxt.hxx>
+#include <swerror.h>
+#include <globals.hrc>
+
+#include <boost/scoped_ptr.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+
+inline OUString lcl_FullPathName(const OUString& sPath, const OUString& sName)
+{
+ return sPath + "/" + sName + SwGlossaries::GetExtension();
+}
+
+OUString lcl_CheckFileName( const OUString& rNewFilePath,
+ const OUString& rNewGroupName )
+{
+ const sal_Int32 nLen = rNewGroupName.getLength();
+ OUStringBuffer aBuf(nLen);
+ //group name should contain only A-Z and a-z and spaces
+ for( sal_Int32 i=0; i < nLen; ++i )
+ {
+ const sal_Unicode cChar = rNewGroupName[i];
+ if (comphelper::string::isalnumAscii(cChar) ||
+ cChar == '_' || cChar == 0x20)
+ {
+ aBuf.append(cChar);
+ }
+ }
+
+ const OUString sRet = aBuf.makeStringAndClear().trim();
+ if ( !sRet.isEmpty() )
+ {
+ if (!FStatHelper::IsDocument( lcl_FullPathName(rNewFilePath, sRet) ))
+ return sRet;
+ }
+
+ OUString rSG = SwGlossaries::GetExtension();
+ //generate generic name
+ utl::TempFile aTemp("group", true, &rSG, &rNewFilePath);
+ aTemp.EnableKillingFile();
+
+ INetURLObject aTempURL( aTemp.GetURL() );
+ return aTempURL.GetBase();
+}
+
+}
+
+// supplies the default group's name
+OUString SwGlossaries::GetDefName()
+{
+ return OUString("standard");
+
+}
+
+// supplies the number of text block groups
+sal_uInt16 SwGlossaries::GetGroupCnt()
+{
+ return static_cast<sal_uInt16>(GetNameList().size());
+}
+
+// supplies the group's name
+bool SwGlossaries::FindGroupName(OUString& rGroup)
+{
+ // if the group name doesn't contain a path, a suitable group entry
+ // can the searched for here;
+ sal_uInt16 nCount = GetGroupCnt();
+ sal_uInt16 i;
+ for(i= 0; i < nCount; i++)
+ {
+ const OUString sTemp(GetGroupName(i));
+ if (rGroup==sTemp.getToken(0, GLOS_DELIM))
+ {
+ rGroup = sTemp;
+ return true;
+ }
+ }
+ // you can search two times because for more directories the case sensitive
+ // name could occur multiple times
+ const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
+ for(i = 0; i < nCount; i++)
+ {
+ const OUString sTemp( GetGroupName( i ));
+ sal_uInt16 nPath = (sal_uInt16)sTemp.getToken(1, GLOS_DELIM).toInt32();
+
+ if (!SWUnoHelper::UCB_IsCaseSensitiveFileName( m_PathArr[nPath] )
+ && rSCmp.isEqual( rGroup, sTemp.getToken( 0, GLOS_DELIM) ) )
+ {
+ rGroup = sTemp;
+ return true;
+ }
+ }
+ return false;
+}
+
+OUString SwGlossaries::GetGroupName(sal_uInt16 nGroupId)
+{
+ OSL_ENSURE(static_cast<size_t>(nGroupId) < m_GlosArr.size(),
+ "SwGlossaries::GetGroupName: index out of bounds");
+ return m_GlosArr[nGroupId];
+}
+
+OUString SwGlossaries::GetGroupTitle( const OUString& rGroupName )
+{
+ OUString sRet;
+ OUString sGroup(rGroupName);
+ if (sGroup.indexOf(GLOS_DELIM)<0)
+ FindGroupName(sGroup);
+ SwTextBlocks* pGroup = GetGroupDoc(sGroup, false);
+ if(pGroup)
+ {
+ sRet = pGroup->GetName();
+ PutGroupDoc( pGroup );
+ }
+ return sRet;
+}
+
+// supplies the group rName's text block document
+SwTextBlocks* SwGlossaries::GetGroupDoc(const OUString &rName,
+ bool bCreate)
+{
+ // insert to the list of text blocks if applicable
+ if(bCreate && !m_GlosArr.empty())
+ {
+ std::vector<OUString>::const_iterator it(m_GlosArr.begin());
+ for (; it != m_GlosArr.end(); ++it)
+ {
+ if (*it == rName)
+ break;
+ }
+ if (it == m_GlosArr.end())
+ { // block not in the list
+ m_GlosArr.push_back(rName);
+ }
+ }
+ return GetGlosDoc( rName, bCreate );
+}
+
+// delete a text block
+void SwGlossaries::PutGroupDoc(SwTextBlocks *pBlock) {
+ delete pBlock;
+}
+
+// Creates a new document with the group name. temporarly also created as file
+// so that groups remain there later (without access).
+bool SwGlossaries::NewGroupDoc(OUString& rGroupName, const OUString& rTitle)
+{
+ const OUString sNewPath(rGroupName.getToken(1, GLOS_DELIM));
+ sal_uInt16 nNewPath = (sal_uInt16)sNewPath.toInt32();
+ if (static_cast<size_t>(nNewPath) >= m_PathArr.size())
+ return false;
+ const OUString sNewFilePath(m_PathArr[nNewPath]);
+ const OUString sNewGroup = lcl_CheckFileName(sNewFilePath, rGroupName.getToken(0, GLOS_DELIM))
+ + OUString(GLOS_DELIM) + sNewPath;
+ SwTextBlocks *pBlock = GetGlosDoc( sNewGroup );
+ if(pBlock)
+ {
+ GetNameList().push_back(sNewGroup);
+ pBlock->SetName(rTitle);
+ PutGroupDoc(pBlock);
+ rGroupName = sNewGroup;
+ return true;
+ }
+ return false;
+}
+
+bool SwGlossaries::RenameGroupDoc(
+ const OUString& rOldGroup, OUString& rNewGroup, const OUString& rNewTitle )
+{
+ sal_uInt16 nOldPath = (sal_uInt16)rOldGroup.getToken(1, GLOS_DELIM).toInt32();
+ if (static_cast<size_t>(nOldPath) >= m_PathArr.size())
+ return false;
+
+ const OUString sOldFileURL =
+ lcl_FullPathName(m_PathArr[nOldPath], rOldGroup.getToken(0, GLOS_DELIM));
+
+ if (!FStatHelper::IsDocument( sOldFileURL ))
+ {
+ OSL_FAIL("group doesn't exist!");
+ return false;
+ }
+
+ sal_uInt16 nNewPath = (sal_uInt16)rNewGroup.getToken(1, GLOS_DELIM).toInt32();
+ if (static_cast<size_t>(nNewPath) >= m_PathArr.size())
+ return false;
+
+ const OUString sNewFileName = lcl_CheckFileName(m_PathArr[nNewPath],
+ rNewGroup.getToken(0, GLOS_DELIM));
+ const OUString sNewFileURL = lcl_FullPathName(m_PathArr[nNewPath], sNewFileName);
+
+ if (FStatHelper::IsDocument( sNewFileURL ))
+ {
+ OSL_FAIL("group already exists!");
+ return false;
+ }
+
+ if (!SWUnoHelper::UCB_CopyFile(sOldFileURL, sNewFileURL, true ))
+ return false;
+
+ RemoveFileFromList( rOldGroup );
+
+ rNewGroup = sNewFileName + OUString(GLOS_DELIM) + OUString::number(nNewPath);
+ if (m_GlosArr.empty())
+ {
+ GetNameList();
+ }
+ else
+ {
+ m_GlosArr.push_back(rNewGroup);
+ }
+
+ SwTextBlocks* pNewBlock = new SwTextBlocks( sNewFileURL );
+ pNewBlock->SetName(rNewTitle);
+ delete pNewBlock;
+
+ return true;
+}
+
+// Deletes a text block group
+bool SwGlossaries::DelGroupDoc(const OUString &rName)
+{
+ sal_uInt16 nPath = (sal_uInt16)rName.getToken(1, GLOS_DELIM).toInt32();
+ if (static_cast<size_t>(nPath) >= m_PathArr.size())
+ return false;
+ const OUString sBaseName(rName.getToken(0, GLOS_DELIM));
+ const OUString sFileURL = lcl_FullPathName(m_PathArr[nPath], sBaseName);
+ const OUString aName = sBaseName + OUString(GLOS_DELIM) + OUString::number(nPath);
+ // Even if the file doesn't exist it has to be deleted from
+ // the list of text block regions
+ // no && because of CFfront
+ bool bRemoved = SWUnoHelper::UCB_DeleteFile( sFileURL );
+ OSL_ENSURE(bRemoved, "file has not been removed");
+ RemoveFileFromList( aName );
+ return bRemoved;
+}
+
+SwGlossaries::~SwGlossaries()
+{
+ InvalidateUNOOjects();
+}
+
+// read a block document
+SwTextBlocks* SwGlossaries::GetGlosDoc( const OUString &rName, bool bCreate ) const
+{
+ sal_uInt16 nPath = (sal_uInt16)rName.getToken(1, GLOS_DELIM).toInt32();
+ SwTextBlocks *pTmp = 0;
+ if (static_cast<size_t>(nPath) < m_PathArr.size())
+ {
+ const OUString sFileURL =
+ lcl_FullPathName(m_PathArr[nPath], rName.getToken(0, GLOS_DELIM));
+
+ bool bExist = false;
+ if(!bCreate)
+ bExist = FStatHelper::IsDocument( sFileURL );
+
+ if (bCreate || bExist)
+ {
+ pTmp = new SwTextBlocks( sFileURL );
+ bool bOk = true;
+ if( pTmp->GetError() )
+ {
+ ErrorHandler::HandleError( pTmp->GetError() );
+ bOk = !IsError( pTmp->GetError() );
+ }
+
+ if( bOk && pTmp->GetName().isEmpty() )
+ pTmp->SetName( rName );
+ }
+ }
+
+ return pTmp;
+}
+
+// access to the list of names; read in if applicable
+std::vector<OUString> & SwGlossaries::GetNameList()
+{
+ if (m_GlosArr.empty())
+ {
+ const OUString sExt( SwGlossaries::GetExtension() );
+ for (size_t i = 0; i < m_PathArr.size(); ++i)
+ {
+ std::vector<OUString> aFiles;
+
+ SWUnoHelper::UCB_GetFileListOfFolder(m_PathArr[i], aFiles, &sExt);
+ for( std::vector<OUString>::const_iterator filesIt(aFiles.begin());
+ filesIt != aFiles.end(); ++filesIt)
+ {
+ const OUString aTitle = *filesIt;
+ const OUString sName( aTitle.copy( 0, aTitle.getLength() - sExt.getLength() )
+ + OUString(GLOS_DELIM) + OUString::number( static_cast<sal_Int16>(i) ));
+ m_GlosArr.push_back(sName);
+ }
+ }
+ if (m_GlosArr.empty())
+ {
+ // the standard block is inside of the path's first part
+ m_GlosArr.push_back( SwGlossaries::GetDefName() + OUString(GLOS_DELIM) + "0" );
+ }
+ }
+ return m_GlosArr;
+}
+
+SwGlossaries::SwGlossaries()
+{
+ UpdateGlosPath(true);
+}
+
+// set new path and recreate internal array
+rtl::OUString lcl_makePath(const std::vector<rtl::OUString>& rPaths)
+{
+ std::vector<rtl::OUString>::const_iterator aIt(rPaths.begin());
+ const std::vector<rtl::OUString>::const_iterator aEnd(rPaths.end());
+ rtl::OUStringBuffer aPath(*aIt);
+ for (++aIt; aIt != aEnd; ++aIt)
+ {
+ aPath.append(SVT_SEARCHPATH_DELIMITER);
+ const INetURLObject aTemp(*aIt);
+ aPath.append(aTemp.GetFull());
+ }
+ return aPath.getStr();
+}
+
+void SwGlossaries::UpdateGlosPath(bool bFull)
+{
+ SvtPathOptions aPathOpt;
+ OUString aNewPath( aPathOpt.GetAutoTextPath() );
+ bool bPathChanged = m_aPath != aNewPath;
+ if (bFull || bPathChanged)
+ {
+ m_aPath = aNewPath;
+
+ m_PathArr.clear();
+
+ std::vector<OUString> aDirArr;
+ std::vector<rtl::OUString> aInvalidPaths;
+ if (!m_aPath.isEmpty())
+ {
+ sal_Int32 nIndex = 0;
+ do
+ {
+ const OUString sPth = URIHelper::SmartRel2Abs(
+ INetURLObject(),
+ m_aPath.getToken(0, SVT_SEARCHPATH_DELIMITER, nIndex),
+ URIHelper::GetMaybeFileHdl());
+ if (aDirArr.size() &&
+ std::find(aDirArr.begin(), aDirArr.end(), sPth) != aDirArr.end())
+ {
+ continue;
+ }
+ aDirArr.push_back(sPth);
+ if( !FStatHelper::IsFolder( sPth ) )
+ aInvalidPaths.push_back(sPth);
+ else
+ m_PathArr.push_back(sPth);
+ }
+ while (nIndex>=0);
+ }
+
+ if (m_aPath.isEmpty() || !aInvalidPaths.empty())
+ {
+ std::sort(aInvalidPaths.begin(), aInvalidPaths.end());
+ aInvalidPaths.erase(std::unique(aInvalidPaths.begin(), aInvalidPaths.end()), aInvalidPaths.end());
+ if (bPathChanged || (m_aInvalidPaths != aInvalidPaths))
+ {
+ m_aInvalidPaths = aInvalidPaths;
+ // wrong path, that means AutoText directory doesn't exist
+
+ ErrorHandler::HandleError( *new StringErrorInfo(
+ ERR_AUTOPATH_ERROR, lcl_makePath(m_aInvalidPaths),
+ ERRCODE_BUTTON_OK | ERRCODE_MSG_ERROR ));
+ m_bError = true;
+ }
+ else
+ m_bError = false;
+ }
+ else
+ m_bError = false;
+
+ if (!m_GlosArr.empty())
+ {
+ m_GlosArr.clear();
+ GetNameList();
+ }
+ }
+}
+
+void SwGlossaries::ShowError()
+{
+ sal_uInt32 nPathError = *new StringErrorInfo(ERR_AUTOPATH_ERROR,
+ lcl_makePath(m_aInvalidPaths), ERRCODE_BUTTON_OK );
+ ErrorHandler::HandleError( nPathError );
+}
+
+OUString SwGlossaries::GetExtension()
+{
+ return OUString(".bau");
+}
+
+void SwGlossaries::RemoveFileFromList( const OUString& rGroup )
+{
+ if (!m_GlosArr.empty())
+ {
+ for (std::vector<OUString>::iterator it(m_GlosArr.begin());
+ it != m_GlosArr.end(); ++it)
+ {
+ if (*it == rGroup)
+ {
+ OUString aUName = rGroup;
+ {
+ // tell the UNO AutoTextGroup object that it's not valid anymore
+ for ( UnoAutoTextGroups::iterator aLoop = m_aGlossaryGroups.begin();
+ aLoop != m_aGlossaryGroups.end();
+ ++aLoop
+ )
+ {
+ Reference< container::XNamed > xNamed( aLoop->get(), UNO_QUERY );
+ if ( xNamed.is() && ( xNamed->getName() == aUName ) )
+ {
+ static_cast< SwXAutoTextGroup* >( xNamed.get() )->Invalidate();
+ // note that this static_cast works because we know that the array only
+ // contains SwXAutoTextGroup implementation
+ m_aGlossaryGroups.erase( aLoop );
+ break;
+ }
+ }
+ }
+
+ {
+ // tell all our UNO AutoTextEntry objects that they're not valid anymore
+ for ( UnoAutoTextEntries::iterator aLoop = m_aGlossaryEntries.begin();
+ aLoop != m_aGlossaryEntries.end();
+ )
+ {
+ Reference< lang::XUnoTunnel > xEntryTunnel( aLoop->get(), UNO_QUERY );
+
+ SwXAutoTextEntry* pEntry = NULL;
+ if ( xEntryTunnel.is() )
+ pEntry = reinterpret_cast< SwXAutoTextEntry* >(
+ xEntryTunnel->getSomething( SwXAutoTextEntry::getUnoTunnelId() ) );
+
+ if ( pEntry && ( pEntry->GetGroupName() == rGroup ) )
+ {
+ pEntry->Invalidate();
+ aLoop = m_aGlossaryEntries.erase( aLoop );
+ }
+ else
+ ++aLoop;
+ }
+ }
+
+ m_GlosArr.erase(it);
+ break;
+ }
+ }
+ }
+}
+
+OUString SwGlossaries::GetCompleteGroupName( const OUString& rGroupName )
+{
+ const sal_uInt16 nCount = GetGroupCnt();
+ // when the group name was created internally the path is here as well
+ sal_Int32 nIndex = 0;
+ const OUString sGroupName(rGroupName.getToken(0, GLOS_DELIM, nIndex));
+ const bool bPathLen = !rGroupName.getToken(0, GLOS_DELIM, nIndex).isEmpty();
+ for ( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ const OUString sGrpName = GetGroupName(i);
+ if (bPathLen)
+ {
+ if (rGroupName == sGrpName)
+ return sGrpName;
+ }
+ else
+ {
+ if (sGroupName == sGrpName.getToken(0, GLOS_DELIM))
+ return sGrpName;
+ }
+ }
+ return OUString();
+}
+
+void SwGlossaries::InvalidateUNOOjects()
+{
+ // invalidate all the AutoTextGroup-objects
+ for ( UnoAutoTextGroups::iterator aGroupLoop = m_aGlossaryGroups.begin();
+ aGroupLoop != m_aGlossaryGroups.end();
+ ++aGroupLoop
+ )
+ {
+ Reference< text::XAutoTextGroup > xGroup( aGroupLoop->get(), UNO_QUERY );
+ if ( xGroup.is() )
+ static_cast< SwXAutoTextGroup* >( xGroup.get() )->Invalidate();
+ }
+ UnoAutoTextGroups aTmpg = UnoAutoTextGroups();
+ m_aGlossaryGroups.swap( aTmpg );
+
+ // invalidate all the AutoTextEntry-objects
+ for ( UnoAutoTextEntries::const_iterator aEntryLoop = m_aGlossaryEntries.begin();
+ aEntryLoop != m_aGlossaryEntries.end();
+ ++aEntryLoop
+ )
+ {
+ Reference< lang::XUnoTunnel > xEntryTunnel( aEntryLoop->get(), UNO_QUERY );
+ SwXAutoTextEntry* pEntry = NULL;
+ if ( xEntryTunnel.is() )
+ pEntry = reinterpret_cast< SwXAutoTextEntry* >(
+ xEntryTunnel->getSomething( SwXAutoTextEntry::getUnoTunnelId() ) );
+
+ if ( pEntry )
+ pEntry->Invalidate();
+ }
+ UnoAutoTextEntries aTmpe = UnoAutoTextEntries();
+ m_aGlossaryEntries.swap( aTmpe );
+}
+
+Reference< text::XAutoTextGroup > SwGlossaries::GetAutoTextGroup( const OUString& _rGroupName, bool _bCreate )
+{
+ // first, find the name with path-extension
+ const OUString sCompleteGroupName = GetCompleteGroupName( _rGroupName );
+
+ Reference< text::XAutoTextGroup > xGroup;
+
+ // look up the group in the cache
+ UnoAutoTextGroups::iterator aSearch = m_aGlossaryGroups.begin();
+ for ( ; aSearch != m_aGlossaryGroups.end(); )
+ {
+ Reference< lang::XUnoTunnel > xGroupTunnel( aSearch->get(), UNO_QUERY );
+
+ SwXAutoTextGroup* pSwGroup = 0;
+ if ( xGroupTunnel.is() )
+ pSwGroup = reinterpret_cast< SwXAutoTextGroup* >( xGroupTunnel->getSomething( SwXAutoTextGroup::getUnoTunnelId() ) );
+
+ if ( !pSwGroup )
+ {
+ // the object is dead in the meantime -> remove from cache
+ aSearch = m_aGlossaryGroups.erase( aSearch );
+ continue;
+ }
+
+ if ( _rGroupName == pSwGroup->getName() )
+ { // the group is already cached
+ if ( !sCompleteGroupName.isEmpty() )
+ { // the group still exists -> return it
+ xGroup = pSwGroup;
+ break;
+ }
+ else
+ {
+ // this group does not exist (anymore) -> release the cached UNO object for it
+ aSearch = m_aGlossaryGroups.erase( aSearch );
+ // so it won't be created below
+ _bCreate = false;
+ break;
+ }
+ }
+
+ ++aSearch;
+ }
+
+ if ( !xGroup.is() && _bCreate )
+ {
+ xGroup = new SwXAutoTextGroup( sCompleteGroupName, this );
+ // cache it
+ m_aGlossaryGroups.push_back( AutoTextGroupRef( xGroup ) );
+ }
+
+ return xGroup;
+}
+
+Reference< text::XAutoTextEntry > SwGlossaries::GetAutoTextEntry(
+ const OUString& rCompleteGroupName,
+ const OUString& rGroupName,
+ const OUString& rEntryName,
+ bool _bCreate )
+{
+ //standard must be created
+ bool bCreate = ( rCompleteGroupName == GetDefName() );
+ boost::scoped_ptr< SwTextBlocks > pGlosGroup( GetGroupDoc( rCompleteGroupName, bCreate ) );
+
+ if ( pGlosGroup.get() && !pGlosGroup->GetError() )
+ {
+ sal_uInt16 nIdx = pGlosGroup->GetIndex( rEntryName );
+ if ( USHRT_MAX == nIdx )
+ throw container::NoSuchElementException();
+ }
+ else
+ throw lang::WrappedTargetException();
+
+ Reference< text::XAutoTextEntry > xReturn;
+
+ UnoAutoTextEntries::iterator aSearch( m_aGlossaryEntries.begin() );
+ for ( ; aSearch != m_aGlossaryEntries.end(); )
+ {
+ Reference< lang::XUnoTunnel > xEntryTunnel( aSearch->get(), UNO_QUERY );
+
+ SwXAutoTextEntry* pEntry = NULL;
+ if ( xEntryTunnel.is() )
+ pEntry = reinterpret_cast< SwXAutoTextEntry* >( xEntryTunnel->getSomething( SwXAutoTextEntry::getUnoTunnelId() ) );
+ else
+ {
+ // the object is dead in the meantime -> remove from cache
+ aSearch = m_aGlossaryEntries.erase( aSearch );
+ continue;
+ }
+
+ if ( pEntry
+ && pEntry->GetGroupName() == rGroupName
+ && pEntry->GetEntryName() == rEntryName
+ )
+ {
+ xReturn = pEntry;
+ break;
+ }
+
+ ++aSearch;
+ }
+
+ if ( !xReturn.is() && _bCreate )
+ {
+ xReturn = new SwXAutoTextEntry( this, rGroupName, rEntryName );
+ // cache it
+ m_aGlossaryEntries.push_back( AutoTextEntryRef( xReturn ) );
+ }
+
+ return xReturn;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/misc/glshell.cxx b/sw/source/uibase/misc/glshell.cxx
new file mode 100644
index 000000000000..21fce360171c
--- /dev/null
+++ b/sw/source/uibase/misc/glshell.cxx
@@ -0,0 +1,276 @@
+/* -*- 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 <com/sun/star/frame/XTitle.hpp>
+
+#include <svl/eitem.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/printer.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <svl/srchitem.hxx>
+#include <svl/macitem.hxx>
+#include <gloshdl.hxx>
+
+#include <editeng/acorrcfg.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <uitool.hxx>
+#include <wrtsh.hxx>
+#include <view.hxx>
+#include <glshell.hxx>
+#include <doc.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <glosdoc.hxx>
+#include <shellio.hxx>
+#include <initui.hxx>
+#include <cmdid.h>
+#include <swerror.h>
+#include <misc.hrc>
+
+#define SwWebGlosDocShell
+#define SwGlosDocShell
+
+#include <sfx2/msg.hxx>
+#include <swslots.hxx>
+
+using namespace ::com::sun::star;
+
+SFX_IMPL_INTERFACE(SwGlosDocShell, SwDocShell, SW_RES(0) )
+
+void SwGlosDocShell::InitInterface_Impl()
+{
+}
+
+SFX_IMPL_INTERFACE(SwWebGlosDocShell, SwWebDocShell, SW_RES(0) )
+
+void SwWebGlosDocShell::InitInterface_Impl()
+{
+}
+
+TYPEINIT1( SwGlosDocShell, SwDocShell );
+TYPEINIT1( SwWebGlosDocShell, SwWebDocShell );
+
+static void lcl_Execute( SwDocShell& rSh, SfxRequest& rReq )
+{
+ if ( rReq.GetSlot() == SID_SAVEDOC )
+ {
+ if( !rSh.HasName() )
+ {
+ rReq.SetReturnValue( SfxBoolItem( 0, rSh.Save() ) );
+ }
+ else
+ {
+ const SfxBoolItem* pRes = ( const SfxBoolItem* )
+ rSh.ExecuteSlot( rReq,
+ rSh.SfxObjectShell::GetInterface() );
+ if( pRes->GetValue() )
+ rSh.GetDoc()->ResetModified();
+ }
+ }
+}
+
+static void lcl_GetState( SwDocShell& rSh, SfxItemSet& rSet )
+{
+ if( SFX_ITEM_AVAILABLE >= rSet.GetItemState( SID_SAVEDOC, false ))
+ {
+ if( !rSh.GetDoc()->IsModified() )
+ rSet.DisableItem( SID_SAVEDOC );
+ else
+ rSet.Put( SfxStringItem( SID_SAVEDOC, SW_RESSTR(STR_SAVE_GLOSSARY)));
+ }
+}
+
+static bool lcl_Save( SwWrtShell& rSh, const OUString& rGroupName,
+ const OUString& rShortNm, const OUString& rLongNm )
+{
+ const SvxAutoCorrCfg& rCfg = SvxAutoCorrCfg::Get();
+ SwTextBlocks * pBlock = ::GetGlossaries()->GetGroupDoc( rGroupName );
+
+ SvxMacro aStart(aEmptyOUStr, aEmptyOUStr);
+ SvxMacro aEnd(aEmptyOUStr, aEmptyOUStr);
+ SwGlossaryHdl* pGlosHdl;
+
+ pGlosHdl = rSh.GetView().GetGlosHdl();
+ pGlosHdl->GetMacros( rShortNm, aStart, aEnd, pBlock );
+
+ sal_uInt16 nRet = rSh.SaveGlossaryDoc( *pBlock, rLongNm, rShortNm,
+ rCfg.IsSaveRelFile(),
+ pBlock->IsOnlyTextBlock( rShortNm ) );
+
+ if(aStart.HasMacro() || aEnd.HasMacro() )
+ {
+ SvxMacro* pStart = aStart.HasMacro() ? &aStart : 0;
+ SvxMacro* pEnd = aEnd.HasMacro() ? &aEnd : 0;
+ pGlosHdl->SetMacros( rShortNm, pStart, pEnd, pBlock );
+ }
+
+ rSh.EnterStdMode();
+ if( USHRT_MAX != nRet )
+ rSh.ResetModified();
+ delete pBlock;
+ return nRet != USHRT_MAX;
+}
+
+SwGlosDocShell::SwGlosDocShell(bool bNewShow)
+ : SwDocShell( (bNewShow)
+ ? SFX_CREATE_MODE_STANDARD : SFX_CREATE_MODE_INTERNAL )
+{
+ SetHelpId(SW_GLOSDOCSHELL);
+}
+
+SwGlosDocShell::~SwGlosDocShell( )
+{
+}
+
+void SwGlosDocShell::Execute( SfxRequest& rReq )
+{
+ ::lcl_Execute( *this, rReq );
+}
+
+void SwGlosDocShell::GetState( SfxItemSet& rSet )
+{
+ ::lcl_GetState( *this, rSet );
+}
+
+bool SwGlosDocShell::Save()
+{
+ // In case of an API object which holds this document, it is possible that the WrtShell is already
+ // dead. For instance, if the doc is modified via this API object, and then, upon office shutdown,
+ // the document's view is closed (by the SFX framework) _before_ the API object is release and
+ // tries to save the doc, again.
+ // 96380 - 2002-03-03 - fs@openoffice.org
+ if ( GetWrtShell() )
+ return ::lcl_Save( *GetWrtShell(), aGroupName, aShortName, aLongName );
+ else
+ {
+ SetModified( false );
+ return false;
+ }
+}
+
+SwWebGlosDocShell::SwWebGlosDocShell()
+ : SwWebDocShell( SFX_CREATE_MODE_STANDARD )
+{
+ SetHelpId(SW_WEBGLOSDOCSHELL);
+}
+
+SwWebGlosDocShell::~SwWebGlosDocShell( )
+{
+}
+
+void SwWebGlosDocShell::Execute( SfxRequest& rReq )
+{
+ ::lcl_Execute( *this, rReq );
+}
+
+void SwWebGlosDocShell::GetState( SfxItemSet& rSet )
+{
+ ::lcl_GetState( *this, rSet );
+}
+
+bool SwWebGlosDocShell::Save()
+{
+ // same comment as in SwGlosDocShell::Save - see there
+ if ( GetWrtShell() )
+ return ::lcl_Save( *GetWrtShell(), aGroupName, aShortName, aLongName );
+ else
+ {
+ SetModified( false );
+ return false;
+ }
+}
+
+SwDocShellRef SwGlossaries::EditGroupDoc( const OUString& rGroup, const OUString& rShortName, bool bShow )
+{
+ SwDocShellRef xDocSh;
+
+ SwTextBlocks* pGroup = GetGroupDoc( rGroup );
+ if( pGroup && pGroup->GetCount() )
+ {
+ // query which view is registered. In WebWriter there is no normal view
+ sal_uInt16 nViewId = 0 != &SwView::Factory() ? 2 : 6;
+ const OUString sLongName = pGroup->GetLongName(pGroup->GetIndex( rShortName ));
+
+ if( 6 == nViewId )
+ {
+ SwWebGlosDocShell* pDocSh = new SwWebGlosDocShell();
+ xDocSh = pDocSh;
+ pDocSh->DoInitNew( 0 );
+ pDocSh->SetLongName( sLongName );
+ pDocSh->SetShortName( rShortName);
+ pDocSh->SetGroupName( rGroup );
+ }
+ else
+ {
+ SwGlosDocShell* pDocSh = new SwGlosDocShell(bShow);
+ xDocSh = pDocSh;
+ pDocSh->DoInitNew( 0 );
+ pDocSh->SetLongName( sLongName );
+ pDocSh->SetShortName( rShortName );
+ pDocSh->SetGroupName( rGroup );
+ }
+
+ // set document title
+ SfxViewFrame* pFrame = bShow ? SfxViewFrame::LoadDocument( *xDocSh, nViewId ) : SfxViewFrame::LoadHiddenDocument( *xDocSh, nViewId );
+ const OUString aDocTitle(SW_RESSTR( STR_GLOSSARY ) + " " + sLongName);
+
+ bool const bDoesUndo =
+ xDocSh->GetDoc()->GetIDocumentUndoRedo().DoesUndo();
+ xDocSh->GetDoc()->GetIDocumentUndoRedo().DoUndo( false );
+
+ xDocSh->GetWrtShell()->InsertGlossary( *pGroup, rShortName );
+ if( !xDocSh->GetDoc()->getPrinter( false ) )
+ {
+ // we create a default SfxPrinter.
+ // ItemSet is deleted by Sfx!
+ SfxItemSet *pSet = new SfxItemSet( xDocSh->GetDoc()->GetAttrPool(),
+ FN_PARAM_ADDPRINTER, FN_PARAM_ADDPRINTER,
+ SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN,
+ SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC,
+ 0 );
+ SfxPrinter* pPrinter = new SfxPrinter( pSet );
+
+ // and append it to the document.
+ xDocSh->GetDoc()->setPrinter( pPrinter, true, true );
+ }
+
+ xDocSh->SetTitle( aDocTitle );
+ try
+ {
+ // set the UI-title
+ uno::Reference< frame::XTitle > xTitle( xDocSh->GetModel(), uno::UNO_QUERY_THROW );
+ xTitle->setTitle( aDocTitle );
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ xDocSh->GetDoc()->GetIDocumentUndoRedo().DoUndo( bDoesUndo );
+ xDocSh->GetDoc()->ResetModified();
+ if ( bShow )
+ pFrame->GetFrame().Appear();
+
+ delete pGroup;
+ }
+ return xDocSh;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/misc/numberingtypelistbox.cxx b/sw/source/uibase/misc/numberingtypelistbox.cxx
new file mode 100644
index 000000000000..ab21d35764a4
--- /dev/null
+++ b/sw/source/uibase/misc/numberingtypelistbox.cxx
@@ -0,0 +1,164 @@
+/* -*- 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 <numberingtypelistbox.hxx>
+#include <misc.hrc>
+#include <cnttab.hxx>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/text/DefaultNumberingProvider.hpp>
+#include <com/sun/star/text/XDefaultNumberingProvider.hpp>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/text/XNumberingTypeInfo.hpp>
+
+#include <unomid.h>
+
+using namespace com::sun::star;
+
+struct SwNumberingTypeListBox_Impl
+{
+ uno::Reference<text::XNumberingTypeInfo> xInfo;
+};
+
+SwNumberingTypeListBox::SwNumberingTypeListBox( Window* pWin, WinBits nStyle ) :
+ ListBox(pWin, nStyle),
+ pImpl(new SwNumberingTypeListBox_Impl)
+{
+ uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
+ uno::Reference<text::XDefaultNumberingProvider> xDefNum = text::DefaultNumberingProvider::create(xContext);
+
+ pImpl->xInfo = uno::Reference<text::XNumberingTypeInfo>(xDefNum, uno::UNO_QUERY);
+}
+
+bool SwNumberingTypeListBox::set_property(const OString &rKey, const OString &rValue)
+{
+ if (rKey == "type")
+ Reload(rValue.toInt32());
+ else
+ return ListBox::set_property(rKey, rValue);
+ return true;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeSwNumberingTypeListBox(Window *pParent, VclBuilder::stringmap &)
+{
+ SwNumberingTypeListBox *pListBox = new SwNumberingTypeListBox(pParent, WB_LEFT|WB_DROPDOWN|WB_VCENTER|WB_3DLOOK|WB_TABSTOP);
+ pListBox->EnableAutoSize(true);
+ return pListBox;
+}
+
+SwNumberingTypeListBox::~SwNumberingTypeListBox()
+{
+ delete pImpl;
+}
+
+void SwNumberingTypeListBox::Reload(sal_uInt16 nTypeFlags)
+{
+ Clear();
+ uno::Sequence<sal_Int16> aTypes;
+ const sal_Int16* pTypes = NULL;
+ if(0 != (nTypeFlags&INSERT_NUM_EXTENDED_TYPES) )
+ {
+ if(pImpl->xInfo.is())
+ {
+ aTypes = pImpl->xInfo->getSupportedNumberingTypes();
+ pTypes = aTypes.getConstArray();
+ }
+ }
+ SwOLENames aNames(SW_RES(STRRES_NUMTYPES));
+ ResStringArray& rNames = aNames.GetNames();
+ for(sal_uInt16 i = 0; i < rNames.Count(); i++)
+ {
+ sal_IntPtr nValue = rNames.GetValue(i);
+ bool bInsert = true;
+ sal_Int32 nPos = LISTBOX_APPEND;
+ switch(nValue)
+ {
+ case style::NumberingType::NUMBER_NONE:
+ bInsert = 0 != (nTypeFlags&INSERT_NUM_TYPE_NO_NUMBERING);
+ nPos = 0;
+ break;
+ case style::NumberingType::CHAR_SPECIAL: bInsert = 0 != (nTypeFlags&INSERT_NUM_TYPE_BULLET); break;
+ case style::NumberingType::PAGE_DESCRIPTOR:bInsert = 0 != (nTypeFlags&INSERT_NUM_TYPE_PAGE_STYLE_NUMBERING); break;
+ case style::NumberingType::BITMAP:bInsert = 0 != (nTypeFlags&INSERT_NUM_TYPE_BITMAP ); break;
+ default:
+ if (nValue > style::NumberingType::CHARS_LOWER_LETTER_N)
+ {
+ // Insert only if offered by i18n framework per configuration.
+ bInsert = false;
+ if (pTypes)
+ {
+ for(sal_Int32 nType = 0; nType < aTypes.getLength(); nType++)
+ {
+ if (pTypes[nType] == nValue)
+ {
+ bInsert = true;
+ break; // for
+ }
+ }
+ }
+ }
+ }
+ if(bInsert)
+ {
+ sal_Int32 nEntry = InsertEntry(rNames.GetString(i), nPos);
+ SetEntryData( nEntry, (void*)nValue );
+ }
+ }
+ if(0 != (nTypeFlags&INSERT_NUM_EXTENDED_TYPES) )
+ {
+ if(pTypes)
+ {
+ for(sal_Int32 nType = 0; nType < aTypes.getLength(); nType++)
+ {
+ sal_Int16 nCurrent = pTypes[nType];
+ if(nCurrent > style::NumberingType::CHARS_LOWER_LETTER_N)
+ {
+ if(LISTBOX_ENTRY_NOTFOUND == GetEntryPos((void*)(sal_uLong)nCurrent))
+ {
+ OUString aIdent = pImpl->xInfo->getNumberingIdentifier( nCurrent );
+ sal_Int32 nPos = InsertEntry(aIdent);
+ SetEntryData(nPos,(void*)(sal_uLong)nCurrent);
+ }
+ }
+ }
+ }
+ SelectEntryPos(0);
+ }
+}
+
+sal_Int16 SwNumberingTypeListBox::GetSelectedNumberingType()
+{
+ sal_Int16 nRet = 0;
+ sal_Int32 nSelPos = GetSelectEntryPos();
+ if(LISTBOX_ENTRY_NOTFOUND != nSelPos)
+ nRet = (sal_Int16)(sal_uLong)GetEntryData(nSelPos);
+#if OSL_DEBUG_LEVEL > 0
+ else
+ OSL_FAIL("SwNumberingTypeListBox not selected");
+#endif
+ return nRet;
+}
+
+bool SwNumberingTypeListBox::SelectNumberingType(sal_Int16 nType)
+{
+ sal_Int32 nPos = GetEntryPos((void*)(sal_uLong)nType);
+ SelectEntryPos( nPos );
+ return LISTBOX_ENTRY_NOTFOUND != nPos;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/misc/redlndlg.cxx b/sw/source/uibase/misc/redlndlg.cxx
new file mode 100644
index 000000000000..53aebdcdcc6d
--- /dev/null
+++ b/sw/source/uibase/misc/redlndlg.cxx
@@ -0,0 +1,1206 @@
+/* -*- 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 <redline.hxx>
+#include <tools/datetime.hxx>
+#include <vcl/msgbox.hxx>
+#include <svl/eitem.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/ctredlin.hxx>
+#include <svx/postattr.hxx>
+#include <swtypes.hxx>
+#include <wrtsh.hxx>
+#include <view.hxx>
+#include <swmodule.hxx>
+#include <redlndlg.hxx>
+#include <swwait.hxx>
+#include <uitool.hxx>
+
+#include <helpid.h>
+#include <cmdid.h>
+#include <misc.hrc>
+#include <redlndlg.hrc>
+#include <shells.hrc>
+
+// -> #111827#
+#include <comcore.hrc>
+#include <swundo.hxx>
+#include <SwRewriter.hxx>
+// <- #111827#
+
+#include <vector>
+#include <svx/svxdlg.hxx>
+#include <svx/dialogs.hrc>
+
+#include <unomid.h>
+
+#include <docsh.hxx>
+
+#include <IDocumentRedlineAccess.hxx>
+
+SFX_IMPL_MODELESSDIALOG_WITHID( SwRedlineAcceptChild, FN_REDLINE_ACCEPT )
+
+static sal_uInt16 nSortMode = 0xffff;
+static bool bSortDir = true;
+
+SwRedlineAcceptChild::SwRedlineAcceptChild( Window* _pParent,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo ) :
+ SwChildWinWrapper( _pParent, nId )
+{
+ pWindow = new SwModelessRedlineAcceptDlg( pBindings, this, _pParent);
+
+ ((SwModelessRedlineAcceptDlg *)pWindow)->Initialize(pInfo);
+}
+
+// newly initialise dialog after document switch
+bool SwRedlineAcceptChild::ReInitDlg(SwDocShell *pDocSh)
+{
+ bool bRet;
+
+ if ((bRet = SwChildWinWrapper::ReInitDlg(pDocSh))) // update immediately, doc switch!
+ ((SwModelessRedlineAcceptDlg*)GetWindow())->Activate();
+
+ return bRet;
+}
+
+SwModelessRedlineAcceptDlg::SwModelessRedlineAcceptDlg(
+ SfxBindings* _pBindings, SwChildWinWrapper* pChild, Window *_pParent)
+ : SfxModelessDialog(_pBindings, pChild, _pParent,
+ "AcceptRejectChangesDialog", "svx/ui/acceptrejectchangesdialog.ui")
+ , pChildWin (pChild)
+{
+ pImplDlg = new SwRedlineAcceptDlg(this);
+}
+
+void SwModelessRedlineAcceptDlg::Activate()
+{
+ SwView *pView = ::GetActiveView();
+
+ if (!pView) // can happen when switching to another app, when a Listbox in dialog
+ return; // had the focus previously (actually THs Bug)
+
+ SwDocShell *pDocSh = pView->GetDocShell();
+
+ if (pChildWin->GetOldDocShell() != pDocSh)
+ { // doc-switch
+ SwWait aWait( *pDocSh, false );
+ SwWrtShell* pSh = pView->GetWrtShellPtr();
+
+ pChildWin->SetOldDocShell(pDocSh); // avoid recursion (using modified-Hdl)
+
+ bool bMod = pSh->IsModified();
+ SfxBoolItem aShow(FN_REDLINE_SHOW, true);
+ pSh->GetView().GetViewFrame()->GetDispatcher()->Execute(
+ FN_REDLINE_SHOW, SFX_CALLMODE_SYNCHRON|SFX_CALLMODE_RECORD, &aShow, 0L);
+ if (!bMod)
+ pSh->ResetModified();
+ pImplDlg->Init();
+
+ return;
+ }
+
+ pImplDlg->Activate();
+}
+
+void SwModelessRedlineAcceptDlg::Initialize(SfxChildWinInfo *pInfo)
+{
+ if (pInfo != NULL)
+ pImplDlg->Initialize(pInfo->aExtraString);
+
+ SfxModelessDialog::Initialize(pInfo);
+}
+
+void SwModelessRedlineAcceptDlg::FillInfo(SfxChildWinInfo& rInfo) const
+{
+ SfxModelessDialog::FillInfo(rInfo);
+ pImplDlg->FillInfo(rInfo.aExtraString);
+}
+
+SwModelessRedlineAcceptDlg::~SwModelessRedlineAcceptDlg()
+{
+ delete pImplDlg;
+}
+
+SwRedlineAcceptDlg::SwRedlineAcceptDlg(Dialog *pParent, bool bAutoFmt) :
+ pParentDlg (pParent),
+ aTabPagesCTRL (pParent->get_content_area()),
+ aPopup (SW_RES(MN_REDLINE_POPUP)),
+ sInserted (SW_RES(STR_REDLINE_INSERTED)),
+ sDeleted (SW_RES(STR_REDLINE_DELETED)),
+ sFormated (SW_RES(STR_REDLINE_FORMATED)),
+ sTableChgd (SW_RES(STR_REDLINE_TABLECHG)),
+ sFmtCollSet (SW_RES(STR_REDLINE_FMTCOLLSET)),
+ sAutoFormat (SW_RES(STR_REDLINE_AUTOFMT)),
+ bOnlyFormatedRedlines( false ),
+ bHasReadonlySel ( false ),
+ bRedlnAutoFmt (bAutoFmt),
+ bInhibitActivate( false )
+{
+ aTabPagesCTRL.SetHelpId(HID_REDLINE_CTRL);
+ pTPView = aTabPagesCTRL.GetViewPage();
+ pTable = pTPView->GetTableControl();
+
+ pTPView->InsertWriterHeader();
+ pTPView->SetAcceptClickHdl(LINK(this, SwRedlineAcceptDlg, AcceptHdl));
+ pTPView->SetAcceptAllClickHdl(LINK(this, SwRedlineAcceptDlg, AcceptAllHdl));
+ pTPView->SetRejectClickHdl(LINK(this, SwRedlineAcceptDlg, RejectHdl));
+ pTPView->SetRejectAllClickHdl(LINK(this, SwRedlineAcceptDlg, RejectAllHdl));
+ pTPView->SetUndoClickHdl(LINK(this, SwRedlineAcceptDlg, UndoHdl));
+
+ aTabPagesCTRL.GetFilterPage()->SetReadyHdl(LINK(this, SwRedlineAcceptDlg, FilterChangedHdl));
+
+ ListBox *pActLB = aTabPagesCTRL.GetFilterPage()->GetLbAction();
+ pActLB->InsertEntry(sInserted);
+ pActLB->InsertEntry(sDeleted);
+ pActLB->InsertEntry(sFormated);
+ pActLB->InsertEntry(sTableChgd);
+
+ if (HasRedlineAutoFmt())
+ {
+ pActLB->InsertEntry(sFmtCollSet);
+ pActLB->InsertEntry(sAutoFormat);
+ pTPView->ShowUndo(true);
+ pTPView->DisableUndo(); // no UNDO events yet
+ }
+
+ pActLB->SelectEntryPos(0);
+
+ pTable->SetStyle(pTable->GetStyle()|WB_HASLINES|WB_CLIPCHILDREN|WB_HASBUTTONS|WB_HASBUTTONSATROOT|WB_HSCROLL);
+ pTable->SetNodeDefaultImages();
+ pTable->SetSelectionMode(MULTIPLE_SELECTION);
+ pTable->SetHighlightRange(1);
+
+ static long aStaticTabs[]=
+ {
+ 4,10,70,120,170
+ };
+
+ pTable->SetTabs(aStaticTabs);
+
+ pTable->SortByCol(nSortMode, bSortDir);
+
+ aOldSelectHdl = pTable->GetSelectHdl();
+ aOldDeselectHdl = pTable->GetDeselectHdl();
+ pTable->SetSelectHdl(LINK(this, SwRedlineAcceptDlg, SelectHdl));
+ pTable->SetDeselectHdl(LINK(this, SwRedlineAcceptDlg, DeselectHdl));
+ pTable->SetCommandHdl(LINK(this, SwRedlineAcceptDlg, CommandHdl));
+
+ // avoid flickering of buttons:
+ aDeselectTimer.SetTimeout(100);
+ aDeselectTimer.SetTimeoutHdl(LINK(this, SwRedlineAcceptDlg, SelectHdl));
+
+ // avoid multiple selection of the same texts:
+ aSelectTimer.SetTimeout(100);
+ aSelectTimer.SetTimeoutHdl(LINK(this, SwRedlineAcceptDlg, GotoHdl));
+}
+
+SwRedlineAcceptDlg::~SwRedlineAcceptDlg()
+{
+}
+
+void SwRedlineAcceptDlg::Init(sal_uInt16 nStart)
+{
+ SwWait aWait( *::GetActiveView()->GetDocShell(), false );
+ pTable->SetUpdateMode(false);
+ aUsedSeqNo.clear();
+
+ if (nStart)
+ RemoveParents(nStart, aRedlineParents.size() - 1);
+ else
+ {
+ pTable->Clear();
+ aRedlineChildren.clear();
+ aRedlineParents.erase(aRedlineParents.begin() + nStart, aRedlineParents.end());
+ }
+
+ // insert parents
+ InsertParents(nStart);
+ InitAuthors();
+
+ pTable->SetUpdateMode(true);
+ // #i69618# this moves the list box to the right position, visually
+ SvTreeListEntry* pSelEntry = pTable->FirstSelected();
+ if( pSelEntry )
+ pTable->MakeVisible( pSelEntry, true ); //#i70937#, force the scroll
+}
+
+void SwRedlineAcceptDlg::InitAuthors()
+{
+ SwWrtShell* pSh = ::GetActiveView()->GetWrtShellPtr();
+
+ SvxTPFilter *pFilterPage = aTabPagesCTRL.GetFilterPage();
+
+ std::vector<OUString> aStrings;
+ OUString sOldAuthor(pFilterPage->GetSelectedAuthor());
+ pFilterPage->ClearAuthors();
+
+ sal_uInt16 nCount = pSh->GetRedlineCount();
+
+ bOnlyFormatedRedlines = true;
+ bHasReadonlySel = false;
+ bool bIsNotFormated = false;
+ sal_uInt16 i;
+
+ // determine authors
+ for ( i = 0; i < nCount; i++)
+ {
+ const SwRangeRedline& rRedln = pSh->GetRedline(i);
+
+ if( bOnlyFormatedRedlines && nsRedlineType_t::REDLINE_FORMAT != rRedln.GetType() )
+ bOnlyFormatedRedlines = false;
+
+ aStrings.push_back(rRedln.GetAuthorString());
+
+ for (sal_uInt16 nStack = 1; nStack < rRedln.GetStackCount(); nStack++)
+ {
+ aStrings.push_back(rRedln.GetAuthorString(nStack));
+ }
+ }
+
+ std::sort(aStrings.begin(), aStrings.end());
+ aStrings.erase(std::unique(aStrings.begin(), aStrings.end()), aStrings.end());
+
+ for (i = 0; i < aStrings.size(); i++)
+ pFilterPage->InsertAuthor(aStrings[i]);
+
+ if (pFilterPage->SelectAuthor(sOldAuthor) == LISTBOX_ENTRY_NOTFOUND && !aStrings.empty())
+ pFilterPage->SelectAuthor(aStrings[0]);
+
+ bool bEnable = pTable->GetEntryCount() != 0 && !pSh->getIDocumentRedlineAccess()->GetRedlinePassword().getLength();
+ bool bSel = pTable->FirstSelected() != 0;
+
+ SvTreeListEntry* pSelEntry = pTable->FirstSelected();
+ while (pSelEntry)
+ {
+ // find the selected redline
+ // (fdo#57874: ignore, if the redline is already gone)
+ sal_uInt16 nPos = GetRedlinePos(*pSelEntry);
+ if( nPos != USHRT_MAX )
+ {
+ const SwRangeRedline& rRedln = pSh->GetRedline( nPos );
+
+ bIsNotFormated |= nsRedlineType_t::REDLINE_FORMAT != rRedln.GetType();
+ }
+ pSelEntry = pTable->NextSelected(pSelEntry);
+ }
+
+ pTPView->EnableAccept( bEnable && bSel );
+ pTPView->EnableReject( bEnable && bIsNotFormated && bSel );
+ pTPView->EnableAcceptAll( bEnable && !bHasReadonlySel );
+ pTPView->EnableRejectAll( bEnable && !bHasReadonlySel &&
+ !bOnlyFormatedRedlines );
+}
+
+OUString SwRedlineAcceptDlg::GetRedlineText( const SwRangeRedline& rRedln,
+ DateTime &rDateTime, sal_uInt16 nStack)
+{
+ OUString sEntry(GetActionText(rRedln, nStack));
+ sEntry += "\t";
+ sEntry += rRedln.GetAuthorString(nStack);
+ sEntry += "\t";
+
+ const DateTime &rDT = rRedln.GetTimeStamp(nStack);
+ rDateTime = rDT;
+
+ sEntry += GetAppLangDateTimeString( rDT );
+ sEntry += "\t";
+
+ sEntry += rRedln.GetComment(nStack);
+
+ return sEntry;
+}
+
+OUString SwRedlineAcceptDlg::GetActionText(const SwRangeRedline& rRedln, sal_uInt16 nStack)
+{
+ switch( rRedln.GetType(nStack) )
+ {
+ case nsRedlineType_t::REDLINE_INSERT: return sInserted;
+ case nsRedlineType_t::REDLINE_DELETE: return sDeleted;
+ case nsRedlineType_t::REDLINE_FORMAT: return sFormated;
+ case nsRedlineType_t::REDLINE_TABLE: return sTableChgd;
+ case nsRedlineType_t::REDLINE_FMTCOLL: return sFmtCollSet;
+ default:;//prevent warning
+ }
+
+ return OUString();
+}
+
+// newly initialise after activation
+void SwRedlineAcceptDlg::Activate()
+{
+ // prevent update if flag is set (#102547#)
+ if( bInhibitActivate )
+ return;
+
+ SwView *pView = ::GetActiveView();
+
+ if (!pView) // can happen when switching to another app, when a Listbox in the dialog
+ return; // had the focus previously (actually THs Bug)
+
+ SwWait aWait( *pView->GetDocShell(), false );
+
+ aUsedSeqNo.clear();
+
+ // did something change?
+ SwWrtShell* pSh = pView->GetWrtShellPtr();
+ sal_uInt16 nCount = pSh->GetRedlineCount();
+
+ // check the number of pointers
+ SwRedlineDataParent *pParent = 0;
+ sal_uInt16 i;
+
+ for ( i = 0; i < nCount; i++)
+ {
+ const SwRangeRedline& rRedln = pSh->GetRedline(i);
+
+ if (i >= aRedlineParents.size())
+ {
+ // new entries have been appended
+ Init(i);
+ return;
+ }
+
+ pParent = &aRedlineParents[i];
+ if (&rRedln.GetRedlineData() != pParent->pData)
+ {
+ // Redline-Parents were inserted, changed or deleted
+ if ((i = CalcDiff(i, false)) == USHRT_MAX)
+ return;
+ continue;
+ }
+
+ const SwRedlineData *pRedlineData = rRedln.GetRedlineData().Next();
+ const SwRedlineDataChild *pBackupData = pParent->pNext;
+
+ if (!pRedlineData && pBackupData)
+ {
+ // Redline-Children were deleted
+ if ((i = CalcDiff(i, true)) == USHRT_MAX)
+ return;
+ continue;
+ }
+ else
+ {
+ while (pRedlineData)
+ {
+ if (pRedlineData != pBackupData->pChild)
+ {
+ // Redline-Children were inserted, changed or deleted
+ if ((i = CalcDiff(i, true)) == USHRT_MAX)
+ return;
+ continue;
+ }
+ pBackupData = pBackupData->pNext;
+ pRedlineData = pRedlineData->Next();
+ }
+ }
+ }
+
+ if (nCount != aRedlineParents.size())
+ {
+ // Redlines were deleted at the end
+ Init(nCount);
+ return;
+ }
+
+ // check comment
+ for (i = 0; i < nCount; i++)
+ {
+ const SwRangeRedline& rRedln = pSh->GetRedline(i);
+ pParent = &aRedlineParents[i];
+
+ if(rRedln.GetComment() != pParent->sComment)
+ {
+ if (pParent->pTLBParent)
+ {
+ // update only comment
+ OUString sComment(rRedln.GetComment());
+ pTable->SetEntryText(sComment.replace('\n', ' '), pParent->pTLBParent, 3);
+ }
+ pParent->sComment = rRedln.GetComment();
+ }
+ }
+
+ InitAuthors();
+}
+
+sal_uInt16 SwRedlineAcceptDlg::CalcDiff(sal_uInt16 nStart, bool bChild)
+{
+ if (!nStart)
+ {
+ Init();
+ return USHRT_MAX;
+ }
+
+ pTable->SetUpdateMode(false);
+ SwView *pView = ::GetActiveView();
+ SwWrtShell* pSh = pView->GetWrtShellPtr();
+ sal_uInt16 nAutoFmt = HasRedlineAutoFmt() ? nsRedlineType_t::REDLINE_FORM_AUTOFMT : 0;
+ SwRedlineDataParent *pParent = &aRedlineParents[nStart];
+ const SwRangeRedline& rRedln = pSh->GetRedline(nStart);
+
+ if (bChild) // should actually never happen, but just in case...
+ {
+ // throw away all entry's children and initialise newly
+ SwRedlineDataChild* pBackupData = (SwRedlineDataChild*)pParent->pNext;
+ SwRedlineDataChild* pNext;
+
+ while (pBackupData)
+ {
+ pNext = (SwRedlineDataChild*)pBackupData->pNext;
+ if (pBackupData->pTLBChild)
+ pTable->RemoveEntry(pBackupData->pTLBChild);
+
+ for( SwRedlineDataChildArr::iterator it = aRedlineChildren.begin();
+ it != aRedlineChildren.end(); ++it)
+ if (&*it == pBackupData)
+ {
+ aRedlineChildren.erase(it);
+ break;
+ }
+ pBackupData = pNext;
+ }
+ pParent->pNext = 0;
+
+ // insert new children
+ InsertChildren(pParent, rRedln, nAutoFmt);
+
+ pTable->SetUpdateMode(true);
+ return nStart;
+ }
+
+ // have entries been deleted?
+ const SwRedlineData *pRedlineData = &rRedln.GetRedlineData();
+ sal_uInt16 i;
+ for ( i = nStart + 1; i < aRedlineParents.size(); i++)
+ {
+ if (aRedlineParents[i].pData == pRedlineData)
+ {
+ // remove entries from nStart to i-1
+ RemoveParents(nStart, i - 1);
+ pTable->SetUpdateMode(true);
+ return nStart - 1;
+ }
+ }
+
+ // entries been inserted?
+ sal_uInt16 nCount = pSh->GetRedlineCount();
+ pRedlineData = aRedlineParents[nStart].pData;
+
+ for (i = nStart + 1; i < nCount; i++)
+ {
+ if (&pSh->GetRedline(i).GetRedlineData() == pRedlineData)
+ {
+ // insert entries from nStart to i-1
+ InsertParents(nStart, i - 1);
+ pTable->SetUpdateMode(true);
+ return nStart - 1;
+ }
+ }
+
+ pTable->SetUpdateMode(true);
+ Init(nStart); // adjust all entries until the end
+ return USHRT_MAX;
+}
+
+void SwRedlineAcceptDlg::InsertChildren(SwRedlineDataParent *pParent, const SwRangeRedline& rRedln, const sal_uInt16 nAutoFmt)
+{
+ OUString sChild;
+ SwRedlineDataChild *pLastRedlineChild = 0;
+ const SwRedlineData *pRedlineData = &rRedln.GetRedlineData();
+ bool bAutoFmt = (rRedln.GetRealType() & nAutoFmt) != 0;
+
+ OUString sAction = GetActionText(rRedln);
+ bool bValidParent = sFilterAction.isEmpty() || sFilterAction == sAction;
+ bValidParent = bValidParent && pTable->IsValidEntry(rRedln.GetAuthorString(), rRedln.GetTimeStamp(), rRedln.GetComment());
+ if (nAutoFmt)
+ {
+
+ if (pParent->pData->GetSeqNo())
+ {
+ std::pair<SwRedlineDataParentSortArr::const_iterator,bool> const ret
+ = aUsedSeqNo.insert(pParent);
+ if (ret.second) // already there
+ {
+ if (pParent->pTLBParent)
+ {
+ pTable->SetEntryText(
+ sAutoFormat, (*ret.first)->pTLBParent, 0);
+ pTable->RemoveEntry(pParent->pTLBParent);
+ pParent->pTLBParent = 0;
+ }
+ return;
+ }
+ }
+ bValidParent = bValidParent && bAutoFmt;
+ }
+ bool bValidTree = bValidParent;
+
+ for (sal_uInt16 nStack = 1; nStack < rRedln.GetStackCount(); nStack++)
+ {
+ pRedlineData = pRedlineData->Next();
+
+ SwRedlineDataChildPtr pRedlineChild = new SwRedlineDataChild;
+ pRedlineChild->pChild = pRedlineData;
+ aRedlineChildren.push_back(pRedlineChild);
+
+ if ( pLastRedlineChild )
+ pLastRedlineChild->pNext = pRedlineChild;
+ else
+ pParent->pNext = pRedlineChild;
+
+ sAction = GetActionText(rRedln, nStack);
+ bool bValidChild = sFilterAction.isEmpty() || sFilterAction == sAction;
+ bValidChild = bValidChild && pTable->IsValidEntry(rRedln.GetAuthorString(nStack), rRedln.GetTimeStamp(nStack), rRedln.GetComment());
+ if (nAutoFmt)
+ bValidChild = bValidChild && bAutoFmt;
+ bValidTree |= bValidChild;
+
+ if (bValidChild)
+ {
+ RedlinData *pData = new RedlinData;
+ pData->pData = pRedlineChild;
+ pData->bDisabled = true;
+ sChild = GetRedlineText(rRedln, pData->aDateTime, nStack);
+
+ SvTreeListEntry* pChild = pTable->InsertEntry(sChild, pData, pParent->pTLBParent);
+
+ pRedlineChild->pTLBChild = pChild;
+ if (!bValidParent)
+ pTable->Expand(pParent->pTLBParent);
+ }
+ else
+ pRedlineChild->pTLBChild = 0;
+
+ pLastRedlineChild = pRedlineChild;
+ }
+
+ if (pLastRedlineChild)
+ pLastRedlineChild->pNext = 0;
+
+ if (!bValidTree && pParent->pTLBParent)
+ {
+ pTable->RemoveEntry(pParent->pTLBParent);
+ pParent->pTLBParent = 0;
+ if (nAutoFmt)
+ aUsedSeqNo.erase(pParent);
+ }
+}
+
+void SwRedlineAcceptDlg::RemoveParents(sal_uInt16 nStart, sal_uInt16 nEnd)
+{
+ SwWrtShell* pSh = ::GetActiveView()->GetWrtShellPtr();
+ sal_uInt16 nCount = pSh->GetRedlineCount();
+
+ SvLBoxEntryArr aLBoxArr;
+
+ // because of Bug of TLB that ALWAYS calls the SelectHandler at Remove:
+ pTable->SetSelectHdl(aOldSelectHdl);
+ pTable->SetDeselectHdl(aOldDeselectHdl);
+ bool bChildrenRemoved = false;
+ pTable->SelectAll(false);
+
+ // set the cursor after the last entry because otherwise performance problem in TLB.
+ // TLB would otherwise reset the cursor at every Remove (expensive)
+ sal_uInt16 nPos = std::min((sal_uInt16)nCount, (sal_uInt16)aRedlineParents.size());
+ SvTreeListEntry *pCurEntry = NULL;
+ while( ( pCurEntry == NULL ) && ( nPos > 0 ) )
+ {
+ --nPos;
+ pCurEntry = aRedlineParents[nPos].pTLBParent;
+ }
+
+ if (pCurEntry)
+ pTable->SetCurEntry(pCurEntry);
+
+ SvTreeList* pModel = pTable->GetModel();
+
+ for (sal_uInt16 i = nStart; i <= nEnd; i++)
+ {
+ if (!bChildrenRemoved && aRedlineParents[i].pNext)
+ {
+ SwRedlineDataChildPtr pChildPtr = (SwRedlineDataChildPtr)aRedlineParents[i].pNext;
+ for( SwRedlineDataChildArr::iterator it = aRedlineChildren.begin();
+ it != aRedlineChildren.end(); ++it)
+ if (&*it == pChildPtr)
+ {
+ sal_uInt16 nChildren = 0;
+ while (pChildPtr)
+ {
+ pChildPtr = (SwRedlineDataChildPtr)pChildPtr->pNext;
+ nChildren++;
+ }
+
+ aRedlineChildren.erase(it, it + nChildren);
+ bChildrenRemoved = true;
+ break;
+ }
+ }
+ SvTreeListEntry *pEntry = aRedlineParents[i].pTLBParent;
+ if (pEntry)
+ {
+ long nIdx = aLBoxArr.size() - 1L;
+ sal_uLong nAbsPos = pModel->GetAbsPos(pEntry);
+ while (nIdx >= 0 &&
+ pModel->GetAbsPos(aLBoxArr[ static_cast< sal_uInt16 >(nIdx) ]) > nAbsPos)
+ nIdx--;
+ aLBoxArr.insert( aLBoxArr.begin() + static_cast< sal_uInt16 >(++nIdx) , pEntry);
+ }
+ }
+
+ // clear TLB from behind
+ long nIdx = (long)aLBoxArr.size() - 1L;
+ while (nIdx >= 0)
+ pTable->RemoveEntry(aLBoxArr[ static_cast< sal_uInt16 >(nIdx--) ]);
+
+ pTable->SetSelectHdl(LINK(this, SwRedlineAcceptDlg, SelectHdl));
+ pTable->SetDeselectHdl(LINK(this, SwRedlineAcceptDlg, DeselectHdl));
+ // unfortunately by Remove it was selected from the TLB always again ...
+ pTable->SelectAll(false);
+
+ aRedlineParents.erase( aRedlineParents.begin() + nStart, aRedlineParents.begin() + nEnd + 1);
+}
+
+void SwRedlineAcceptDlg::InsertParents(sal_uInt16 nStart, sal_uInt16 nEnd)
+{
+ SwView *pView = ::GetActiveView();
+ SwWrtShell* pSh = pView->GetWrtShellPtr();
+ sal_uInt16 nAutoFmt = HasRedlineAutoFmt() ? nsRedlineType_t::REDLINE_FORM_AUTOFMT : 0;
+
+ OUString sParent;
+ sal_uInt16 nCount = pSh->GetRedlineCount();
+ nEnd = std::min((sal_uInt16)nEnd, (sal_uInt16)(nCount - 1)); // also treats nEnd=USHRT_MAX (until the end)
+
+ if (nEnd == USHRT_MAX)
+ return; // no redlines in the document
+
+ RedlinData *pData;
+ SvTreeListEntry *pParent;
+ SwRedlineDataParent* pRedlineParent;
+ const SwRangeRedline* pCurrRedline;
+ if( !nStart && !pTable->FirstSelected() )
+ {
+ pCurrRedline = pSh->GetCurrRedline();
+ if( !pCurrRedline )
+ {
+ pSh->SwCrsrShell::Push();
+ if( 0 == (pCurrRedline = pSh->SelNextRedline()))
+ pCurrRedline = pSh->SelPrevRedline();
+ pSh->SwCrsrShell::Pop( false );
+ }
+ }
+ else
+ pCurrRedline = 0;
+
+ for (sal_uInt16 i = nStart; i <= nEnd; i++)
+ {
+ const SwRangeRedline& rRedln = pSh->GetRedline(i);
+ const SwRedlineData *pRedlineData = &rRedln.GetRedlineData();
+
+ pRedlineParent = new SwRedlineDataParent;
+ pRedlineParent->pData = pRedlineData;
+ pRedlineParent->pNext = 0;
+ OUString sComment(rRedln.GetComment());
+ pRedlineParent->sComment = sComment.replace('\n', ' ');
+ aRedlineParents.insert(aRedlineParents.begin() + i, pRedlineParent);
+
+ pData = new RedlinData;
+ pData->pData = pRedlineParent;
+ pData->bDisabled = false;
+
+ sParent = GetRedlineText(rRedln, pData->aDateTime);
+ pParent = pTable->InsertEntry(sParent, pData, 0, i);
+ if( pCurrRedline == &rRedln )
+ {
+ pTable->SetCurEntry( pParent );
+ pTable->Select( pParent );
+ pTable->MakeVisible( pParent );
+ }
+
+ pRedlineParent->pTLBParent = pParent;
+
+ InsertChildren(pRedlineParent, rRedln, nAutoFmt);
+ }
+}
+
+void SwRedlineAcceptDlg::CallAcceptReject( bool bSelect, bool bAccept )
+{
+ SwWrtShell* pSh = ::GetActiveView()->GetWrtShellPtr();
+ SvTreeListEntry* pEntry = bSelect ? pTable->FirstSelected() : pTable->First();
+ sal_uLong nPos = LONG_MAX;
+
+ typedef std::vector<SvTreeListEntry*> ListBoxEntries_t;
+ ListBoxEntries_t aRedlines;
+
+ // don't activate
+ OSL_ENSURE( bInhibitActivate == false,
+ "recursive call of CallAcceptReject?");
+ bInhibitActivate = true;
+
+ // collect redlines-to-be-accepted/rejected in aRedlines vector
+ while( pEntry )
+ {
+ if( !pTable->GetParent( pEntry ) )
+ {
+ if( bSelect && LONG_MAX == nPos )
+ nPos = pTable->GetModel()->GetAbsPos( pEntry );
+
+ RedlinData *pData = (RedlinData *)pEntry->GetUserData();
+
+ if( !pData->bDisabled )
+ aRedlines.push_back( pEntry );
+ }
+
+ pEntry = bSelect ? pTable->NextSelected(pEntry) : pTable->Next(pEntry);
+ }
+
+ bool (SwEditShell:: *FnAccRej)( sal_uInt16 ) = &SwEditShell::AcceptRedline;
+ if( !bAccept )
+ FnAccRej = &SwEditShell::RejectRedline;
+
+ SwWait aWait( *pSh->GetView().GetDocShell(), true );
+ pSh->StartAction();
+
+ // #111827#
+ if (aRedlines.size() > 1)
+ {
+ OUString aTmpStr;
+ {
+ SwRewriter aRewriter;
+ aRewriter.AddRule(UndoArg1,
+ OUString::number(aRedlines.size()));
+ aTmpStr = aRewriter.Apply(OUString(SW_RES(STR_N_REDLINES)));
+ }
+
+ SwRewriter aRewriter;
+ aRewriter.AddRule(UndoArg1, aTmpStr);
+
+ pSh->StartUndo(bAccept? UNDO_ACCEPT_REDLINE : UNDO_REJECT_REDLINE,
+ &aRewriter);
+ }
+
+ // accept/reject the redlines in aRedlines. The absolute
+ // position may change during the process (e.g. when two redlines
+ // are merged in result of another one being deleted), so the
+ // position must be resolved late and checked before using it.
+ // (cf #102547#)
+ ListBoxEntries_t::iterator aEnd = aRedlines.end();
+ for( ListBoxEntries_t::iterator aIter = aRedlines.begin();
+ aIter != aEnd;
+ ++aIter )
+ {
+ sal_uInt16 nPosition = GetRedlinePos( **aIter );
+ if( nPosition != USHRT_MAX )
+ (pSh->*FnAccRej)( nPosition );
+ }
+
+ // #111827#
+ if (aRedlines.size() > 1)
+ {
+ pSh->EndUndo();
+ }
+
+ pSh->EndAction();
+
+ bInhibitActivate = false;
+ Activate();
+
+ if( ULONG_MAX != nPos && pTable->GetEntryCount() )
+ {
+ if( nPos >= pTable->GetEntryCount() )
+ nPos = pTable->GetEntryCount() - 1;
+ pEntry = pTable->GetEntryAtAbsPos( nPos );
+ if( !pEntry && nPos-- )
+ pEntry = pTable->GetEntryAtAbsPos( nPos );
+ if( pEntry )
+ {
+ pTable->Select( pEntry );
+ pTable->MakeVisible( pEntry );
+ pTable->SetCurEntry(pEntry);
+ }
+ }
+ pTPView->EnableUndo();
+}
+
+sal_uInt16 SwRedlineAcceptDlg::GetRedlinePos( const SvTreeListEntry& rEntry ) const
+{
+ SwWrtShell* pSh = ::GetActiveView()->GetWrtShellPtr();
+ return pSh->FindRedlineOfData( *((SwRedlineDataParent*)((RedlinData *)
+ rEntry.GetUserData())->pData)->pData );
+}
+
+IMPL_LINK_NOARG(SwRedlineAcceptDlg, AcceptHdl)
+{
+ CallAcceptReject( true, true );
+ return 0;
+}
+
+IMPL_LINK_NOARG(SwRedlineAcceptDlg, AcceptAllHdl)
+{
+ CallAcceptReject( false, true );
+ return 0;
+}
+
+IMPL_LINK_NOARG(SwRedlineAcceptDlg, RejectHdl)
+{
+ CallAcceptReject( true, false );
+ return 0;
+}
+
+IMPL_LINK_NOARG(SwRedlineAcceptDlg, RejectAllHdl)
+{
+ CallAcceptReject( false, false );
+ return 0;
+}
+
+IMPL_LINK_NOARG(SwRedlineAcceptDlg, UndoHdl)
+{
+ SwView * pView = ::GetActiveView();
+ pView->GetViewFrame()->GetDispatcher()->
+ Execute(SID_UNDO, SFX_CALLMODE_SYNCHRON);
+ pTPView->EnableUndo(pView->GetSlotState(SID_UNDO) != 0);
+
+ Activate();
+
+ return 0;
+}
+
+IMPL_LINK_NOARG(SwRedlineAcceptDlg, FilterChangedHdl)
+{
+ SvxTPFilter *pFilterTP = aTabPagesCTRL.GetFilterPage();
+
+ if (pFilterTP->IsAction())
+ sFilterAction = pFilterTP->GetLbAction()->GetSelectEntry();
+ else
+ sFilterAction = aEmptyOUStr;
+
+ Init();
+
+ return 0;
+}
+
+IMPL_LINK_NOARG(SwRedlineAcceptDlg, DeselectHdl)
+{
+ // avoid flickering of buttons:
+ aDeselectTimer.Start();
+
+ return 0;
+}
+
+IMPL_LINK_NOARG(SwRedlineAcceptDlg, SelectHdl)
+{
+ aDeselectTimer.Stop();
+ aSelectTimer.Start();
+
+ return 0;
+}
+
+IMPL_LINK_NOARG(SwRedlineAcceptDlg, GotoHdl)
+{
+ SwWrtShell* pSh = ::GetActiveView()->GetWrtShellPtr();
+ aSelectTimer.Stop();
+
+ bool bIsNotFormated = false;
+ bool bSel = false;
+
+ //#98883# don't select redlines while the dialog is not focussed
+ //#107938# But not only ask pTable if it has the focus. To move
+ // the selection to the selected redline any child of pParentDlg
+ // may the focus.
+ SvTreeListEntry* pSelEntry = 0;
+
+ if (pParentDlg->HasChildPathFocus())
+ pSelEntry = pTable->FirstSelected();
+
+ if( pSelEntry )
+ {
+ SvTreeListEntry* pActEntry = pSelEntry;
+ pSh->StartAction();
+ pSh->EnterStdMode();
+ pSh->SetCareWin(pParentDlg);
+
+ while (pSelEntry)
+ {
+ if (pTable->GetParent(pSelEntry))
+ {
+ pActEntry = pTable->GetParent(pSelEntry);
+
+ if (pTable->IsSelected(pActEntry))
+ {
+ pSelEntry = pActEntry = pTable->NextSelected(pSelEntry);
+ continue; // don't select twice
+ }
+ }
+ else
+ bSel = true;
+
+ // #98864# find the selected redline (ignore, if the redline is already gone)
+ sal_uInt16 nPos = GetRedlinePos(*pActEntry);
+ if( nPos != USHRT_MAX )
+ {
+
+ const SwRangeRedline& rRedln = pSh->GetRedline( nPos );
+ bIsNotFormated |= nsRedlineType_t::REDLINE_FORMAT != rRedln.GetType();
+
+ if (pSh->GotoRedline(nPos, true))
+ {
+ pSh->SetInSelect();
+ pSh->EnterAddMode();
+ }
+ }
+
+ pSelEntry = pActEntry = pTable->NextSelected(pSelEntry);
+ }
+
+ pSh->LeaveAddMode();
+ pSh->EndAction();
+ pSh->SetCareWin(NULL);
+ }
+ bool bEnable = !pSh->getIDocumentRedlineAccess()->GetRedlinePassword().getLength();
+ pTPView->EnableAccept( bEnable && bSel /*&& !bReadonlySel*/ );
+ pTPView->EnableReject( bEnable && bSel && bIsNotFormated /*&& !bReadonlySel*/ );
+ pTPView->EnableRejectAll( bEnable && !bOnlyFormatedRedlines && !bHasReadonlySel );
+
+ return 0;
+}
+
+IMPL_LINK_NOARG(SwRedlineAcceptDlg, CommandHdl)
+{
+ const CommandEvent aCEvt(pTable->GetCommandEvent());
+
+ switch ( aCEvt.GetCommand() )
+ {
+ case COMMAND_CONTEXTMENU:
+ {
+ SwWrtShell* pSh = ::GetActiveView()->GetWrtShellPtr();
+ SvTreeListEntry* pEntry = pTable->FirstSelected();
+ const SwRangeRedline *pRed = 0;
+
+ if (pEntry)
+ {
+ SvTreeListEntry* pTopEntry = pEntry;
+
+ if (pTable->GetParent(pEntry))
+ pTopEntry = pTable->GetParent(pEntry);
+
+ sal_uInt16 nPos = GetRedlinePos(*pTopEntry);
+
+ // disable commenting for protected areas
+ if (nPos != USHRT_MAX && (pRed = pSh->GotoRedline(nPos, true)) != 0)
+ {
+ if( pSh->IsCrsrPtAtEnd() )
+ pSh->SwapPam();
+ pSh->SetInSelect();
+ }
+ }
+
+ aPopup.EnableItem( MN_EDIT_COMMENT, pEntry && pRed &&
+ !pTable->GetParent(pEntry) &&
+ !pTable->NextSelected(pEntry)
+//JP 27.9.2001: make no sense if we handle readonly sections
+// && pRed->HasReadonlySel()
+ );
+
+ aPopup.EnableItem( MN_SUB_SORT, pTable->First() != 0 );
+ sal_uInt16 nColumn = pTable->GetSortedCol();
+ if (nColumn == 0xffff)
+ nColumn = 4;
+
+ PopupMenu *pSubMenu = aPopup.GetPopupMenu(MN_SUB_SORT);
+ if (pSubMenu)
+ {
+ for (sal_uInt16 i = MN_SORT_ACTION; i < MN_SORT_ACTION + 5; i++)
+ pSubMenu->CheckItem(i, false);
+
+ pSubMenu->CheckItem(nColumn + MN_SORT_ACTION);
+ }
+
+ sal_uInt16 nRet = aPopup.Execute(pTable, aCEvt.GetMousePosPixel());
+
+ switch( nRet )
+ {
+ case MN_EDIT_COMMENT:
+ {
+ if (pEntry)
+ {
+ if (pTable->GetParent(pEntry))
+ pEntry = pTable->GetParent(pEntry);
+
+ sal_uInt16 nPos = GetRedlinePos(*pEntry);
+
+ if (nPos == USHRT_MAX)
+ break;
+
+ const SwRangeRedline &rRedline = pSh->GetRedline(nPos);
+
+ /* enable again once we have redline comments in the margin
+ sComment = rRedline.GetComment();
+ if ( !sComment.Len() )
+ GetActiveView()->GetDocShell()->Broadcast(SwRedlineHint(&rRedline,SWREDLINE_INSERTED));
+ const_cast<SwRangeRedline&>(rRedline).Broadcast(SwRedlineHint(&rRedline,SWREDLINE_FOCUS));
+ */
+
+ OUString sComment = convertLineEnd(rRedline.GetComment(), GetSystemLineEnd());
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ OSL_ENSURE(pFact, "Dialogdiet fail!");
+ ::DialogGetRanges fnGetRange = pFact->GetDialogGetRangesFunc();
+ OSL_ENSURE(fnGetRange, "Dialogdiet fail! GetRanges()");
+ SfxItemSet aSet( pSh->GetAttrPool(), fnGetRange() );
+
+ aSet.Put(SvxPostItTextItem(sComment, SID_ATTR_POSTIT_TEXT));
+ aSet.Put(SvxPostItAuthorItem(rRedline.GetAuthorString(), SID_ATTR_POSTIT_AUTHOR));
+
+ aSet.Put(SvxPostItDateItem( GetAppLangDateTimeString(
+ rRedline.GetRedlineData().GetTimeStamp() ),
+ SID_ATTR_POSTIT_DATE ));
+
+ AbstractSvxPostItDialog* pDlg = pFact->CreateSvxPostItDialog( pParentDlg, aSet, false );
+ OSL_ENSURE(pDlg, "Dialogdiet fail!");
+
+ pDlg->HideAuthor();
+
+ sal_uInt16 nResId = 0;
+ switch( rRedline.GetType() )
+ {
+ case nsRedlineType_t::REDLINE_INSERT:
+ nResId = STR_REDLINE_INSERTED;
+ break;
+ case nsRedlineType_t::REDLINE_DELETE:
+ nResId = STR_REDLINE_DELETED;
+ break;
+ case nsRedlineType_t::REDLINE_FORMAT:
+ nResId = STR_REDLINE_FORMATED;
+ break;
+ case nsRedlineType_t::REDLINE_TABLE:
+ nResId = STR_REDLINE_TABLECHG;
+ break;
+ default:;//prevent warning
+ }
+ OUString sTitle(SW_RES(STR_REDLINE_COMMENT));
+ if( nResId )
+ sTitle += SW_RESSTR( nResId );
+ pDlg->SetText(sTitle);
+
+ pSh->SetCareWin(pDlg->GetWindow());
+
+ if ( pDlg->Execute() == RET_OK )
+ {
+ const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
+ OUString sMsg(((const SvxPostItTextItem&)pOutSet->Get(SID_ATTR_POSTIT_TEXT)).GetValue());
+
+ // insert / change comment
+ pSh->SetRedlineComment(sMsg);
+ pTable->SetEntryText(sMsg.replace('\n', ' '), pEntry, 3);
+ }
+
+ delete pDlg;
+ pSh->SetCareWin(NULL);
+ }
+
+ }
+ break;
+
+ case MN_SORT_ACTION:
+ case MN_SORT_AUTHOR:
+ case MN_SORT_DATE:
+ case MN_SORT_COMMENT:
+ case MN_SORT_POSITION:
+ {
+ bSortDir = true;
+ if (nRet - MN_SORT_ACTION == 4 && pTable->GetSortedCol() == 0xffff)
+ break; // we already have it
+
+ nSortMode = nRet - MN_SORT_ACTION;
+ if (nSortMode == 4)
+ nSortMode = 0xffff; // unsorted / sorted by position
+
+ if (pTable->GetSortedCol() == nSortMode)
+ bSortDir = !pTable->GetSortDirection();
+
+ SwWait aWait( *::GetActiveView()->GetDocShell(), false );
+ pTable->SortByCol(nSortMode, bSortDir);
+ if (nSortMode == 0xffff)
+ Init(); // newly fill everything
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+void SwRedlineAcceptDlg::Initialize(const OUString& rExtraData)
+{
+ if (!rExtraData.isEmpty())
+ {
+ sal_Int32 nPos = rExtraData.indexOf("AcceptChgDat:");
+
+ // try to read the alignment string "ALIGN:(...)"; if none existing,
+ // it's an old version
+ if (nPos != -1)
+ {
+ sal_Int32 n1 = rExtraData.indexOf('(', nPos);
+ if (n1 != -1)
+ {
+ sal_Int32 n2 = rExtraData.indexOf(')', n1);
+ if (n2 != -1)
+ {
+ // cut out the alignment string
+ OUString aStr = rExtraData.copy(nPos, n2 - nPos + 1);
+ aStr = aStr.copy(n1 - nPos + 1);
+
+ if (!aStr.isEmpty())
+ {
+ sal_uInt16 nCount = static_cast< sal_uInt16 >(aStr.toInt32());
+
+ for (sal_uInt16 i = 0; i < nCount; i++)
+ {
+ sal_Int32 n3 = aStr.indexOf(';');
+ aStr = aStr.copy(n3 + 1);
+ pTable->SetTab(i, aStr.toInt32(), MAP_PIXEL);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void SwRedlineAcceptDlg::FillInfo(OUString &rExtraData) const
+{
+ rExtraData += "AcceptChgDat:(";
+
+ sal_uInt16 nCount = pTable->TabCount();
+
+ rExtraData += OUString::number(nCount);
+ rExtraData += ";";
+ for(sal_uInt16 i = 0; i < nCount; i++)
+ {
+ rExtraData += OUString::number( pTable->GetTab(i) );
+ rExtraData += ";";
+ }
+ rExtraData += ")";
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/misc/redlndlg.hrc b/sw/source/uibase/misc/redlndlg.hrc
new file mode 100644
index 000000000000..e3d0464faca6
--- /dev/null
+++ b/sw/source/uibase/misc/redlndlg.hrc
@@ -0,0 +1,28 @@
+/* -*- 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 .
+ */
+
+#define MN_EDIT_COMMENT 1
+#define MN_SUB_SORT 2
+#define MN_SORT_ACTION 3
+#define MN_SORT_AUTHOR 4
+#define MN_SORT_DATE 5
+#define MN_SORT_COMMENT 6
+#define MN_SORT_POSITION 7
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/misc/redlndlg.src b/sw/source/uibase/misc/redlndlg.src
new file mode 100644
index 000000000000..e3b9aadb3a0f
--- /dev/null
+++ b/sw/source/uibase/misc/redlndlg.src
@@ -0,0 +1,85 @@
+/* -*- 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 .
+ */
+/* StarView resource file */
+
+#include "redlndlg.hrc"
+#include "misc.hrc"
+#include "helpid.h"
+
+Menu MN_REDLINE_POPUP
+{
+ ItemList =
+ {
+ MenuItem
+ {
+ Identifier = MN_EDIT_COMMENT ;
+ HelpID = HID_EDIT_COMMENT ;
+ Text [ en-US ] = "Edit Comment..." ;
+ };
+ MenuItem
+ {
+ Identifier = MN_SUB_SORT ;
+ RadioCheck = TRUE ;
+ SubMenu = Menu
+ {
+ ItemList =
+ {
+ MenuItem
+ {
+ Identifier = MN_SORT_ACTION ;
+ HelpID = HID_SORT_ACTION ;
+ RadioCheck = TRUE ;
+ Text [ en-US ] = "Action" ;
+ };
+ MenuItem
+ {
+ Identifier = MN_SORT_AUTHOR ;
+ HelpID = HID_SORT_AUTHOR ;
+ RadioCheck = TRUE ;
+ Text [ en-US ] = "Author" ;
+ };
+ MenuItem
+ {
+ Identifier = MN_SORT_DATE ;
+ HelpID = HID_SORT_DATE ;
+ RadioCheck = TRUE ;
+ Text [ en-US ] = "Date" ;
+ };
+ MenuItem
+ {
+ Identifier = MN_SORT_COMMENT ;
+ HelpID = HID_SORT_COMMENT ;
+ RadioCheck = TRUE ;
+ Text [ en-US ] = "Comment" ;
+ };
+ MenuItem
+ {
+ Identifier = MN_SORT_POSITION ;
+ HelpID = HID_SW_SORT_POSITION ;
+ RadioCheck = TRUE ;
+ Text [ en-US ] = "Document position" ;
+ };
+ };
+ };
+ Text [ en-US ] = "Sort By" ;
+ };
+ };
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/misc/swruler.cxx b/sw/source/uibase/misc/swruler.cxx
new file mode 100644
index 000000000000..1ba770fd6a42
--- /dev/null
+++ b/sw/source/uibase/misc/swruler.cxx
@@ -0,0 +1,302 @@
+/* -*- 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/.
+ */
+
+// FIX fdo#38246 https://bugs.libreoffice.org/show_bug.cgi?id=38246
+// Design proposal: https://wiki.documentfoundation.org/Design/Whiteboards/Comments_Ruler_Control
+// TODO Alpha blend border when it doesn't fit in window
+
+#include "swruler.hxx"
+
+#include "viewsh.hxx"
+#include "edtwin.hxx"
+#include "PostItMgr.hxx"
+#include "viewopt.hxx"
+#include <view.hxx>
+#include "cmdid.h"
+#include <sfx2/request.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <vcl/settings.hxx>
+#include "misc.hrc"
+
+#define CONTROL_BORDER_WIDTH 1
+
+#define CONTROL_LEFT_OFFSET 6
+#define CONTROL_RIGHT_OFFSET 3
+#define CONTROL_TOP_OFFSET 4
+
+#define CONTROL_TRIANGLE_WIDTH 4
+#define CONTROL_TRIANGLE_PAD 3
+
+// Constructor
+SwCommentRuler::SwCommentRuler( SwViewShell* pViewSh, Window* pParent, SwEditWin* pWin, sal_uInt16 nRulerFlags, SfxBindings& rBindings, WinBits nWinStyle)
+: SvxRuler(pParent, pWin, nRulerFlags, rBindings, nWinStyle | WB_HSCROLL)
+, mpViewShell(pViewSh)
+, mpSwWin(pWin)
+, mbIsHighlighted(false)
+, mnFadeRate(0)
+, maVirDev( *this )
+{
+ // Set fading timeout: 5 x 40ms = 200ms
+ maFadeTimer.SetTimeout(40);
+ maFadeTimer.SetTimeoutHdl( LINK( this, SwCommentRuler, FadeHandler ) );
+}
+
+// Destructor
+SwCommentRuler::~SwCommentRuler()
+{
+}
+
+void SwCommentRuler::Paint( const Rectangle& rRect )
+{
+ SvxRuler::Paint( rRect );
+ // Don't draw if there is not any note
+ if ( mpViewShell->GetPostItMgr()
+ && mpViewShell->GetPostItMgr()->HasNotes() )
+ DrawCommentControl();
+}
+
+void SwCommentRuler::DrawCommentControl()
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ bool bIsCollapsed = ! mpViewShell->GetPostItMgr()->ShowNotes();
+
+ Rectangle aControlRect = GetCommentControlRegion();
+ maVirDev.SetOutputSizePixel( aControlRect.GetSize() );
+
+ // Paint comment control background
+ // TODO Check if these are best colors to be used
+ Color aBgColor = GetFadedColor( rStyleSettings.GetDarkShadowColor(), rStyleSettings.GetWorkspaceColor() );
+ maVirDev.SetFillColor( aBgColor );
+
+ if ( mbIsHighlighted || !bIsCollapsed )
+ {
+ // Draw borders
+ maVirDev.SetLineColor( rStyleSettings.GetShadowColor() );
+ }
+ else
+ {
+ // No borders
+ maVirDev.SetLineColor();
+ }
+
+ maVirDev.DrawRect( Rectangle( Point(), aControlRect.GetSize() ) );
+
+ // Label and arrow tip
+ OUString aLabel( SW_RESSTR ( STR_COMMENTS_LABEL ) );
+ // Get label and arrow coordinates
+ Point aLabelPos;
+ Point aArrowPos;
+ bool bArrowToRight;
+ // TODO Discover why it should be 0 instead of CONTROL_BORDER_WIDTH + CONTROL_TOP_OFFSET
+ aLabelPos.Y() = 0;
+ aArrowPos.Y() = CONTROL_BORDER_WIDTH + CONTROL_TOP_OFFSET;
+ if ( !Application::GetSettings().GetLayoutRTL() )
+ {
+ // LTR
+ if ( bIsCollapsed )
+ {
+ // It should draw something like | > Comments |
+ aLabelPos.X() = CONTROL_LEFT_OFFSET + CONTROL_TRIANGLE_WIDTH + CONTROL_TRIANGLE_PAD;
+ aArrowPos.X() = CONTROL_LEFT_OFFSET;
+ }
+ else
+ {
+ // It should draw something like | Comments < |
+ aLabelPos.X() = CONTROL_LEFT_OFFSET;
+ aArrowPos.X() = aControlRect.GetSize().Width() - 1 - CONTROL_RIGHT_OFFSET - CONTROL_BORDER_WIDTH - CONTROL_TRIANGLE_WIDTH;
+ }
+ bArrowToRight = bIsCollapsed;
+ }
+ else
+ {
+ // RTL
+ long nLabelWidth = GetTextWidth( aLabel );
+ if ( bIsCollapsed )
+ {
+ // It should draw something like | Comments < |
+ aArrowPos.X() = aControlRect.GetSize().Width() - 1 - CONTROL_RIGHT_OFFSET - CONTROL_BORDER_WIDTH - CONTROL_TRIANGLE_WIDTH;
+ aLabelPos.X() = aArrowPos.X() - CONTROL_TRIANGLE_PAD - nLabelWidth;
+ }
+ else
+ {
+ // It should draw something like | > Comments |
+ aLabelPos.X() = aControlRect.GetSize().Width() - 1 - CONTROL_RIGHT_OFFSET - CONTROL_BORDER_WIDTH - nLabelWidth;
+ aArrowPos.X() = CONTROL_LEFT_OFFSET;
+ }
+ bArrowToRight = !bIsCollapsed;
+ }
+
+ // Draw label
+ Color aTextColor = GetFadedColor( rStyleSettings.GetButtonTextColor(), rStyleSettings.GetDarkShadowColor() );
+ maVirDev.SetTextColor( aTextColor );
+ // FIXME Expected font size?
+ maVirDev.DrawText( aLabelPos, aLabel );
+
+ // Draw arrow
+ // FIXME consistence of button colors. http://opengrok.libreoffice.org/xref/core/vcl/source/control/button.cxx#785
+ Color aArrowColor = GetFadedColor( Color( COL_BLACK ), rStyleSettings.GetShadowColor() );
+ ImplDrawArrow ( aArrowPos.X(), aArrowPos.Y(), aArrowColor, bArrowToRight );
+
+ // Blit comment control
+ DrawOutDev( aControlRect.TopLeft(), aControlRect.GetSize(), Point(), aControlRect.GetSize(), maVirDev );
+}
+
+void SwCommentRuler::ImplDrawArrow(long nX, long nY, const Color& rColor, bool bPointRight)
+{
+ maVirDev.SetLineColor();
+ maVirDev.SetFillColor( rColor );
+ if ( bPointRight )
+ {
+ maVirDev.DrawRect( Rectangle( nX+0, nY+0, nX+0, nY+6 ) );
+ maVirDev.DrawRect( Rectangle( nX+1, nY+1, nX+1, nY+5 ) );
+ maVirDev.DrawRect( Rectangle( nX+2, nY+2, nX+2, nY+4 ) );
+ maVirDev.DrawRect( Rectangle( nX+3, nY+3, nX+3, nY+3 ) );
+ }
+ else
+ {
+ maVirDev.DrawRect( Rectangle( nX+0, nY+3, nX+0, nY+3 ) );
+ maVirDev.DrawRect( Rectangle( nX+1, nY+2, nX+1, nY+4 ) );
+ maVirDev.DrawRect( Rectangle( nX+2, nY+1, nX+2, nY+5 ) );
+ maVirDev.DrawRect( Rectangle( nX+3, nY+0, nX+3, nY+6 ) );
+ }
+}
+
+// Just accept double-click outside comment control
+void SwCommentRuler::Command( const CommandEvent& rCEvt )
+{
+ Point aMousePos = rCEvt.GetMousePosPixel();
+ // Ignore command request if it is inside Comment Control
+ if ( !mpViewShell->GetPostItMgr()
+ || !mpViewShell->GetPostItMgr()->HasNotes()
+ || !GetCommentControlRegion().IsInside( aMousePos ) )
+ SvxRuler::Command( rCEvt );
+}
+
+void SwCommentRuler::MouseMove(const MouseEvent& rMEvt)
+{
+ SvxRuler::MouseMove(rMEvt);
+ if ( ! mpViewShell->GetPostItMgr() || ! mpViewShell->GetPostItMgr()->HasNotes() )
+ return;
+
+ Point aMousePos = rMEvt.GetPosPixel();
+ bool bWasHighlighted = mbIsHighlighted;
+ mbIsHighlighted = GetCommentControlRegion().IsInside( aMousePos );
+ if ( mbIsHighlighted != bWasHighlighted )
+ {
+ // Set proper help text
+ if ( mbIsHighlighted )
+ {
+ // Mouse over comment control
+ UpdateCommentHelpText();
+ }
+ else
+ {
+ // Mouse out of comment control
+ // FIXME Should remember previous tooltip text?
+ SetQuickHelpText( OUString() );
+ }
+ // Do start fading
+ maFadeTimer.Start();
+ }
+}
+
+void SwCommentRuler::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ Point aMousePos = rMEvt.GetPosPixel();
+ if ( !rMEvt.IsLeft() || IsTracking() || !GetCommentControlRegion().IsInside( aMousePos ) )
+ {
+ SvxRuler::MouseButtonDown(rMEvt);
+ return;
+ }
+
+ // Toggle notes visibility
+ SwView &rView = mpSwWin->GetView();
+ SfxRequest aRequest( rView.GetViewFrame(), FN_VIEW_NOTES );
+ rView.ExecViewOptions( aRequest );
+
+ // It is inside comment control, so update help text
+ UpdateCommentHelpText();
+
+ Invalidate();
+}
+
+void SwCommentRuler::Update()
+{
+ Rectangle aPreviousControlRect = GetCommentControlRegion();
+ SvxRuler::Update();
+ if (aPreviousControlRect != GetCommentControlRegion())
+ Invalidate();
+}
+
+void SwCommentRuler::UpdateCommentHelpText()
+{
+ int nTooltipResId;
+ if ( mpViewShell->GetPostItMgr()->ShowNotes() )
+ nTooltipResId = STR_HIDE_COMMENTS;
+ else
+ nTooltipResId = STR_SHOW_COMMENTS;
+ SetQuickHelpText( OUString( SW_RESSTR( nTooltipResId ) ) );
+}
+
+// TODO Make Ruler return its central rectangle instead of margins.
+Rectangle SwCommentRuler::GetCommentControlRegion()
+{
+ long nLeft = 0;
+ SwPostItMgr *pPostItMgr = mpViewShell->GetPostItMgr();
+
+ //rhbz#1006850 When the SwPostItMgr ctor is called from SwView::SwView it
+ //triggers an update of the uiview, but the result of the ctor hasn't been
+ //set into the mpViewShell yet, so GetPostItMgr is temporarily still NULL
+ if (!pPostItMgr)
+ return Rectangle();
+
+ unsigned long nSidebarWidth = pPostItMgr->GetSidebarWidth(true);
+ //FIXME When the page width is larger then screen, the ruler is misplaced by one pixel
+ if (GetTextRTL())
+ nLeft = GetPageOffset() - nSidebarWidth + GetBorderOffset();
+ else
+ nLeft = GetWinOffset() + GetPageOffset() + mpSwWin->LogicToPixel(Size(GetPageWidth(), 0)).Width();
+ long nTop = 0 + 4; // Ruler::ImplDraw uses RULER_OFF (value: 3px) as offset, and Ruler::ImplFormat adds one extra pixel
+ // Somehow pPostItMgr->GetSidebarBorderWidth() returns border width already doubled
+ long nRight = nLeft + nSidebarWidth + pPostItMgr->GetSidebarBorderWidth(true);
+ long nBottom = nTop + GetRulerVirHeight() - 3;
+
+ Rectangle aRect(nLeft, nTop, nRight, nBottom);
+ return aRect;
+}
+
+Color SwCommentRuler::GetFadedColor(const Color &rHighColor, const Color &rLowColor)
+{
+ if ( ! maFadeTimer.IsActive() )
+ return mbIsHighlighted ? rHighColor : rLowColor;
+
+ Color aColor = rHighColor;
+ aColor.Merge( rLowColor, mnFadeRate * 255/100.f );
+ return aColor;
+}
+
+IMPL_LINK_NOARG(SwCommentRuler, FadeHandler)
+{
+ const int nStep = 25;
+ if ( mbIsHighlighted && mnFadeRate < 100 )
+ mnFadeRate += nStep;
+ else if ( !mbIsHighlighted && mnFadeRate > 0 )
+ mnFadeRate -= nStep;
+ else
+ return 0;
+
+ Invalidate();
+
+ if ( mnFadeRate != 0 && mnFadeRate != 100)
+ maFadeTimer.Start();
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */