diff options
Diffstat (limited to 'sfx2/source/doc')
57 files changed, 46325 insertions, 0 deletions
diff --git a/sfx2/source/doc/DocumentMetadataAccess.cxx b/sfx2/source/doc/DocumentMetadataAccess.cxx new file mode 100644 index 000000000000..df0781be8877 --- /dev/null +++ b/sfx2/source/doc/DocumentMetadataAccess.cxx @@ -0,0 +1,1432 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sfx2.hxx" + +#include <sfx2/DocumentMetadataAccess.hxx> + +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/task/ErrorCodeIOException.hpp> +#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> +#include <com/sun/star/rdf/FileFormat.hpp> +#include <com/sun/star/rdf/URIs.hpp> +#include <com/sun/star/rdf/Statement.hpp> +#include <com/sun/star/rdf/Literal.hpp> +#include <com/sun/star/rdf/URI.hpp> +#include <com/sun/star/rdf/Repository.hpp> + +#include <rtl/uuid.h> +#include <rtl/ustrbuf.hxx> +#include <rtl/uri.hxx> +#include <rtl/bootstrap.hxx> + +#include <comphelper/interaction.hxx> +#include <comphelper/makesequence.hxx> +#include <comphelper/mediadescriptor.hxx> +#include <comphelper/sequenceasvector.hxx> +#include <comphelper/storagehelper.hxx> + +#include <sfx2/docfile.hxx> +#include <sfx2/XmlIdRegistry.hxx> + +#include <libxml/tree.h> // for xmlValidateNCName + +#include <boost/bind.hpp> +#include <boost/shared_array.hpp> +#include <boost/tuple/tuple.hpp> + +#include <vector> +#include <set> +#include <map> +#include <functional> +#include <algorithm> + +#include <unotools/ucbhelper.hxx> +#include <com/sun/star/uri/XUriReference.hpp> +#include <com/sun/star/uri/XUriReferenceFactory.hpp> +#include <com/sun/star/uri/XVndSunStarPkgUrlReferenceFactory.hpp> + + +/* + Note: in the context of this implementation, all rdf.QueryExceptions and + rdf.RepositoryExceptions are RuntimeExceptions, and will be reported as such. + + This implementation assumes that it is only used with ODF documents, not mere + ODF packages. In other words, we enforce that metadata files must not be + called reserved names. + */ + +using namespace ::com::sun::star; + +namespace sfx2 { + + +bool isValidNCName(::rtl::OUString const & i_rIdref) +{ + const ::rtl::OString id( + ::rtl::OUStringToOString(i_rIdref, RTL_TEXTENCODING_UTF8) ); + return !(xmlValidateNCName( + reinterpret_cast<const unsigned char*>(id.getStr()), 0)); +} + +//////////////////////////////////////////////////////////////////////////// + +static const char s_content [] = "content.xml"; +static const char s_styles [] = "styles.xml"; +static const char s_meta [] = "meta.xml"; +static const char s_settings[] = "settings.xml"; +static const char s_manifest[] = "manifest.rdf"; +static const char s_rdfxml [] = "application/rdf+xml"; +static const char s_odfmime [] = "application/vnd.oasis.opendocument."; + +//////////////////////////////////////////////////////////////////////////// + +static bool isContentFile(::rtl::OUString const & i_rPath) +{ + return i_rPath.equalsAscii(s_content); +} + +static bool isStylesFile (::rtl::OUString const & i_rPath) +{ + return i_rPath.equalsAscii(s_styles); +} + +static bool isReservedFile(::rtl::OUString const & i_rPath) +{ + return isContentFile(i_rPath) + || isStylesFile(i_rPath) + || i_rPath.equalsAscii(s_meta) + || i_rPath.equalsAscii(s_settings); +} + +//////////////////////////////////////////////////////////////////////////// + +uno::Reference<rdf::XURI> createBaseURI( + uno::Reference<uno::XComponentContext> const & i_xContext, + uno::Reference<embed::XStorage> const & i_xStorage, + ::rtl::OUString const & i_rPkgURI, ::rtl::OUString const & i_rSubDocument) +{ + if (!i_xContext.is() || !i_xStorage.is() || !i_rPkgURI.getLength()) { + throw uno::RuntimeException(); + } + + // #i108078# workaround non-hierarchical vnd.sun.star.expand URIs + // this really should be done somewhere else, not here. + ::rtl::OUString pkgURI(i_rPkgURI); + if (pkgURI.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.expand:"))) + { + // expand it here (makeAbsolute requires hierarchical URI) + pkgURI = pkgURI.copy( RTL_CONSTASCII_LENGTH("vnd.sun.star.expand:") ); + if (pkgURI.getLength() != 0) { + pkgURI = ::rtl::Uri::decode( + pkgURI, rtl_UriDecodeStrict, RTL_TEXTENCODING_UTF8); + if (pkgURI.getLength() == 0) { + throw uno::RuntimeException(); + } + ::rtl::Bootstrap::expandMacros(pkgURI); + } + } + + const uno::Reference<lang::XMultiComponentFactory> xServiceFactory( + i_xContext->getServiceManager(), uno::UNO_SET_THROW); + const uno::Reference<uri::XUriReferenceFactory> xUriFactory( + xServiceFactory->createInstanceWithContext( + ::rtl::OUString::createFromAscii( + "com.sun.star.uri.UriReferenceFactory"), i_xContext), + uno::UNO_QUERY_THROW); + uno::Reference< uri::XUriReference > xBaseURI; + + const uno::Reference< uri::XUriReference > xPkgURI( + xUriFactory->parse(pkgURI), uno::UNO_SET_THROW ); + xPkgURI->clearFragment(); + + // need to know whether the storage is a FileSystemStorage + // XServiceInfo would be better, but it is not implemented +// if ( pkgURI.getLength() && ::utl::UCBContentHelper::IsFolder(pkgURI) ) + if (true) { + xBaseURI.set( xPkgURI, uno::UNO_SET_THROW ); +#if 0 + } else { + const uno::Reference<uri::XVndSunStarPkgUrlReferenceFactory> + xPkgUriFactory( xServiceFactory->createInstanceWithContext( + ::rtl::OUString::createFromAscii( + "com.sun.star.uri.VndSunStarPkgUrlReferenceFactory"), + i_xContext), + uno::UNO_QUERY_THROW); + xBaseURI.set( xPkgUriFactory->createVndSunStarPkgUrlReference(xPkgURI), + uno::UNO_SET_THROW ); +#endif + } + ::rtl::OUStringBuffer buf; + if (!xBaseURI->getUriReference().endsWithAsciiL("/", 1)) + { + const sal_Int32 count( xBaseURI->getPathSegmentCount() ); + if (count > 0) + { + const ::rtl::OUString last( xBaseURI->getPathSegment(count - 1) ); + buf.append(last); + } + buf.append(static_cast<sal_Unicode>('/')); + } + if (i_rSubDocument.getLength()) + { + buf.append(i_rSubDocument); + buf.append(static_cast<sal_Unicode>('/')); + } + const ::rtl::OUString Path(buf.makeStringAndClear()); + if (Path.getLength()) + { + const uno::Reference< uri::XUriReference > xPathURI( + xUriFactory->parse(Path), uno::UNO_SET_THROW ); + xBaseURI.set( + xUriFactory->makeAbsolute(xBaseURI, xPathURI, + true, uri::RelativeUriExcessParentSegments_ERROR), + uno::UNO_SET_THROW); + } + + return rdf::URI::create(i_xContext, xBaseURI->getUriReference()); +} + +//////////////////////////////////////////////////////////////////////////// + +struct DocumentMetadataAccess_Impl +{ + // note: these are all initialized in constructor, and loadFromStorage + const uno::Reference<uno::XComponentContext> m_xContext; + const IXmlIdRegistrySupplier & m_rXmlIdRegistrySupplier; + uno::Reference<rdf::XURI> m_xBaseURI; + uno::Reference<rdf::XRepository> m_xRepository; + uno::Reference<rdf::XNamedGraph> m_xManifest; + DocumentMetadataAccess_Impl( + uno::Reference<uno::XComponentContext> const& i_xContext, + IXmlIdRegistrySupplier const & i_rRegistrySupplier) + : m_xContext(i_xContext) + , m_rXmlIdRegistrySupplier(i_rRegistrySupplier) + , m_xBaseURI() + , m_xRepository() + , m_xManifest() + { + OSL_ENSURE(m_xContext.is(), "context null"); + } +}; + +// this is... a hack. +template<sal_Int16 Constant> +/*static*/ uno::Reference<rdf::XURI> +getURI(uno::Reference< uno::XComponentContext > const & i_xContext) +{ + static uno::Reference< rdf::XURI > xURI( + rdf::URI::createKnown(i_xContext, Constant), uno::UNO_QUERY_THROW); + return xURI; +} + + +/** would storing the file to a XStorage succeed? */ +static bool isFileNameValid(const ::rtl::OUString & i_rFileName) +{ + if (i_rFileName.getLength() <= 0) return false; + if (i_rFileName[0] == '/') return false; // no absolute paths! + sal_Int32 idx(0); + do { + const ::rtl::OUString segment( + i_rFileName.getToken(0, static_cast<sal_Unicode> ('/'), idx) ); + if (!segment.getLength() || // no empty segments + segment.equalsAscii(".") || // no . segments + segment.equalsAscii("..") || // no .. segments + !::comphelper::OStorageHelper::IsValidZipEntryFileName( + segment, sal_False)) // no invalid characters + return false; + } while (idx >= 0); + return true; +} + +/** split a uri hierarchy into first segment and rest */ +static bool +splitPath(::rtl::OUString const & i_rPath, + ::rtl::OUString & o_rDir, ::rtl::OUString& o_rRest) +{ + const sal_Int32 idx(i_rPath.indexOf(static_cast<sal_Unicode>('/'))); + if (idx < 0 || idx >= i_rPath.getLength()) { + o_rDir = ::rtl::OUString(); + o_rRest = i_rPath; + return true; + } else if (idx == 0 || idx == i_rPath.getLength() - 1) { + // input must not start or end with '/' + return false; + } else { + o_rDir = (i_rPath.copy(0, idx)); + o_rRest = (i_rPath.copy(idx+1)); + return true; + } +} + +static bool +splitXmlId(::rtl::OUString const & i_XmlId, + ::rtl::OUString & o_StreamName, ::rtl::OUString& o_Idref ) +{ + const sal_Int32 idx(i_XmlId.indexOf(static_cast<sal_Unicode>('#'))); + if ((idx <= 0) || (idx >= i_XmlId.getLength() - 1)) { + return false; + } else { + o_StreamName = (i_XmlId.copy(0, idx)); + o_Idref = (i_XmlId.copy(idx+1)); + return isValidXmlId(o_StreamName, o_Idref); + } +} + +//////////////////////////////////////////////////////////////////////////// + +static uno::Reference<rdf::XURI> +getURIForStream(struct DocumentMetadataAccess_Impl& i_rImpl, + ::rtl::OUString const& i_rPath) +{ + const uno::Reference<rdf::XURI> xURI( + rdf::URI::createNS( i_rImpl.m_xContext, + i_rImpl.m_xBaseURI->getStringValue(), i_rPath), + uno::UNO_SET_THROW); + return xURI; +} + +/** add statements declaring i_xResource to be a file of type i_xType with + path i_rPath to manifest, with optional additional types i_pTypes */ +static void +addFile(struct DocumentMetadataAccess_Impl & i_rImpl, + uno::Reference<rdf::XURI> const& i_xType, + ::rtl::OUString const & i_rPath, + const uno::Sequence < uno::Reference< rdf::XURI > > * i_pTypes = 0) +{ + try { + const uno::Reference<rdf::XURI> xURI( getURIForStream( + i_rImpl, i_rPath) ); + + i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI.get(), + getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext), + xURI.get()); + i_rImpl.m_xManifest->addStatement(xURI.get(), + getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), + i_xType.get()); + if (i_pTypes) { + for (sal_Int32 i = 0; i < i_pTypes->getLength(); ++i) { + i_rImpl.m_xManifest->addStatement(xURI.get(), + getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), + (*i_pTypes)[i].get()); + } + } + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "addFile: exception"), /*this*/0, uno::makeAny(e)); + } +} + +/** add content.xml or styles.xml to manifest */ +static bool +addContentOrStylesFileImpl(struct DocumentMetadataAccess_Impl & i_rImpl, + const ::rtl::OUString & i_rPath) +{ + uno::Reference<rdf::XURI> xType; + if (isContentFile(i_rPath)) { + xType.set(getURI<rdf::URIs::ODF_CONTENTFILE>(i_rImpl.m_xContext)); + } else if (isStylesFile(i_rPath)) { + xType.set(getURI<rdf::URIs::ODF_STYLESFILE>(i_rImpl.m_xContext)); + } else { + return false; + } + addFile(i_rImpl, xType.get(), i_rPath); + return true; +} + +/** add metadata file to manifest */ +static void +addMetadataFileImpl(struct DocumentMetadataAccess_Impl & i_rImpl, + const ::rtl::OUString & i_rPath, + const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes) +{ + addFile(i_rImpl, + getURI<rdf::URIs::PKG_METADATAFILE>(i_rImpl.m_xContext), + i_rPath, &i_rTypes); +} + +/** remove a file from the manifest */ +static void +removeFile(struct DocumentMetadataAccess_Impl & i_rImpl, + uno::Reference<rdf::XURI> const& i_xPart) +{ + if (!i_xPart.is()) throw uno::RuntimeException(); + try { + i_rImpl.m_xManifest->removeStatements(i_rImpl.m_xBaseURI.get(), + getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext), + i_xPart.get()); + i_rImpl.m_xManifest->removeStatements(i_xPart.get(), + getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), 0); + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii("removeFile: exception"), + 0, uno::makeAny(e)); + } +} + +static ::std::vector< uno::Reference< rdf::XURI > > +getAllParts(struct DocumentMetadataAccess_Impl & i_rImpl) +{ + ::std::vector< uno::Reference< rdf::XURI > > ret; + try { + const uno::Reference<container::XEnumeration> xEnum( + i_rImpl.m_xManifest->getStatements( i_rImpl.m_xBaseURI.get(), + getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext), 0), + uno::UNO_SET_THROW); + while (xEnum->hasMoreElements()) { + rdf::Statement stmt; + if (!(xEnum->nextElement() >>= stmt)) { + throw uno::RuntimeException(); + } + const uno::Reference<rdf::XURI> xPart(stmt.Object, + uno::UNO_QUERY); + if (!xPart.is()) continue; + ret.push_back(xPart); + } + return ret; + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii("getAllParts: exception"), + 0, uno::makeAny(e)); + } +} + +static bool +isPartOfType(struct DocumentMetadataAccess_Impl & i_rImpl, + uno::Reference<rdf::XURI> const & i_xPart, + uno::Reference<rdf::XURI> const & i_xType) +{ + if (!i_xPart.is() || !i_xType.is()) throw uno::RuntimeException(); + try { + const uno::Reference<container::XEnumeration> xEnum( + i_rImpl.m_xManifest->getStatements(i_xPart.get(), + getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), + i_xType.get()), + uno::UNO_SET_THROW); + return (xEnum->hasMoreElements()); + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii("isPartOfType: exception"), + 0, uno::makeAny(e)); + } +} + +//////////////////////////////////////////////////////////////////////////// + +static ucb::InteractiveAugmentedIOException +mkException( ::rtl::OUString const & i_rMessage, + ucb::IOErrorCode const i_ErrorCode, + ::rtl::OUString const & i_rUri, ::rtl::OUString const & i_rResource) +{ + ucb::InteractiveAugmentedIOException iaioe; + iaioe.Message = i_rMessage; + iaioe.Classification = task::InteractionClassification_ERROR; + iaioe.Code = i_ErrorCode; + + const beans::PropertyValue uriProp(::rtl::OUString::createFromAscii("Uri"), + -1, uno::makeAny(i_rUri), static_cast<beans::PropertyState>(0)); + const beans::PropertyValue rnProp( + ::rtl::OUString::createFromAscii("ResourceName"), + -1, uno::makeAny(i_rResource), static_cast<beans::PropertyState>(0)); + iaioe.Arguments = ::comphelper::makeSequence( + uno::makeAny(uriProp), uno::makeAny(rnProp)); + return iaioe; +} + +/** error handling policy. + <p>If a handler is given, ask it how to proceed: + <ul><li>(default:) cancel import, raise exception</li> + <li>ignore the error and continue</li> + <li>retry the action that led to the error</li></ul></p> + N.B.: must not be called before DMA is fully initalized! + @returns true iff caller should retry + */ +static bool +handleError( ucb::InteractiveAugmentedIOException const & i_rException, + const uno::Reference<task::XInteractionHandler> & i_xHandler) +{ + if (!i_xHandler.is()) { + throw lang::WrappedTargetException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: exception"), + /* *this*/ 0, uno::makeAny(i_rException)); + } + + ::rtl::Reference< ::comphelper::OInteractionRequest > pRequest( + new ::comphelper::OInteractionRequest(uno::makeAny(i_rException)) ); + ::rtl::Reference< ::comphelper::OInteractionRetry > pRetry( + new ::comphelper::OInteractionRetry ); + ::rtl::Reference< ::comphelper::OInteractionApprove > pApprove( + new ::comphelper::OInteractionApprove ); + ::rtl::Reference< ::comphelper::OInteractionAbort > pAbort( + new ::comphelper::OInteractionAbort ); + /* this does not seem to work + if (i_rException.Code != ucb::IOErrorCode_WRONG_FORMAT) { + pRequest->addContinuation( pRetry.get() ); + } + */ + pRequest->addContinuation( pApprove.get() ); + pRequest->addContinuation( pAbort.get() ); + // actually call the handler + i_xHandler->handle( pRequest.get() ); + if (pRetry->wasSelected()) { + return true; + } else if (pApprove->wasSelected()) { + return false; + } else { + OSL_ENSURE(pAbort->wasSelected(), "no continuation selected?"); + throw lang::WrappedTargetException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: exception"), + /* *this*/ 0, uno::makeAny(i_rException)); + } +} + +/** check if storage has content.xml/styles.xml; + e.g. ODB files seem to only have content.xml */ +static void +collectFilesFromStorage(uno::Reference<embed::XStorage> const& i_xStorage, + ::rtl::OUString i_Path, + std::set< ::rtl::OUString > & o_rFiles) +{ + static ::rtl::OUString content(::rtl::OUString::createFromAscii(s_content)); + static ::rtl::OUString styles (::rtl::OUString::createFromAscii(s_styles )); + try { + if (i_xStorage->hasByName(content) && + i_xStorage->isStreamElement(content)) + { + o_rFiles.insert(i_Path + content); + } + if (i_xStorage->hasByName(styles) && + i_xStorage->isStreamElement(styles)) + { + o_rFiles.insert(i_Path + styles); + } + } catch (uno::Exception &) { + OSL_TRACE("collectFilesFromStorage: exception?"); + } +} + +/** import a metadata file into repository */ +static void +readStream(struct DocumentMetadataAccess_Impl & i_rImpl, + uno::Reference< embed::XStorage > const & i_xStorage, + ::rtl::OUString const & i_rPath, + ::rtl::OUString const & i_rBaseURI) +{ + ::rtl::OUString dir; + ::rtl::OUString rest; + try { + if (!splitPath(i_rPath, dir, rest)) throw uno::RuntimeException(); + if (dir.equalsAscii("")) { + if (i_xStorage->isStreamElement(i_rPath)) { + const uno::Reference<io::XStream> xStream( + i_xStorage->openStreamElement(i_rPath, + embed::ElementModes::READ), uno::UNO_SET_THROW); + const uno::Reference<io::XInputStream> xInStream( + xStream->getInputStream(), uno::UNO_SET_THROW ); + const uno::Reference<rdf::XURI> xBaseURI( + rdf::URI::create(i_rImpl.m_xContext, i_rBaseURI)); + const uno::Reference<rdf::XURI> xURI( + rdf::URI::createNS(i_rImpl.m_xContext, + i_rBaseURI, i_rPath)); + i_rImpl.m_xRepository->importGraph(rdf::FileFormat::RDF_XML, + xInStream, xURI, xBaseURI); + } else { + throw mkException(::rtl::OUString::createFromAscii( + "readStream: is not a stream"), + ucb::IOErrorCode_NO_FILE, i_rBaseURI + i_rPath, i_rPath); + } + } else { + if (i_xStorage->isStorageElement(dir)) { + const uno::Reference<embed::XStorage> xDir( + i_xStorage->openStorageElement(dir, + embed::ElementModes::READ)); + const uno::Reference< beans::XPropertySet > xDirProps(xDir, + uno::UNO_QUERY_THROW); + try { + ::rtl::OUString mimeType; + xDirProps->getPropertyValue( + ::comphelper::MediaDescriptor::PROP_MEDIATYPE() ) + >>= mimeType; + if (mimeType.matchAsciiL(s_odfmime, sizeof(s_odfmime) - 1)) + { + OSL_TRACE("readStream: " + "refusing to recurse into embedded document"); + return; + } + } catch (uno::Exception &) { } + ::rtl::OUStringBuffer buf(i_rBaseURI); + buf.append(dir).append(static_cast<sal_Unicode>('/')); + readStream(i_rImpl, xDir, rest, buf.makeStringAndClear() ); + } else { + throw mkException(::rtl::OUString::createFromAscii( + "readStream: is not a directory"), + ucb::IOErrorCode_NO_DIRECTORY, i_rBaseURI + dir, dir); + } + } + } catch (container::NoSuchElementException & e) { + throw mkException(e.Message, ucb::IOErrorCode_NOT_EXISTING_PATH, + i_rBaseURI + i_rPath, i_rPath); + } catch (io::IOException & e) { + throw mkException(e.Message, ucb::IOErrorCode_CANT_READ, + i_rBaseURI + i_rPath, i_rPath); + } catch (rdf::ParseException & e) { + throw mkException(e.Message, ucb::IOErrorCode_WRONG_FORMAT, + i_rBaseURI + i_rPath, i_rPath); + } +} + +/** import a metadata file into repository */ +static void +importFile(struct DocumentMetadataAccess_Impl & i_rImpl, + uno::Reference<embed::XStorage> const & i_xStorage, + ::rtl::OUString const & i_rBaseURI, + uno::Reference<task::XInteractionHandler> const & i_xHandler, + ::rtl::OUString i_rPath) +{ +retry: + try { + readStream(i_rImpl, i_xStorage, i_rPath, i_rBaseURI); + } catch (ucb::InteractiveAugmentedIOException & e) { + if (handleError(e, i_xHandler)) goto retry; + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii("importFile: exception"), + 0, uno::makeAny(e)); + } +} + +/** actually write a metadata file to the storage */ +static void +exportStream(struct DocumentMetadataAccess_Impl & i_rImpl, + uno::Reference< embed::XStorage > const & i_xStorage, + uno::Reference<rdf::XURI> const & i_xGraphName, + ::rtl::OUString const & i_rFileName, + ::rtl::OUString const & i_rBaseURI) +{ + const uno::Reference<io::XStream> xStream( + i_xStorage->openStreamElement(i_rFileName, + embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE), + uno::UNO_SET_THROW); + const uno::Reference< beans::XPropertySet > xStreamProps(xStream, + uno::UNO_QUERY); + if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage + xStreamProps->setPropertyValue( + ::rtl::OUString::createFromAscii("MediaType"), + uno::makeAny(::rtl::OUString::createFromAscii(s_rdfxml))); + } + const uno::Reference<io::XOutputStream> xOutStream( + xStream->getOutputStream(), uno::UNO_SET_THROW ); + const uno::Reference<rdf::XURI> xBaseURI( + rdf::URI::create(i_rImpl.m_xContext, i_rBaseURI)); + i_rImpl.m_xRepository->exportGraph(rdf::FileFormat::RDF_XML, + xOutStream, i_xGraphName, xBaseURI); +} + +/** write a metadata file to the storage */ +static void +writeStream(struct DocumentMetadataAccess_Impl & i_rImpl, + uno::Reference< embed::XStorage > const & i_xStorage, + uno::Reference<rdf::XURI> const & i_xGraphName, + ::rtl::OUString const & i_rPath, + ::rtl::OUString const & i_rBaseURI) +{ + ::rtl::OUString dir; + ::rtl::OUString rest; + if (!splitPath(i_rPath, dir, rest)) throw uno::RuntimeException(); + try { + if (dir.equalsAscii("")) { + exportStream(i_rImpl, i_xStorage, i_xGraphName, i_rPath, + i_rBaseURI); + } else { + const uno::Reference<embed::XStorage> xDir( + i_xStorage->openStorageElement(dir, + embed::ElementModes::WRITE)); + const uno::Reference< beans::XPropertySet > xDirProps(xDir, + uno::UNO_QUERY_THROW); + try { + ::rtl::OUString mimeType; + xDirProps->getPropertyValue( + ::comphelper::MediaDescriptor::PROP_MEDIATYPE() ) + >>= mimeType; + if (mimeType.matchAsciiL(s_odfmime, sizeof(s_odfmime) - 1)) { + OSL_TRACE("writeStream: " + "refusing to recurse into embedded document"); + return; + } + } catch (uno::Exception &) { } + ::rtl::OUStringBuffer buf(i_rBaseURI); + buf.append(dir).append(static_cast<sal_Unicode>('/')); + writeStream(i_rImpl, xDir, i_xGraphName, rest, + buf.makeStringAndClear()); + } + const uno::Reference<embed::XTransactedObject> xTransaction( + i_xStorage, uno::UNO_QUERY); + if (xTransaction.is()) { + xTransaction->commit(); + } + } catch (uno::RuntimeException &) { + throw; + } catch (io::IOException &) { + throw; + } +} + +static void +initLoading(struct DocumentMetadataAccess_Impl & i_rImpl, + const uno::Reference< embed::XStorage > & i_xStorage, + const uno::Reference<rdf::XURI> & i_xBaseURI, + const uno::Reference<task::XInteractionHandler> & i_xHandler) +{ +retry: + // clear old data + i_rImpl.m_xManifest.clear(); + // init BaseURI + i_rImpl.m_xBaseURI = i_xBaseURI; + + // create repository + i_rImpl.m_xRepository.clear(); + i_rImpl.m_xRepository.set(rdf::Repository::create(i_rImpl.m_xContext), + uno::UNO_SET_THROW); + + const ::rtl::OUString manifest ( + ::rtl::OUString::createFromAscii(s_manifest)); + const ::rtl::OUString baseURI( i_xBaseURI->getStringValue() ); + // try to delay raising errors until after initialization is done + uno::Any rterr; + ucb::InteractiveAugmentedIOException iaioe; + bool err(false); + + const uno::Reference <rdf::XURI> xManifest( + getURIForStream(i_rImpl, manifest)); + try { + readStream(i_rImpl, i_xStorage, manifest, baseURI); + } catch (ucb::InteractiveAugmentedIOException & e) { + // no manifest.rdf: this is not an error in ODF < 1.2 + if (!(ucb::IOErrorCode_NOT_EXISTING_PATH == e.Code)) { + iaioe = e; + err = true; + } + } catch (uno::Exception & e) { + rterr <<= e; + } + + // init manifest graph + const uno::Reference<rdf::XNamedGraph> xManifestGraph( + i_rImpl.m_xRepository->getGraph(xManifest)); + i_rImpl.m_xManifest.set(xManifestGraph.is() ? xManifestGraph : + i_rImpl.m_xRepository->createGraph(xManifest), uno::UNO_SET_THROW); + const uno::Reference<container::XEnumeration> xEnum( + i_rImpl.m_xManifest->getStatements(0, + getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), + getURI<rdf::URIs::PKG_DOCUMENT>(i_rImpl.m_xContext).get())); + + // document statement + i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI.get(), + getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), + getURI<rdf::URIs::PKG_DOCUMENT>(i_rImpl.m_xContext).get()); + + OSL_ENSURE(i_rImpl.m_xBaseURI.is(), "base URI is null"); + OSL_ENSURE(i_rImpl.m_xRepository.is(), "repository is null"); + OSL_ENSURE(i_rImpl.m_xManifest.is(), "manifest is null"); + + if (rterr.hasValue()) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: " + "exception"), 0, rterr); + } + + if (err) { + if (handleError(iaioe, i_xHandler)) goto retry; + } +} + +/** init Impl struct */ +static void init(struct DocumentMetadataAccess_Impl & i_rImpl) +{ + try { + + i_rImpl.m_xManifest.set(i_rImpl.m_xRepository->createGraph( + getURIForStream(i_rImpl, + ::rtl::OUString::createFromAscii(s_manifest))), + uno::UNO_SET_THROW); + + // insert the document statement + i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI.get(), + getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), + getURI<rdf::URIs::PKG_DOCUMENT>(i_rImpl.m_xContext).get()); + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii("init: unexpected exception"), 0, + uno::makeAny(e)); + } + + // add top-level content files + if (!addContentOrStylesFileImpl(i_rImpl, + ::rtl::OUString::createFromAscii(s_content))) { + throw uno::RuntimeException(); + } + if (!addContentOrStylesFileImpl(i_rImpl, + ::rtl::OUString::createFromAscii(s_styles))) { + throw uno::RuntimeException(); + } +} + + +//////////////////////////////////////////////////////////////////////////// + +DocumentMetadataAccess::DocumentMetadataAccess( + uno::Reference< uno::XComponentContext > const & i_xContext, + const IXmlIdRegistrySupplier & i_rRegistrySupplier) + : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext, i_rRegistrySupplier)) +{ + // no initalization: must call loadFrom... +} + +DocumentMetadataAccess::DocumentMetadataAccess( + uno::Reference< uno::XComponentContext > const & i_xContext, + const IXmlIdRegistrySupplier & i_rRegistrySupplier, + ::rtl::OUString const & i_rURI) + : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext, i_rRegistrySupplier)) +{ + OSL_ENSURE(i_rURI.getLength(), "DMA::DMA: no URI given!"); + OSL_ENSURE(i_rURI.endsWithAsciiL("/", 1), "DMA::DMA: URI without / given!"); + if (!i_rURI.endsWithAsciiL("/", 1)) throw uno::RuntimeException(); + m_pImpl->m_xBaseURI.set(rdf::URI::create(m_pImpl->m_xContext, i_rURI)); + m_pImpl->m_xRepository.set(rdf::Repository::create(m_pImpl->m_xContext), + uno::UNO_SET_THROW); + + // init repository + init(*m_pImpl); + + OSL_ENSURE(m_pImpl->m_xBaseURI.is(), "base URI is null"); + OSL_ENSURE(m_pImpl->m_xRepository.is(), "repository is null"); + OSL_ENSURE(m_pImpl->m_xManifest.is(), "manifest is null"); +} + +DocumentMetadataAccess::~DocumentMetadataAccess() +{ +} + + +// ::com::sun::star::rdf::XRepositorySupplier: +uno::Reference< rdf::XRepository > SAL_CALL +DocumentMetadataAccess::getRDFRepository() throw (uno::RuntimeException) +{ + OSL_ENSURE(m_pImpl->m_xRepository.is(), "repository not initialized"); + return m_pImpl->m_xRepository; +} + +// ::com::sun::star::rdf::XNode: +::rtl::OUString SAL_CALL +DocumentMetadataAccess::getStringValue() throw (uno::RuntimeException) +{ + return m_pImpl->m_xBaseURI->getStringValue(); +} + +// ::com::sun::star::rdf::XURI: +::rtl::OUString SAL_CALL +DocumentMetadataAccess::getNamespace() throw (uno::RuntimeException) +{ + return m_pImpl->m_xBaseURI->getNamespace(); +} + +::rtl::OUString SAL_CALL +DocumentMetadataAccess::getLocalName() throw (uno::RuntimeException) +{ + return m_pImpl->m_xBaseURI->getLocalName(); +} + +// ::com::sun::star::rdf::XDocumentMetadataAccess: +uno::Reference< rdf::XMetadatable > SAL_CALL +DocumentMetadataAccess::getElementByMetadataReference( + const ::com::sun::star::beans::StringPair & i_rReference) +throw (uno::RuntimeException) +{ + const IXmlIdRegistry * pReg( + m_pImpl->m_rXmlIdRegistrySupplier.GetXmlIdRegistry() ); + if (!pReg) { + throw uno::RuntimeException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::getElementByXmlId: no registry"), *this); + } + return pReg->GetElementByMetadataReference(i_rReference); +} + +uno::Reference< rdf::XMetadatable > SAL_CALL +DocumentMetadataAccess::getElementByURI( + const uno::Reference< rdf::XURI > & i_xURI ) +throw (uno::RuntimeException, lang::IllegalArgumentException) +{ + if (!i_xURI.is()) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::getElementByURI: URI is null"), *this, 0); + } + + const ::rtl::OUString baseURI( m_pImpl->m_xBaseURI->getStringValue() ); + const ::rtl::OUString name( i_xURI->getStringValue() ); + if (!name.match(baseURI)) { + return 0; + } + const ::rtl::OUString relName( name.copy(baseURI.getLength()) ); + ::rtl::OUString path; + ::rtl::OUString idref; + if (!splitXmlId(relName, path, idref)) { + return 0; + } + + return getElementByMetadataReference( beans::StringPair(path, idref) ); +} + + +uno::Sequence< uno::Reference< rdf::XURI > > SAL_CALL +DocumentMetadataAccess::getMetadataGraphsWithType( + const uno::Reference<rdf::XURI> & i_xType) +throw (uno::RuntimeException, lang::IllegalArgumentException) +{ + if (!i_xType.is()) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::getMetadataGraphsWithType: " + "type is null"), *this, 0); + } + + ::comphelper::SequenceAsVector< uno::Reference< rdf::XURI > > ret; + const ::std::vector< uno::Reference< rdf::XURI > > parts( + getAllParts(*m_pImpl) ); + ::std::remove_copy_if(parts.begin(), parts.end(), + ::std::back_inserter(ret), + ::boost::bind( + ::std::logical_not<bool>(), + ::boost::bind(&isPartOfType, ::boost::ref(*m_pImpl), _1, i_xType) )); + return ret.getAsConstList(); +} + +uno::Reference<rdf::XURI> SAL_CALL +DocumentMetadataAccess::addMetadataFile(const ::rtl::OUString & i_rFileName, + const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::ElementExistException) +{ + if (!isFileNameValid(i_rFileName)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::addMetadataFile: invalid FileName"), + *this, 0); + } + if (isReservedFile(i_rFileName)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::addMetadataFile:" + "invalid FileName: reserved"), *this, 0); + } + for (sal_Int32 i = 0; i < i_rTypes.getLength(); ++i) { + if (!i_rTypes[i].is()) { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::addMetadataFile: " + "null type"), *this, 2); + } + } + + const uno::Reference<rdf::XURI> xGraphName( + getURIForStream(*m_pImpl, i_rFileName) ); + + try { + m_pImpl->m_xRepository->createGraph(xGraphName); + } catch (rdf::RepositoryException & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::addMetadataFile: exception"), + *this, uno::makeAny(e)); + // note: all other exceptions are propagated + } + + addMetadataFileImpl(*m_pImpl, i_rFileName, i_rTypes); + return xGraphName; +} + +uno::Reference<rdf::XURI> SAL_CALL +DocumentMetadataAccess::importMetadataFile(::sal_Int16 i_Format, + const uno::Reference< io::XInputStream > & i_xInStream, + const ::rtl::OUString & i_rFileName, + const uno::Reference< rdf::XURI > & i_xBaseURI, + const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes) +throw (uno::RuntimeException, lang::IllegalArgumentException, + datatransfer::UnsupportedFlavorException, + container::ElementExistException, rdf::ParseException, io::IOException) +{ + if (!isFileNameValid(i_rFileName)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::importMetadataFile: invalid FileName"), + *this, 0); + } + if (isReservedFile(i_rFileName)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::importMetadataFile:" + "invalid FileName: reserved"), *this, 0); + } + for (sal_Int32 i = 0; i < i_rTypes.getLength(); ++i) { + if (!i_rTypes[i].is()) { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::importMetadataFile: null type"), + *this, 5); + } + } + + const uno::Reference<rdf::XURI> xGraphName( + getURIForStream(*m_pImpl, i_rFileName) ); + + try { + m_pImpl->m_xRepository->importGraph( + i_Format, i_xInStream, xGraphName, i_xBaseURI); + } catch (rdf::RepositoryException & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::importMetadataFile: " + "RepositoryException"), *this, uno::makeAny(e)); + // note: all other exceptions are propagated + } + + // add to manifest + addMetadataFileImpl(*m_pImpl, i_rFileName, i_rTypes); + return xGraphName; +} + +void SAL_CALL +DocumentMetadataAccess::removeMetadataFile( + const uno::Reference< rdf::XURI > & i_xGraphName) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::NoSuchElementException) +{ + try { + m_pImpl->m_xRepository->destroyGraph(i_xGraphName); + } catch (rdf::RepositoryException & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::removeMetadataFile: " + "RepositoryException"), *this, uno::makeAny(e)); + // note: all other exceptions are propagated + } + + // remove file from manifest + removeFile(*m_pImpl, i_xGraphName.get()); +} + +void SAL_CALL +DocumentMetadataAccess::addContentOrStylesFile( + const ::rtl::OUString & i_rFileName) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::ElementExistException) +{ + if (!isFileNameValid(i_rFileName)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::addContentOrStylesFile: " + "invalid FileName"), *this, 0); + } + + if (!addContentOrStylesFileImpl(*m_pImpl, i_rFileName)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::addContentOrStylesFile: " + "invalid FileName: must end with content.xml or styles.xml"), + *this, 0); + } +} + +void SAL_CALL +DocumentMetadataAccess::removeContentOrStylesFile( + const ::rtl::OUString & i_rFileName) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::NoSuchElementException) +{ + if (!isFileNameValid(i_rFileName)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::removeContentOrStylesFile: " + "invalid FileName"), *this, 0); + } + + try { + const uno::Reference<rdf::XURI> xPart( + getURIForStream(*m_pImpl, i_rFileName) ); + const uno::Reference<container::XEnumeration> xEnum( + m_pImpl->m_xManifest->getStatements( m_pImpl->m_xBaseURI.get(), + getURI<rdf::URIs::PKG_HASPART>(m_pImpl->m_xContext), + xPart.get()), + uno::UNO_SET_THROW); + if (!xEnum->hasMoreElements()) { + throw container::NoSuchElementException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::removeContentOrStylesFile: " + "cannot find stream in manifest graph: ") + i_rFileName, + *this); + } + + // remove file from manifest + removeFile(*m_pImpl, xPart); + + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::removeContentOrStylesFile: exception"), + *this, uno::makeAny(e)); + } +} + +void SAL_CALL DocumentMetadataAccess::loadMetadataFromStorage( + const uno::Reference< embed::XStorage > & i_xStorage, + const uno::Reference<rdf::XURI> & i_xBaseURI, + const uno::Reference<task::XInteractionHandler> & i_xHandler) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + if (!i_xStorage.is()) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: " + "storage is null"), *this, 0); + } + if (!i_xBaseURI.is()) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: " + "base URI is null"), *this, 1); + } + const ::rtl::OUString baseURI( i_xBaseURI->getStringValue()); + if (baseURI.indexOf('#') >= 0) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: " + "base URI not absolute"), *this, 1); + } + if (!baseURI.getLength() || !baseURI.endsWithAsciiL("/", 1)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: " + "base URI does not end with slash"), *this, 1); + } + + initLoading(*m_pImpl, i_xStorage, i_xBaseURI, i_xHandler); + + std::set< ::rtl::OUString > StgFiles; + collectFilesFromStorage(i_xStorage, + ::rtl::OUString::createFromAscii(""), StgFiles); + + std::vector< ::rtl::OUString > MfstMetadataFiles; + + try { + const ::std::vector< uno::Reference< rdf::XURI > > parts( + getAllParts(*m_pImpl) ); + const uno::Reference<rdf::XURI> xContentFile( + getURI<rdf::URIs::ODF_CONTENTFILE>(m_pImpl->m_xContext)); + const uno::Reference<rdf::XURI> xStylesFile( + getURI<rdf::URIs::ODF_STYLESFILE>(m_pImpl->m_xContext)); + const uno::Reference<rdf::XURI> xMetadataFile( + getURI<rdf::URIs::PKG_METADATAFILE>(m_pImpl->m_xContext)); + const sal_Int32 len( baseURI.getLength() ); + const ::rtl::OUString manifest ( + ::rtl::OUString::createFromAscii(s_manifest)); + for (::std::vector< uno::Reference< rdf::XURI > >::const_iterator it + = parts.begin(); + it != parts.end(); ++it) { + const ::rtl::OUString name((*it)->getStringValue()); + if (!name.match(baseURI)) { + OSL_TRACE("loadMetadataFromStorage: graph not in document: %s", + ::rtl::OUStringToOString(name, RTL_TEXTENCODING_UTF8) + .getStr()); + continue; + } + const ::rtl::OUString relName( name.copy(len) ); + if (relName == manifest) { + OSL_TRACE("loadMetadataFromStorage: " + "found ourselves a recursive manifest!"); + continue; + } + // remove found items from StgFiles + StgFiles.erase(relName); + if (isContentFile(relName)) { + if (!isPartOfType(*m_pImpl, *it, xContentFile)) { + const uno::Reference <rdf::XURI> xName( + getURIForStream(*m_pImpl, relName) ); + // add missing type statement + m_pImpl->m_xManifest->addStatement(xName.get(), + getURI<rdf::URIs::RDF_TYPE>(m_pImpl->m_xContext), + xContentFile.get()); + } + } else if (isStylesFile(relName)) { + if (!isPartOfType(*m_pImpl, *it, xStylesFile)) { + const uno::Reference <rdf::XURI> xName( + getURIForStream(*m_pImpl, relName) ); + // add missing type statement + m_pImpl->m_xManifest->addStatement(xName.get(), + getURI<rdf::URIs::RDF_TYPE>(m_pImpl->m_xContext), + xStylesFile.get()); + } + } else if (isReservedFile(relName)) { + OSL_TRACE("loadMetadataFromStorage: " + "reserved file name in manifest"); + } else { + if (isPartOfType(*m_pImpl, *it, xMetadataFile)) { + MfstMetadataFiles.push_back(relName); + } + // do not add statement for MetadataFile; it could be + // something else! just ignore it... + } + } + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: " + "exception"), *this, uno::makeAny(e)); + } + + std::for_each(StgFiles.begin(), StgFiles.end(), + boost::bind(addContentOrStylesFileImpl, boost::ref(*m_pImpl), _1)); + + std::for_each(MfstMetadataFiles.begin(), MfstMetadataFiles.end(), + boost::bind(importFile, boost::ref(*m_pImpl), + i_xStorage, baseURI, i_xHandler, _1)); +} + +void SAL_CALL DocumentMetadataAccess::storeMetadataToStorage( + const uno::Reference< embed::XStorage > & i_xStorage) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + if (!i_xStorage.is()) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::storeMetadataToStorage: " + "storage is null"), *this, 0); + } + + // export manifest + const ::rtl::OUString manifest ( + ::rtl::OUString::createFromAscii(s_manifest)); + const uno::Reference <rdf::XURI> xManifest( + getURIForStream(*m_pImpl, manifest) ); + const ::rtl::OUString baseURI( m_pImpl->m_xBaseURI->getStringValue() ); + try { + writeStream(*m_pImpl, i_xStorage, xManifest, manifest, baseURI); + } catch (uno::RuntimeException &) { + throw; + } catch (io::IOException & e) { + throw lang::WrappedTargetException( ::rtl::OUString::createFromAscii( + "storeMetadataToStorage: IO exception"), *this, uno::makeAny(e)); + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "storeMetadataToStorage: exception"), *this, uno::makeAny(e)); + } + + // export metadata streams + try { + const uno::Sequence<uno::Reference<rdf::XURI> > graphs( + m_pImpl->m_xRepository->getGraphNames()); + const sal_Int32 len( baseURI.getLength() ); + for (sal_Int32 i = 0; i < graphs.getLength(); ++i) { + const uno::Reference<rdf::XURI> xName(graphs[i]); + const ::rtl::OUString name(xName->getStringValue()); + if (!name.match(baseURI)) { + OSL_TRACE("storeMetadataToStorage: graph not in document: %s", + ::rtl::OUStringToOString(name, RTL_TEXTENCODING_UTF8) + .getStr()); + continue; + } + const ::rtl::OUString relName( name.copy(len) ); + if (relName == manifest) { + continue; + } + if (!isFileNameValid(relName) || isReservedFile(relName)) { + OSL_TRACE("storeMetadataToStorage: invalid file name: %s", + ::rtl::OUStringToOString(relName, RTL_TEXTENCODING_UTF8) + .getStr()); + continue; + } + try { + writeStream(*m_pImpl, i_xStorage, xName, relName, baseURI); + } catch (uno::RuntimeException &) { + throw; + } catch (io::IOException & e) { + throw lang::WrappedTargetException( + ::rtl::OUString::createFromAscii( + "storeMetadataToStorage: IO exception"), + *this, uno::makeAny(e)); + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "storeMetadataToStorage: exception"), + *this, uno::makeAny(e)); + } + } + } catch (rdf::RepositoryException & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "storeMetadataToStorage: exception"), *this, uno::makeAny(e)); + } +} + +void SAL_CALL +DocumentMetadataAccess::loadMetadataFromMedium( + const uno::Sequence< beans::PropertyValue > & i_rMedium) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + uno::Reference<io::XInputStream> xIn; + ::comphelper::MediaDescriptor md(i_rMedium); + ::rtl::OUString URL; + md[ ::comphelper::MediaDescriptor::PROP_URL() ] >>= URL; + ::rtl::OUString BaseURL; + md[ ::comphelper::MediaDescriptor::PROP_DOCUMENTBASEURL() ] >>= BaseURL; + if (md.addInputStream()) { + md[ ::comphelper::MediaDescriptor::PROP_INPUTSTREAM() ] >>= xIn; + } + if (!xIn.is() && URL.equalsAscii("")) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromMedium: " + "inalid medium: no URL, no input stream"), *this, 0); + } + uno::Reference<embed::XStorage> xStorage; + try { + const uno::Reference<lang::XMultiServiceFactory> xMsf ( + m_pImpl->m_xContext->getServiceManager(), uno::UNO_QUERY_THROW); + if (xIn.is()) { + xStorage = ::comphelper::OStorageHelper::GetStorageFromInputStream( + xIn, xMsf); + } else { // fallback to url + xStorage = ::comphelper::OStorageHelper::GetStorageFromURL2( + URL, embed::ElementModes::READ, xMsf); + } + } catch (uno::RuntimeException &) { + throw; + } catch (io::IOException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromMedium: " + "exception"), *this, uno::makeAny(e)); + } + if (!xStorage.is()) { + throw uno::RuntimeException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromMedium: " + "cannot get Storage"), *this); + } + uno::Reference<rdf::XURI> xBaseURI; + try { + xBaseURI = createBaseURI(m_pImpl->m_xContext, xStorage, BaseURL); + } catch (uno::Exception &) { + // fall back to URL + try { + xBaseURI = createBaseURI(m_pImpl->m_xContext, xStorage, URL); + } catch (uno::Exception &) { + OSL_ENSURE(false, "cannot create base URI"); + } + } + uno::Reference<task::XInteractionHandler> xIH; + md[ ::comphelper::MediaDescriptor::PROP_INTERACTIONHANDLER() ] >>= xIH; + loadMetadataFromStorage(xStorage, xBaseURI, xIH); +} + +void SAL_CALL +DocumentMetadataAccess::storeMetadataToMedium( + const uno::Sequence< beans::PropertyValue > & i_rMedium) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + ::comphelper::MediaDescriptor md(i_rMedium); + ::rtl::OUString URL; + md[ ::comphelper::MediaDescriptor::PROP_URL() ] >>= URL; + if (URL.equalsAscii("")) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::storeMetadataToMedium: " + "invalid medium: no URL"), *this, 0); + } + + SfxMedium aMedium(i_rMedium); + uno::Reference<embed::XStorage> xStorage(aMedium.GetOutputStorage()); + + bool sfx(false); + if (xStorage.is()) { + sfx = true; + } else { + const uno::Reference<lang::XMultiServiceFactory> xMsf ( + m_pImpl->m_xContext->getServiceManager(), uno::UNO_QUERY_THROW); + xStorage = ::comphelper::OStorageHelper::GetStorageFromURL2( + URL, embed::ElementModes::WRITE, xMsf); + } + + if (!xStorage.is()) { + throw uno::RuntimeException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::storeMetadataToMedium: " + "cannot get Storage"), *this); + } + // set MIME type of the storage + ::comphelper::MediaDescriptor::const_iterator iter + = md.find(::comphelper::MediaDescriptor::PROP_MEDIATYPE()); + if (iter != md.end()) { + uno::Reference< beans::XPropertySet > xProps(xStorage, + uno::UNO_QUERY_THROW); + try { + // this is NOT supported in FileSystemStorage + xProps->setPropertyValue( + ::comphelper::MediaDescriptor::PROP_MEDIATYPE(), + iter->second); + } catch (uno::Exception &) { } + } + storeMetadataToStorage(xStorage); + + if (sfx) { + const sal_Bool bOk = aMedium.Commit(); + aMedium.Close(); + if ( !bOk ) { + sal_uInt32 nError = aMedium.GetError(); + if ( nError == ERRCODE_NONE ) { + nError = ERRCODE_IO_GENERAL; + } + task::ErrorCodeIOException ex( ::rtl::OUString(), + uno::Reference< uno::XInterface >(), nError); + throw lang::WrappedTargetException(::rtl::OUString(), *this, + uno::makeAny(ex)); + } + } +} + +} // namespace sfx2 + diff --git a/sfx2/source/doc/Metadatable.cxx b/sfx2/source/doc/Metadatable.cxx new file mode 100644 index 000000000000..94c5826569f2 --- /dev/null +++ b/sfx2/source/doc/Metadatable.cxx @@ -0,0 +1,1703 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sfx2.hxx" + +#include <sfx2/Metadatable.hxx> +#include <sfx2/XmlIdRegistry.hxx> + +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> // solarmutex + +#include <rtl/random.h> + +#include <boost/bind.hpp> + +#include <memory> +#include <hash_map> +#include <list> +#include <algorithm> +#if OSL_DEBUG_LEVEL > 0 +#include <typeinfo> +#endif + + +/** XML ID handling. + + There is an abstract base class <type>XmlIdRegistry</type>, with + 2 subclasses <type>XmlIdRegistryDocument</type> for "normal" documents, + and <type>XmlIdRegistryClipboard</type> for clipboard documents. + These classes are responsible for managing XML IDs for all elements + of the model. Only the implementation of the <type>Metadatable</type> + base class needs to know the registries, so they are not in the header. + + The handling of XML IDs differs between clipboard and non-clipboard + documents in several aspects. Most importantly, non-clipboard documents + can have several elements associated with one XML ID. + This is necessary because of the weird undo implementation: + deleting a text node moves the deleted node to the undo array, but + executing undo will then create a <em>copy</em> of that node in the + document array. These 2 nodes must have the same XML ID, because + we cannot know whether the user will do a redo next, or something else. + + Because we need to have a mechanism for several objects per XML ID anyway, + we use that also to enable some usability features: + The document registry has a list of Metadatables per XML ID. + This list is sorted by priority, i.e., the first element has highest + priority. When inserting copies, care must be taken that they are inserted + at the right position: either before or after the source. + This is done by <method>Metadatable::RegisterAsCopyOf</method>. + When a text node is split, then both resulting text nodes are inserted + into the list. If the user then deletes one text node, the other one + will have the XML ID. + Also, when a Metadatable is copied to the clipboard and then pasted, + the copy is inserted into the list. If the user then deletes the source, + the XML ID is not lost. + The goal is that it should be hard to lose an XML ID by accident, which + is especially important as long as we do not have an UI that displays them. + + There are two subclasses of <type>Metadatable</type>: + <ul><li><type>MetadatableClipboard</type>: for copies in the clipboard</li> + <li><type>MetadatableUndo</type>: for undo, because a Metadatable + may be destroyed on delete and a new one created on undo.</li></ul> + These serve only to track the position in an XML ID list in a document + registry, so that future actions can insert objects at the right position. + Unfortunately, inserting dummy objects seems to be necessary: + <ul><li>it is not sufficent to just remember the saved id, because then + the relative priorities might change when executing the undo</li> + <li>it is not sufficient to record the position as an integer, because + if we delete a text node and then undo, the node will be copied(!), + and we will have one more node in the list.<li> + <li>it is not sufficient to record the pointer of the previous/next + Metadatable, because if we delete a text node, undo, and then + do something to clear the redo array, the original text node is + destroyed, and is replaced by the copy created by undo</li></ul> + + If content from a non-clipboard document is copied into a clipboard + document, a dummy <type>MetadatableClipboard</type> is inserted into the + non-clipboard document registry in order to track the position of the + source element. When the clipboard content is pasted back into the source + document, this dummy object is used to associate the pasted element with + that same XML ID. + + If a <type>Metadatable</type> is deleted or merged, + <method>Metadatable::CreateUndo</method> is called, and returns a + <type>MetadatableUndo<type> instance, which can be used to undo the action + by passing it to <method>Metadatable::RestoreMetadata</method>. + + @author mst + */ + + +using namespace ::com::sun::star; + +using ::sfx2::isValidXmlId; + + +namespace sfx2 { + +static const char s_content [] = "content.xml"; +static const char s_styles [] = "styles.xml"; +static const char s_prefix [] = "id"; // prefix for generated xml:id + +static bool isContentFile(::rtl::OUString const & i_rPath) +{ + return i_rPath.equalsAscii(s_content); +} + +static bool isStylesFile (::rtl::OUString const & i_rPath) +{ + return i_rPath.equalsAscii(s_styles); +} + + +//============================================================================= +// XML ID handling --------------------------------------------------- + +/** handles registration of XMetadatable. + + This class is responsible for guaranteeing that XMetadatable objects + always have XML IDs that are unique within a stream. + + This is an abstract base class; see subclasses XmlIdRegistryDocument and + XmlIdRegistryClipboard. + + @see SwDoc::GetXmlIdRegistry + @see SwDocShell::GetXmlIdRegistry + */ +class XmlIdRegistry : public sfx2::IXmlIdRegistry +{ + +public: + XmlIdRegistry(); + + virtual ~XmlIdRegistry(); + + /** get the ODF element with the given metadata reference. */ + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XMetadatable > SAL_CALL + GetElementByMetadataReference( + const ::com::sun::star::beans::StringPair & i_rReference) const; + + /** register an ODF element at a newly generated, unique metadata reference. + + <p> + Find a fresh XML ID, and register it for the element. + The generated ID does not occur in any stream of the document. + </p> + */ + virtual void RegisterMetadatableAndCreateID(Metadatable& i_xObject) = 0; + + /** try to register an ODF element at a given XML ID, or update its + registation to a different XML ID. + + <p> + If the given new metadata reference is not already occupied in the + document, unregister the element at its old metadata reference if + it has one, and register the new metadata reference for the element. + Note that this method only ensures that XML IDs are unique per stream, + so using the same XML ID in both content.xml and styles.xml is allowed. + </p> + + @returns + true iff the element has successfully been registered + */ + virtual bool TryRegisterMetadatable(Metadatable& i_xObject, + ::rtl::OUString const& i_rStreamName, ::rtl::OUString const& i_rIdref) + = 0; + + /** unregister an ODF element. + + <p> + Unregister the element at its metadata reference. + Does not remove the metadata reference from the element. + </p> + + @see RemoveXmlIdForElement + */ + virtual void UnregisterMetadatable(Metadatable const&) = 0; + + /** get the metadata reference for the given element. */ + ::com::sun::star::beans::StringPair + GetXmlIdForElement(Metadatable const&) const; + + /** remove the metadata reference for the given element. */ + virtual void RemoveXmlIdForElement(Metadatable const&) = 0; + +protected: + + virtual bool LookupXmlId(const Metadatable& i_xObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref) const = 0; + + virtual Metadatable* LookupElement(const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const = 0; +}; + +// XmlIdRegistryDocument --------------------------------------------- + +/** non-clipboard documents */ +class XmlIdRegistryDocument : public XmlIdRegistry +{ + +public: + XmlIdRegistryDocument(); + + virtual ~XmlIdRegistryDocument(); + + virtual void RegisterMetadatableAndCreateID(Metadatable& i_xObject); + + virtual bool TryRegisterMetadatable(Metadatable& i_xObject, + ::rtl::OUString const& i_rStreamName, ::rtl::OUString const& i_rIdref); + + virtual void UnregisterMetadatable(Metadatable const&); + + virtual void RemoveXmlIdForElement(Metadatable const&); + + /** register i_rCopy as a copy of i_rSource, + with precedence iff i_bCopyPrecedesSource is true */ + void RegisterCopy(Metadatable const& i_rSource, Metadatable & i_rCopy, + const bool i_bCopyPrecedesSource); + + /** create a Undo Metadatable for i_rObject. */ + ::boost::shared_ptr<MetadatableUndo> CreateUndo( + Metadatable const& i_rObject); + + /** merge i_rMerged and i_rOther into i_rMerged. */ + void JoinMetadatables(Metadatable & i_rMerged, Metadatable const& i_rOther); + + // unfortunately public, Metadatable::RegisterAsCopyOf needs this + virtual bool LookupXmlId(const Metadatable& i_xObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref) const; + +private: + + virtual Metadatable* LookupElement(const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const; + + struct XmlIdRegistry_Impl; + ::std::auto_ptr<XmlIdRegistry_Impl> m_pImpl; +}; + +// MetadatableUndo --------------------------------------------------- + +/** the horrible Undo Metadatable: is inserted into lists to track position */ +class MetadatableUndo : public Metadatable +{ + /// as determined by the stream of the source in original document + const bool m_isInContent; +public: + MetadatableUndo(const bool i_isInContent) + : m_isInContent(i_isInContent) { } + virtual ::sfx2::XmlIdRegistry& GetRegistry() + { + // N.B. for Undo, m_pReg is initialized by registering this as copy in + // CreateUndo; it is never cleared + OSL_ENSURE(m_pReg, "no m_pReg in MetadatableUndo ?"); + return *m_pReg; + } + virtual bool IsInClipboard() const { return false; } + virtual bool IsInUndo() const { return true; } + virtual bool IsInContent() const { return m_isInContent; } + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XMetadatable > MakeUnoObject() + { OSL_ENSURE(false, "MetadatableUndo::MakeUnoObject"); throw; } +}; + +// MetadatableClipboard ---------------------------------------------- + +/** the horrible Clipboard Metadatable: inserted into lists to track position */ +class MetadatableClipboard : public Metadatable +{ + /// as determined by the stream of the source in original document + const bool m_isInContent; +public: + MetadatableClipboard(const bool i_isInContent) + : m_isInContent(i_isInContent) { } + virtual ::sfx2::XmlIdRegistry& GetRegistry() + { + // N.B. for Clipboard, m_pReg is initialized by registering this as copy in + // RegisterAsCopyOf; it is only cleared by OriginNoLongerInBusinessAnymore + OSL_ENSURE(m_pReg, "no m_pReg in MetadatableClipboard ?"); + return *m_pReg; + } + virtual bool IsInClipboard() const { return true; } + virtual bool IsInUndo() const { return false; } + virtual bool IsInContent() const { return m_isInContent; } + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XMetadatable > MakeUnoObject() + { OSL_ENSURE(false, "MetadatableClipboard::MakeUnoObject"); throw; } + void OriginNoLongerInBusinessAnymore() { m_pReg = 0; } +}; + +// XmlIdRegistryClipboard -------------------------------------------- + +class XmlIdRegistryClipboard : public XmlIdRegistry +{ + +public: + XmlIdRegistryClipboard(); + virtual ~XmlIdRegistryClipboard(); + + virtual void RegisterMetadatableAndCreateID(Metadatable& i_xObject); + + virtual bool TryRegisterMetadatable(Metadatable& i_xObject, + ::rtl::OUString const& i_rStreamName, ::rtl::OUString const& i_rIdref); + + virtual void UnregisterMetadatable(Metadatable const&); + + virtual void RemoveXmlIdForElement(Metadatable const&); + + /** register i_rCopy as a copy of i_rSource */ + MetadatableClipboard & RegisterCopyClipboard(Metadatable & i_rCopy, + beans::StringPair const & i_rReference, + const bool i_isLatent); + + /** get the Metadatable that links i_rObject to its origin registry */ + MetadatableClipboard const* SourceLink(Metadatable const& i_rObject); + +private: + virtual bool LookupXmlId(const Metadatable& i_xObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref) const; + + virtual Metadatable* LookupElement(const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const; + + /** create a Clipboard Metadatable for i_rObject. */ + ::boost::shared_ptr<MetadatableClipboard> CreateClipboard( + const bool i_isInContent); + + struct XmlIdRegistry_Impl; + ::std::auto_ptr<XmlIdRegistry_Impl> m_pImpl; +}; + + +//============================================================================= +// XmlIdRegistry + +::sfx2::IXmlIdRegistry * createXmlIdRegistry(const bool i_DocIsClipboard) +{ + return i_DocIsClipboard + ? static_cast<XmlIdRegistry*>( new XmlIdRegistryClipboard ) + : static_cast<XmlIdRegistry*>( new XmlIdRegistryDocument ); +} + +XmlIdRegistry::XmlIdRegistry() +{ +} + +XmlIdRegistry::~XmlIdRegistry() +{ +} + +::com::sun::star::uno::Reference< ::com::sun::star::rdf::XMetadatable > SAL_CALL +XmlIdRegistry::GetElementByMetadataReference( + const beans::StringPair & i_rReference) const +{ + Metadatable* pObject( LookupElement(i_rReference.First, + i_rReference.Second) ); + return pObject ? pObject->MakeUnoObject() : 0; +} + +beans::StringPair +XmlIdRegistry::GetXmlIdForElement(const Metadatable& i_rObject) const +{ + ::rtl::OUString path; + ::rtl::OUString idref; + if (LookupXmlId(i_rObject, path, idref)) + { + if (LookupElement(path, idref) == &i_rObject) + { + return beans::StringPair(path, idref); + } + } + return beans::StringPair(); +} + + +/// generate unique xml:id +template< typename T > +/*static*/ ::rtl::OUString create_id(const + ::std::hash_map< ::rtl::OUString, T, ::rtl::OUStringHash > & i_rXmlIdMap) +{ + static rtlRandomPool s_Pool( rtl_random_createPool() ); + const ::rtl::OUString prefix( ::rtl::OUString::createFromAscii(s_prefix) ); + typename ::std::hash_map< ::rtl::OUString, T, ::rtl::OUStringHash > + ::const_iterator iter; + ::rtl::OUString id; + do + { + sal_Int32 n; + rtl_random_getBytes(s_Pool, & n, sizeof(n)); + id = prefix + ::rtl::OUString::valueOf(static_cast<sal_Int32>(abs(n))); + iter = i_rXmlIdMap.find(id); + } + while (iter != i_rXmlIdMap.end()); + return id; +} + +//============================================================================= +// Document XML ID Registry (_Impl) + +/// element list +typedef ::std::list< Metadatable* > XmlIdList_t; + +/// Idref -> (content.xml element list, styles.xml element list) +typedef ::std::hash_map< ::rtl::OUString, + ::std::pair< XmlIdList_t, XmlIdList_t >, ::rtl::OUStringHash > XmlIdMap_t; + +/// pointer hash template +template<typename T> struct PtrHash +{ + size_t operator() (T const * i_pT) const + { + return reinterpret_cast<size_t>(i_pT); + } +}; + +/// element -> (stream name, idref) +typedef ::std::hash_map< const Metadatable*, + ::std::pair< ::rtl::OUString, ::rtl::OUString>, PtrHash<Metadatable> > + XmlIdReverseMap_t; + +struct XmlIdRegistryDocument::XmlIdRegistry_Impl +{ + XmlIdRegistry_Impl() + : m_XmlIdMap(), m_XmlIdReverseMap() { } + + bool TryInsertMetadatable(Metadatable& i_xObject, + const ::rtl::OUString & i_rStream, const ::rtl::OUString & i_rIdref); + + bool LookupXmlId(const Metadatable& i_xObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref) const; + + Metadatable* LookupElement(const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const; + + const XmlIdList_t * LookupElementList( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const; + + XmlIdList_t * LookupElementList( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) + { + return const_cast<XmlIdList_t*>( + const_cast<const XmlIdRegistry_Impl*>(this) + ->LookupElementList(i_rStreamName, i_rIdref)); + } + + XmlIdMap_t m_XmlIdMap; + XmlIdReverseMap_t m_XmlIdReverseMap; +}; + +// ------------------------------------------------------------------- + +static void +rmIter(XmlIdMap_t & i_rXmlIdMap, XmlIdMap_t::iterator const& i_rIter, + ::rtl::OUString const & i_rStream, Metadatable const& i_rObject) +{ + if (i_rIter != i_rXmlIdMap.end()) + { + XmlIdList_t & rList( isContentFile(i_rStream) + ? i_rIter->second.first : i_rIter->second.second ); + rList.remove(&const_cast<Metadatable&>(i_rObject)); + if (i_rIter->second.first.empty() && i_rIter->second.second.empty()) + { + i_rXmlIdMap.erase(i_rIter); + } + } +} + +// ------------------------------------------------------------------- + +const XmlIdList_t * +XmlIdRegistryDocument::XmlIdRegistry_Impl::LookupElementList( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const +{ + const XmlIdMap_t::const_iterator iter( m_XmlIdMap.find(i_rIdref) ); + if (iter != m_XmlIdMap.end()) + { + OSL_ENSURE(!iter->second.first.empty() || !iter->second.second.empty(), + "null entry in m_XmlIdMap"); + return (isContentFile(i_rStreamName)) + ? &iter->second.first + : &iter->second.second; + } + else + { + return 0; + } +} + +Metadatable* +XmlIdRegistryDocument::XmlIdRegistry_Impl::LookupElement( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const +{ + if (!isValidXmlId(i_rStreamName, i_rIdref)) + { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "illegal XmlId"), 0, 0); + } + + const XmlIdList_t * pList( LookupElementList(i_rStreamName, i_rIdref) ); + if (pList) + { + const XmlIdList_t::const_iterator iter( + ::std::find_if(pList->begin(), pList->end(), + ::boost::bind( + ::std::logical_not<bool>(), + ::boost::bind( + ::std::logical_or<bool>(), + ::boost::bind( &Metadatable::IsInUndo, _1 ), + ::boost::bind( &Metadatable::IsInClipboard, _1 ) + ) ) ) ); + if (iter != pList->end()) + { + return *iter; + } + } + return 0; +} + +bool +XmlIdRegistryDocument::XmlIdRegistry_Impl::LookupXmlId( + const Metadatable& i_rObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref) const +{ + const XmlIdReverseMap_t::const_iterator iter( + m_XmlIdReverseMap.find(&i_rObject) ); + if (iter != m_XmlIdReverseMap.end()) + { + OSL_ENSURE(!iter->second.first.equalsAscii(""), + "null stream in m_XmlIdReverseMap"); + OSL_ENSURE(!iter->second.second.equalsAscii(""), + "null id in m_XmlIdReverseMap"); + o_rStream = iter->second.first; + o_rIdref = iter->second.second; + return true; + } + else + { + return false; + } +} + +bool +XmlIdRegistryDocument::XmlIdRegistry_Impl::TryInsertMetadatable( + Metadatable & i_rObject, + const ::rtl::OUString & i_rStreamName, const ::rtl::OUString & i_rIdref) +{ + const bool bContent( isContentFile(i_rStreamName) ); + OSL_ENSURE(isContentFile(i_rStreamName) || isStylesFile(i_rStreamName), + "invalid stream"); + + XmlIdList_t * pList( LookupElementList(i_rStreamName, i_rIdref) ); + if (pList) + { + if (pList->empty()) + { + pList->push_back( &i_rObject ); + return true; + } + else + { + // this is only called from TryRegister now, so check + // if all elements in the list are deleted (in undo) or + // placeholders, then "steal" the id from them + if ( pList->end() == ::std::find_if(pList->begin(), pList->end(), + ::boost::bind( + ::std::logical_not<bool>(), + ::boost::bind( + ::std::logical_or<bool>(), + ::boost::bind( &Metadatable::IsInUndo, _1 ), + ::boost::bind( &Metadatable::IsInClipboard, _1 ) + ) ) ) ) + { +// ??? this is not undoable +// pList->clear(); +// pList->push_back( &i_rObject ); + pList->push_front( &i_rObject ); + return true; + } + else + { + return false; + } + } + } + else + { + m_XmlIdMap.insert(::std::make_pair(i_rIdref, bContent + ? ::std::make_pair( XmlIdList_t( 1, &i_rObject ), XmlIdList_t() ) + : ::std::make_pair( XmlIdList_t(), XmlIdList_t( 1, &i_rObject ) ))); + return true; + } +} + +//============================================================================= +// Document XML ID Registry + + +XmlIdRegistryDocument::XmlIdRegistryDocument() + : m_pImpl( new XmlIdRegistry_Impl ) +{ +} + +static void +removeLink(Metadatable* i_pObject) +{ + OSL_ENSURE(i_pObject, "null in list ???"); + if (!i_pObject) return; + if (i_pObject->IsInClipboard()) + { + MetadatableClipboard* pLink( + dynamic_cast<MetadatableClipboard*>( i_pObject ) ); + OSL_ENSURE(pLink, "IsInClipboard, but no MetadatableClipboard ?"); + if (pLink) + { + pLink->OriginNoLongerInBusinessAnymore(); + } + } +} + +XmlIdRegistryDocument::~XmlIdRegistryDocument() +{ + // notify all list elements that are actually in the clipboard + for (XmlIdMap_t::iterator iter(m_pImpl->m_XmlIdMap.begin()); + iter != m_pImpl->m_XmlIdMap.end(); ++iter) + { + ::std::for_each(iter->second.first.begin(), iter->second.first.end(), + removeLink); + ::std::for_each(iter->second.second.begin(), iter->second.second.end(), + removeLink); + } +} + +bool +XmlIdRegistryDocument::LookupXmlId( + const Metadatable& i_rObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref) const +{ + return m_pImpl->LookupXmlId(i_rObject, o_rStream, o_rIdref); +} + +Metadatable* +XmlIdRegistryDocument::LookupElement( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const +{ + return m_pImpl->LookupElement(i_rStreamName, i_rIdref); +} + +bool +XmlIdRegistryDocument::TryRegisterMetadatable(Metadatable & i_rObject, + ::rtl::OUString const& i_rStreamName, ::rtl::OUString const& i_rIdref) +{ + OSL_TRACE("TryRegisterMetadatable: %p (%s#%s)\n", &i_rObject, + ::rtl::OUStringToOString(i_rStreamName, RTL_TEXTENCODING_UTF8).getStr(), + ::rtl::OUStringToOString(i_rIdref, RTL_TEXTENCODING_UTF8).getStr()); + + OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject), + "TryRegisterMetadatable called for MetadatableUndo?"); + OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject), + "TryRegisterMetadatable called for MetadatableClipboard?"); + + if (!isValidXmlId(i_rStreamName, i_rIdref)) + { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "illegal XmlId"), 0, 0); + } + if (i_rObject.IsInContent() + ? !isContentFile(i_rStreamName) + : !isStylesFile(i_rStreamName)) + { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "illegal XmlId: wrong stream"), 0, 0); + } + + ::rtl::OUString old_path; + ::rtl::OUString old_idref; + m_pImpl->LookupXmlId(i_rObject, old_path, old_idref); + if (old_path == i_rStreamName && old_idref == i_rIdref) + { + return (m_pImpl->LookupElement(old_path, old_idref) == &i_rObject); + } + XmlIdMap_t::iterator old_id( m_pImpl->m_XmlIdMap.end() ); + if (!old_idref.equalsAscii("")) + { + old_id = m_pImpl->m_XmlIdMap.find(old_idref); + OSL_ENSURE(old_id != m_pImpl->m_XmlIdMap.end(), "old id not found"); + } + if (m_pImpl->TryInsertMetadatable(i_rObject, i_rStreamName, i_rIdref)) + { + rmIter(m_pImpl->m_XmlIdMap, old_id, old_path, i_rObject); + m_pImpl->m_XmlIdReverseMap[&i_rObject] = + ::std::make_pair(i_rStreamName, i_rIdref); + return true; + } + else + { + return false; + } +} + +void +XmlIdRegistryDocument::RegisterMetadatableAndCreateID(Metadatable & i_rObject) +{ + OSL_TRACE("RegisterMetadatableAndCreateID: %p\n", &i_rObject); + + OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject), + "RegisterMetadatableAndCreateID called for MetadatableUndo?"); + OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject), + "RegisterMetadatableAndCreateID called for MetadatableClipboard?"); + + const bool isInContent( i_rObject.IsInContent() ); + const ::rtl::OUString stream( ::rtl::OUString::createFromAscii( + isInContent ? s_content : s_styles ) ); + // check if we have a latent xmlid, and if yes, remove it + ::rtl::OUString old_path; + ::rtl::OUString old_idref; + m_pImpl->LookupXmlId(i_rObject, old_path, old_idref); + + XmlIdMap_t::iterator old_id( m_pImpl->m_XmlIdMap.end() ); + if (!old_idref.equalsAscii("")) + { + old_id = m_pImpl->m_XmlIdMap.find(old_idref); + OSL_ENSURE(old_id != m_pImpl->m_XmlIdMap.end(), "old id not found"); + if (m_pImpl->LookupElement(old_path, old_idref) == &i_rObject) + { + return; + } + else + { + // remove latent xmlid + rmIter(m_pImpl->m_XmlIdMap, old_id, old_path, i_rObject); + } + } + + // create id + const ::rtl::OUString id( create_id(m_pImpl->m_XmlIdMap) ); + OSL_ENSURE(m_pImpl->m_XmlIdMap.find(id) == m_pImpl->m_XmlIdMap.end(), + "created id is in use"); + m_pImpl->m_XmlIdMap.insert(::std::make_pair(id, isInContent + ? ::std::make_pair( XmlIdList_t( 1, &i_rObject ), XmlIdList_t() ) + : ::std::make_pair( XmlIdList_t(), XmlIdList_t( 1, &i_rObject ) ))); + m_pImpl->m_XmlIdReverseMap[&i_rObject] = ::std::make_pair(stream, id); +} + +void XmlIdRegistryDocument::UnregisterMetadatable(const Metadatable& i_rObject) +{ + OSL_TRACE("UnregisterMetadatable: %p\n", &i_rObject); + + ::rtl::OUString path; + ::rtl::OUString idref; + if (!m_pImpl->LookupXmlId(i_rObject, path, idref)) + { + OSL_ENSURE(false, "unregister: no xml id?"); + return; + } + const XmlIdMap_t::iterator iter( m_pImpl->m_XmlIdMap.find(idref) ); + if (iter != m_pImpl->m_XmlIdMap.end()) + { + rmIter(m_pImpl->m_XmlIdMap, iter, path, i_rObject); + } +} + +void XmlIdRegistryDocument::RemoveXmlIdForElement(const Metadatable& i_rObject) +{ + OSL_TRACE("RemoveXmlIdForElement: %p\n", &i_rObject); + + const XmlIdReverseMap_t::iterator iter( + m_pImpl->m_XmlIdReverseMap.find(&i_rObject) ); + if (iter != m_pImpl->m_XmlIdReverseMap.end()) + { + OSL_ENSURE(!iter->second.second.equalsAscii(""), + "null id in m_XmlIdReverseMap"); + m_pImpl->m_XmlIdReverseMap.erase(iter); + } +} + +// ------------------------------------------------------------------- + +void XmlIdRegistryDocument::RegisterCopy(Metadatable const& i_rSource, + Metadatable & i_rCopy, const bool i_bCopyPrecedesSource) +{ + OSL_TRACE("RegisterCopy: %p -> %p (%d)\n", + &i_rSource, &i_rCopy, i_bCopyPrecedesSource); + + // potential sources: clipboard, undo array, splitNode + // assumption: stream change can only happen via clipboard, and is handled + // by Metadatable::RegisterAsCopyOf + OSL_ENSURE(i_rSource.IsInUndo() || i_rCopy.IsInUndo() || + (i_rSource.IsInContent() == i_rCopy.IsInContent()), + "RegisterCopy: not in same stream?"); + + ::rtl::OUString path; + ::rtl::OUString idref; + if (!m_pImpl->LookupXmlId( i_rSource, path, idref )) + { + OSL_ENSURE(false, "no xml id?"); + return; + } + XmlIdList_t * pList ( m_pImpl->LookupElementList(path, idref) ); + OSL_ENSURE( ::std::find( pList->begin(), pList->end(), &i_rCopy ) + == pList->end(), "copy already registered???"); + XmlIdList_t::iterator srcpos( + ::std::find( pList->begin(), pList->end(), &i_rSource ) ); + OSL_ENSURE(srcpos != pList->end(), "source not in list???"); + if (srcpos == pList->end()) + { + return; + } + if (i_bCopyPrecedesSource) + { + pList->insert( srcpos, &i_rCopy ); + } + else + { + // for undo push_back does not work! must insert right after source + pList->insert( ++srcpos, &i_rCopy ); + } + m_pImpl->m_XmlIdReverseMap.insert(::std::make_pair(&i_rCopy, + ::std::make_pair(path, idref))); +} + +::boost::shared_ptr<MetadatableUndo> +XmlIdRegistryDocument::CreateUndo(Metadatable const& i_rObject) +{ + OSL_TRACE("CreateUndo: %p\n", &i_rObject); + + return ::boost::shared_ptr<MetadatableUndo>( + new MetadatableUndo(i_rObject.IsInContent()) ); +} + +/* +i_rMerged is both a source and the target node of the merge +i_rOther is the other source, and will be deleted after the merge + +dimensions: none|latent|actual empty|nonempty +i_rMerged(1) i_rOther(2) result + *|empty *|empty => 1|2 (arbitrary) + *|empty *|nonempty => 2 + *|nonempty *|empty => 1 + none|nonempty none|nonempty => none + none|nonempty latent|nonempty => 2 +latent|nonempty none|nonempty => 1 +latent|nonempty latent|nonempty => 1|2 + *|nonempty actual|nonempty => 2 +actual|nonempty *|nonempty => 1 +actual|nonempty actual|nonempty => 1|2 +*/ +void +XmlIdRegistryDocument::JoinMetadatables( + Metadatable & i_rMerged, Metadatable const & i_rOther) +{ + OSL_TRACE("JoinMetadatables: %p <- %p\n", &i_rMerged, &i_rOther); + + bool mergedOwnsRef; + ::rtl::OUString path; + ::rtl::OUString idref; + if (m_pImpl->LookupXmlId(i_rMerged, path, idref)) + { + mergedOwnsRef = (m_pImpl->LookupElement(path, idref) == &i_rMerged); + } + else + { + OSL_ENSURE(false, "JoinMetadatables: no xmlid?"); + return; + } + if (!mergedOwnsRef) + { + i_rMerged.RemoveMetadataReference(); + i_rMerged.RegisterAsCopyOf(i_rOther, true); + return; + } + // other cases: merged has actual ref and is nonempty, + // other has latent/actual ref and is nonempty: other loses => nothing to do +} + + +//============================================================================= +// Clipboard XML ID Registry (_Impl) + +struct RMapEntry +{ + RMapEntry() : m_pLink() { } + RMapEntry(::rtl::OUString const& i_rStream, + ::rtl::OUString const& i_rXmlId, + ::boost::shared_ptr<MetadatableClipboard> const& i_pLink + = ::boost::shared_ptr<MetadatableClipboard>()) + : m_Stream(i_rStream), m_XmlId(i_rXmlId), m_pLink(i_pLink) + {} + ::rtl::OUString m_Stream; + ::rtl::OUString m_XmlId; + // this would have been an auto_ptr, if only that would have compiled... + ::boost::shared_ptr<MetadatableClipboard> m_pLink; +}; + +/// element -> (stream name, idref, source) +typedef ::std::hash_map< const Metadatable*, + struct RMapEntry, + PtrHash<Metadatable> > + ClipboardXmlIdReverseMap_t; + +/// Idref -> (content.xml element, styles.xml element) +typedef ::std::hash_map< ::rtl::OUString, + ::std::pair< Metadatable*, Metadatable* >, ::rtl::OUStringHash > + ClipboardXmlIdMap_t; + +struct XmlIdRegistryClipboard::XmlIdRegistry_Impl +{ + XmlIdRegistry_Impl() + : m_XmlIdMap(), m_XmlIdReverseMap() { } + + bool TryInsertMetadatable(Metadatable& i_xObject, + const ::rtl::OUString & i_rStream, const ::rtl::OUString & i_rIdref); + + bool LookupXmlId(const Metadatable& i_xObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref, + MetadatableClipboard const* &o_rpLink) const; + + Metadatable* LookupElement(const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const; + + Metadatable* const* LookupEntry(const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const; + + Metadatable* * LookupEntry(const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) + { + return const_cast<Metadatable**>( + const_cast<const XmlIdRegistry_Impl*>(this) + ->LookupEntry(i_rStreamName, i_rIdref)); + } + + ClipboardXmlIdMap_t m_XmlIdMap; + ClipboardXmlIdReverseMap_t m_XmlIdReverseMap; +}; + +// ------------------------------------------------------------------- + +static void +rmIter(ClipboardXmlIdMap_t & i_rXmlIdMap, + ClipboardXmlIdMap_t::iterator const& i_rIter, + ::rtl::OUString const & i_rStream, Metadatable const& i_rObject) +{ + if (i_rIter != i_rXmlIdMap.end()) + { + Metadatable *& rMeta = isContentFile(i_rStream) + ? i_rIter->second.first : i_rIter->second.second; + if (rMeta == &i_rObject) + { + rMeta = 0; + } + if (!i_rIter->second.first && !i_rIter->second.second) + { + i_rXmlIdMap.erase(i_rIter); + } + } +} + +// ------------------------------------------------------------------- + +Metadatable* const* +XmlIdRegistryClipboard::XmlIdRegistry_Impl::LookupEntry( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const +{ + if (!isValidXmlId(i_rStreamName, i_rIdref)) + { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "illegal XmlId"), 0, 0); + } + + const ClipboardXmlIdMap_t::const_iterator iter( m_XmlIdMap.find(i_rIdref) ); + if (iter != m_XmlIdMap.end()) + { + OSL_ENSURE(iter->second.first || iter->second.second, + "null entry in m_XmlIdMap"); + return (isContentFile(i_rStreamName)) + ? &iter->second.first + : &iter->second.second; + } + else + { + return 0; + } +} + +Metadatable* +XmlIdRegistryClipboard::XmlIdRegistry_Impl::LookupElement( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const +{ + Metadatable * const * ppEntry = LookupEntry(i_rStreamName, i_rIdref); + return ppEntry ? *ppEntry : 0; +} + +bool +XmlIdRegistryClipboard::XmlIdRegistry_Impl::LookupXmlId( + const Metadatable& i_rObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref, + MetadatableClipboard const* &o_rpLink) const +{ + const ClipboardXmlIdReverseMap_t::const_iterator iter( + m_XmlIdReverseMap.find(&i_rObject) ); + if (iter != m_XmlIdReverseMap.end()) + { + OSL_ENSURE(!iter->second.m_Stream.equalsAscii(""), + "null stream in m_XmlIdReverseMap"); + OSL_ENSURE(!iter->second.m_XmlId.equalsAscii(""), + "null id in m_XmlIdReverseMap"); + o_rStream = iter->second.m_Stream; + o_rIdref = iter->second.m_XmlId; + o_rpLink = iter->second.m_pLink.get(); + return true; + } + else + { + return false; + } +} + +bool +XmlIdRegistryClipboard::XmlIdRegistry_Impl::TryInsertMetadatable( + Metadatable & i_rObject, + const ::rtl::OUString & i_rStreamName, const ::rtl::OUString & i_rIdref) +{ + bool bContent( isContentFile(i_rStreamName) ); + OSL_ENSURE(isContentFile(i_rStreamName) || isStylesFile(i_rStreamName), + "invalid stream"); + + //wntmsci12 won't parse this: +// Metadatable ** ppEntry( LookupEntry(i_rStreamName, i_rIdref) ); + Metadatable ** ppEntry = LookupEntry(i_rStreamName, i_rIdref); + if (ppEntry) + { + if (*ppEntry) + { + return false; + } + else + { + *ppEntry = &i_rObject; + return true; + } + } + else + { + m_XmlIdMap.insert(::std::make_pair(i_rIdref, bContent + ? ::std::make_pair( &i_rObject, static_cast<Metadatable*>(0) ) + : ::std::make_pair( static_cast<Metadatable*>(0), &i_rObject ))); + return true; + } +} + +//============================================================================= +// Clipboard XML ID Registry + + +XmlIdRegistryClipboard::XmlIdRegistryClipboard() + : m_pImpl( new XmlIdRegistry_Impl ) +{ +} + +XmlIdRegistryClipboard::~XmlIdRegistryClipboard() +{ +} + +bool +XmlIdRegistryClipboard::LookupXmlId( + const Metadatable& i_rObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref) const +{ + const MetadatableClipboard * pLink; + return m_pImpl->LookupXmlId(i_rObject, o_rStream, o_rIdref, pLink); +} + +Metadatable* +XmlIdRegistryClipboard::LookupElement( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const +{ + return m_pImpl->LookupElement(i_rStreamName, i_rIdref); +} + +bool +XmlIdRegistryClipboard::TryRegisterMetadatable(Metadatable & i_rObject, + ::rtl::OUString const& i_rStreamName, ::rtl::OUString const& i_rIdref) +{ + OSL_TRACE("TryRegisterMetadatable: %p (%s#%s)\n", &i_rObject, + ::rtl::OUStringToOString(i_rStreamName, RTL_TEXTENCODING_UTF8).getStr(), + ::rtl::OUStringToOString(i_rIdref, RTL_TEXTENCODING_UTF8).getStr()); + + OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject), + "TryRegisterMetadatable called for MetadatableUndo?"); + OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject), + "TryRegisterMetadatable called for MetadatableClipboard?"); + + if (!isValidXmlId(i_rStreamName, i_rIdref)) + { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "illegal XmlId"), 0, 0); + } + if (i_rObject.IsInContent() + ? !isContentFile(i_rStreamName) + : !isStylesFile(i_rStreamName)) + { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "illegal XmlId: wrong stream"), 0, 0); + } + + ::rtl::OUString old_path; + ::rtl::OUString old_idref; + const MetadatableClipboard * pLink; + m_pImpl->LookupXmlId(i_rObject, old_path, old_idref, pLink); + if (old_path == i_rStreamName && old_idref == i_rIdref) + { + return (m_pImpl->LookupElement(old_path, old_idref) == &i_rObject); + } + ClipboardXmlIdMap_t::iterator old_id( m_pImpl->m_XmlIdMap.end() ); + if (!old_idref.equalsAscii("")) + { + old_id = m_pImpl->m_XmlIdMap.find(old_idref); + OSL_ENSURE(old_id != m_pImpl->m_XmlIdMap.end(), "old id not found"); + } + if (m_pImpl->TryInsertMetadatable(i_rObject, i_rStreamName, i_rIdref)) + { + rmIter(m_pImpl->m_XmlIdMap, old_id, old_path, i_rObject); + m_pImpl->m_XmlIdReverseMap[&i_rObject] = + RMapEntry(i_rStreamName, i_rIdref); + return true; + } + else + { + return false; + } +} + +void +XmlIdRegistryClipboard::RegisterMetadatableAndCreateID(Metadatable & i_rObject) +{ + OSL_TRACE("RegisterMetadatableAndCreateID: %p\n", &i_rObject); + + OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject), + "RegisterMetadatableAndCreateID called for MetadatableUndo?"); + OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject), + "RegisterMetadatableAndCreateID called for MetadatableClipboard?"); + + bool isInContent( i_rObject.IsInContent() ); + ::rtl::OUString stream( ::rtl::OUString::createFromAscii( + isInContent ? s_content : s_styles ) ); + + ::rtl::OUString old_path; + ::rtl::OUString old_idref; + LookupXmlId(i_rObject, old_path, old_idref); + if (!old_idref.equalsAscii("") && + (m_pImpl->LookupElement(old_path, old_idref) == &i_rObject)) + { + return; + } + + // create id + const ::rtl::OUString id( create_id(m_pImpl->m_XmlIdMap) ); + OSL_ENSURE(m_pImpl->m_XmlIdMap.find(id) == m_pImpl->m_XmlIdMap.end(), + "created id is in use"); + m_pImpl->m_XmlIdMap.insert(::std::make_pair(id, isInContent + ? ::std::make_pair( &i_rObject, static_cast<Metadatable*>(0) ) + : ::std::make_pair( static_cast<Metadatable*>(0), &i_rObject ))); + // N.B.: if i_rObject had a latent XmlId, then we implicitly delete the + // MetadatableClipboard and thus the latent XmlId here + m_pImpl->m_XmlIdReverseMap[&i_rObject] = RMapEntry(stream, id); +} + +void XmlIdRegistryClipboard::UnregisterMetadatable(const Metadatable& i_rObject) +{ + OSL_TRACE("UnregisterMetadatable: %p\n", &i_rObject); + + ::rtl::OUString path; + ::rtl::OUString idref; + const MetadatableClipboard * pLink; + if (!m_pImpl->LookupXmlId(i_rObject, path, idref, pLink)) + { + OSL_ENSURE(false, "unregister: no xml id?"); + return; + } + const ClipboardXmlIdMap_t::iterator iter( m_pImpl->m_XmlIdMap.find(idref) ); + if (iter != m_pImpl->m_XmlIdMap.end()) + { + rmIter(m_pImpl->m_XmlIdMap, iter, path, i_rObject); + } +} + + +void XmlIdRegistryClipboard::RemoveXmlIdForElement(const Metadatable& i_rObject) +{ + OSL_TRACE("RemoveXmlIdForElement: %p\n", &i_rObject); + + ClipboardXmlIdReverseMap_t::iterator iter( + m_pImpl->m_XmlIdReverseMap.find(&i_rObject) ); + if (iter != m_pImpl->m_XmlIdReverseMap.end()) + { + OSL_ENSURE(!iter->second.m_XmlId.equalsAscii(""), + "null id in m_XmlIdReverseMap"); + m_pImpl->m_XmlIdReverseMap.erase(iter); + } +} + +// ------------------------------------------------------------------- + +::boost::shared_ptr<MetadatableClipboard> +XmlIdRegistryClipboard::CreateClipboard(const bool i_isInContent) +{ + OSL_TRACE("CreateClipboard: \n"); + + return ::boost::shared_ptr<MetadatableClipboard>( + new MetadatableClipboard(i_isInContent) ); +} + +MetadatableClipboard & +XmlIdRegistryClipboard::RegisterCopyClipboard(Metadatable & i_rCopy, + beans::StringPair const & i_rReference, + const bool i_isLatent) +{ + OSL_TRACE("RegisterCopyClipboard: %p -> "/*"%p"*/"(%s#%s) (%d)\n", + /*&i_rSource,*/ &i_rCopy, + ::rtl::OUStringToOString(i_rReference.First, + RTL_TEXTENCODING_UTF8).getStr(), + ::rtl::OUStringToOString(i_rReference.Second, + RTL_TEXTENCODING_UTF8).getStr(), + i_isLatent); + + // N.B.: when copying to the clipboard, the selection is always inserted + // into the body, even if the source is a header/footer! + // so we do not check whether the stream is right in this function + + if (!isValidXmlId(i_rReference.First, i_rReference.Second)) + { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "illegal XmlId"), 0, 0); + } + + if (!i_isLatent) + { + // this should succeed assuming clipboard has a single source document + const bool success( m_pImpl->TryInsertMetadatable(i_rCopy, + i_rReference.First, i_rReference.Second) ); + OSL_ENSURE(success, "RegisterCopyClipboard: TryInsert failed?"); + (void) success; + } + const ::boost::shared_ptr<MetadatableClipboard> pLink( + CreateClipboard( isContentFile(i_rReference.First)) ); + m_pImpl->m_XmlIdReverseMap.insert(::std::make_pair(&i_rCopy, + RMapEntry(i_rReference.First, i_rReference.Second, pLink))); + return *pLink.get(); +} + +MetadatableClipboard const* +XmlIdRegistryClipboard::SourceLink(Metadatable const& i_rObject) +{ + ::rtl::OUString path; + ::rtl::OUString idref; + const MetadatableClipboard * pLink( 0 ); + m_pImpl->LookupXmlId(i_rObject, path, idref, pLink); + return pLink; +} + + +//============================================================================= +// Metadatable mixin + + +Metadatable::~Metadatable() +{ + RemoveMetadataReference(); +} + +void Metadatable::RemoveMetadataReference() +{ + try + { + if (m_pReg) + { + m_pReg->UnregisterMetadatable( *this ); + m_pReg->RemoveXmlIdForElement( *this ); + m_pReg = 0; + } + } + catch (uno::Exception &) + { + OSL_ENSURE(false, "Metadatable::RemoveMetadataReference: exception"); + } +} + +// ::com::sun::star::rdf::XMetadatable: +beans::StringPair +Metadatable::GetMetadataReference() const +{ + if (m_pReg) + { + return m_pReg->GetXmlIdForElement(*this); + } + return beans::StringPair(); +} + +void +Metadatable::SetMetadataReference( + const ::com::sun::star::beans::StringPair & i_rReference) +{ + if (i_rReference.Second.equalsAscii("")) + { + RemoveMetadataReference(); + } + else + { + ::rtl::OUString streamName( i_rReference.First ); + if (streamName.equalsAscii("")) + { + // handle empty stream name as auto-detect. + // necessary for importing flat file format. + streamName = ::rtl::OUString::createFromAscii( + IsInContent() ? s_content : s_styles ); + } + XmlIdRegistry & rReg( dynamic_cast<XmlIdRegistry&>( GetRegistry() ) ); + if (rReg.TryRegisterMetadatable(*this, streamName, i_rReference.Second)) + { + m_pReg = &rReg; + } + else + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("Metadatable::" + "SetMetadataReference: argument is invalid"), /*this*/0, 0); + } + } +} + +void Metadatable::EnsureMetadataReference() +{ + XmlIdRegistry& rReg( + m_pReg ? *m_pReg : dynamic_cast<XmlIdRegistry&>( GetRegistry() ) ); + rReg.RegisterMetadatableAndCreateID( *this ); + m_pReg = &rReg; +} + +const ::sfx2::IXmlIdRegistry& GetRegistryConst(Metadatable const& i_rObject) +{ + return const_cast< Metadatable& >( i_rObject ).GetRegistry(); +} + +void +Metadatable::RegisterAsCopyOf(Metadatable const & i_rSource, + const bool i_bCopyPrecedesSource) +{ + OSL_ENSURE(typeid(*this) == typeid(i_rSource) + || typeid(i_rSource) == typeid(MetadatableUndo) + || typeid(*this) == typeid(MetadatableUndo) + || typeid(i_rSource) == typeid(MetadatableClipboard) + || typeid(*this) == typeid(MetadatableClipboard), + "RegisterAsCopyOf element with different class?"); + OSL_ENSURE(!this->m_pReg, "RegisterAsCopyOf called on element with XmlId?"); + + if (this->m_pReg) + { + RemoveMetadataReference(); + } + + try + { + if (i_rSource.m_pReg) + { + XmlIdRegistry & rReg( + dynamic_cast<XmlIdRegistry&>( GetRegistry() ) ); + if (i_rSource.m_pReg == &rReg) + { + OSL_ENSURE(!IsInClipboard(), + "RegisterAsCopy: both in clipboard?"); + if (!IsInClipboard()) + { + XmlIdRegistryDocument & rRegDoc( + dynamic_cast<XmlIdRegistryDocument&>( rReg ) ); + rRegDoc.RegisterCopy(i_rSource, *this, + i_bCopyPrecedesSource); + this->m_pReg = &rRegDoc; + } + return; + } + // source is in different document + XmlIdRegistryDocument * pRegDoc( + dynamic_cast<XmlIdRegistryDocument *>(&rReg) ); + XmlIdRegistryClipboard * pRegClp( + dynamic_cast<XmlIdRegistryClipboard*>(&rReg) ); + + if (pRegClp) + { + beans::StringPair SourceRef( + i_rSource.m_pReg->GetXmlIdForElement(i_rSource) ); + bool isLatent( SourceRef.Second.equalsAscii("") ); + XmlIdRegistryDocument * pSourceRegDoc( + dynamic_cast<XmlIdRegistryDocument*>(i_rSource.m_pReg) ); + OSL_ENSURE(pSourceRegDoc, "RegisterAsCopyOf: 2 clipboards?"); + if (!pSourceRegDoc) return; + // this is a copy _to_ the clipboard + if (isLatent) + { + pSourceRegDoc->LookupXmlId(i_rSource, + SourceRef.First, SourceRef.Second); + } + Metadatable & rLink( + pRegClp->RegisterCopyClipboard(*this, SourceRef, isLatent)); + this->m_pReg = pRegClp; + // register as copy in the non-clipboard registry + pSourceRegDoc->RegisterCopy(i_rSource, rLink, + false); // i_bCopyPrecedesSource); + rLink.m_pReg = pSourceRegDoc; + } + else if (pRegDoc) + { + XmlIdRegistryClipboard * pSourceRegClp( + dynamic_cast<XmlIdRegistryClipboard*>(i_rSource.m_pReg) ); + OSL_ENSURE(pSourceRegClp, + "RegisterAsCopyOf: 2 non-clipboards?"); + if (!pSourceRegClp) return; + const MetadatableClipboard * pLink( + pSourceRegClp->SourceLink(i_rSource) ); + // may happen if src got its id via UNO call + if (!pLink) return; + // only register copy if clipboard content is from this SwDoc! + if (pLink && (&GetRegistryConst(*pLink) == pRegDoc)) + { + // this is a copy _from_ the clipboard; check if the + // element is still in the same stream + // N.B.: we check the stream of pLink, not of i_rSource! + bool srcInContent( pLink->IsInContent() ); + bool tgtInContent( this->IsInContent() ); + if (srcInContent == tgtInContent) + { + pRegDoc->RegisterCopy(*pLink, *this, + true); // i_bCopyPrecedesSource); + this->m_pReg = pRegDoc; + } + // otherwise: stream change! do not register! + } + } + else + { + OSL_ENSURE(false, "neither RegDoc nor RegClp cannot happen"); + } +#if 0 + { + //FIXME: do we need this at all??? + XmlIdRegistryDocument & rRegDoc( + dynamic_cast<XmlIdRegistryDocument&>( rReg ) ); + { + if (rRegDoc.TryRegisterMetadatable(*this, SourceRef)) + { + this->m_pReg = &rRegDoc; + } + } + } +#endif + } + } + catch (uno::Exception &) + { + OSL_ENSURE(false, "Metadatable::RegisterAsCopyOf: exception"); + } +} + +::boost::shared_ptr<MetadatableUndo> Metadatable::CreateUndo() const +{ + OSL_ENSURE(!IsInUndo(), "CreateUndo called for object in undo?"); + OSL_ENSURE(!IsInClipboard(), "CreateUndo called for object in clipboard?"); + try + { + if (!IsInClipboard() && !IsInUndo() && m_pReg) + { + XmlIdRegistryDocument * pRegDoc( + dynamic_cast<XmlIdRegistryDocument*>( m_pReg ) ); + ::boost::shared_ptr<MetadatableUndo> pUndo( + pRegDoc->CreateUndo(*this) ); + pRegDoc->RegisterCopy(*this, *pUndo, false); + pUndo->m_pReg = pRegDoc; + return pUndo; + } + } + catch (uno::Exception &) + { + OSL_ENSURE(false, "Metadatable::CreateUndo: exception"); + } + return ::boost::shared_ptr<MetadatableUndo>(); +} + +::boost::shared_ptr<MetadatableUndo> Metadatable::CreateUndoForDelete() +{ + ::boost::shared_ptr<MetadatableUndo> const pUndo( CreateUndo() ); + RemoveMetadataReference(); + return pUndo; +} + +void Metadatable::RestoreMetadata( + ::boost::shared_ptr<MetadatableUndo> const& i_pUndo) +{ + OSL_ENSURE(!IsInUndo(), "RestoreMetadata called for object in undo?"); + OSL_ENSURE(!IsInClipboard(), + "RestoreMetadata called for object in clipboard?"); + if (IsInClipboard() || IsInUndo()) return; + RemoveMetadataReference(); + if (i_pUndo) + { + this->RegisterAsCopyOf(*i_pUndo, true); + } +} + +void +Metadatable::JoinMetadatable(Metadatable const & i_rOther, + const bool i_isMergedEmpty, const bool i_isOtherEmpty) +{ + OSL_ENSURE(!IsInUndo(), "JoinMetadatables called for object in undo?"); + OSL_ENSURE(!IsInClipboard(), + "JoinMetadatables called for object in clipboard?"); + if (IsInClipboard() || IsInUndo()) return; + + if (i_isOtherEmpty && !i_isMergedEmpty) + { + // other is empty, thus loses => nothing to do + return; + } + if (i_isMergedEmpty && !i_isOtherEmpty) + { + this->RemoveMetadataReference(); + this->RegisterAsCopyOf(i_rOther, true); + return; + } + + if (!i_rOther.m_pReg) + { + // other doesn't have xmlid, thus loses => nothing to do + return; + } + if (!m_pReg) + { + this->RegisterAsCopyOf(i_rOther, true); + // assumption: i_rOther will be deleted, so don't unregister it here + return; + } + try + { + XmlIdRegistryDocument * pRegDoc( + dynamic_cast<XmlIdRegistryDocument*>( m_pReg ) ); + OSL_ENSURE(pRegDoc, "JoinMetadatable: no pRegDoc?"); + if (pRegDoc) + { + pRegDoc->JoinMetadatables(*this, i_rOther); + } + } + catch (uno::Exception &) + { + OSL_ENSURE(false, "Metadatable::JoinMetadatable: exception"); + } +} + + +//============================================================================= +// XMetadatable mixin + +// ::com::sun::star::rdf::XNode: +::rtl::OUString SAL_CALL MetadatableMixin::getStringValue() + throw (::com::sun::star::uno::RuntimeException) +{ + return getNamespace() + getLocalName(); +} + +// ::com::sun::star::rdf::XURI: +::rtl::OUString SAL_CALL MetadatableMixin::getLocalName() + throw (::com::sun::star::uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + beans::StringPair mdref( getMetadataReference() ); + if (!mdref.Second.getLength()) + { + ensureMetadataReference(); // N.B.: side effect! + mdref = getMetadataReference(); + } + ::rtl::OUStringBuffer buf; + buf.append(mdref.First); + buf.append(static_cast<sal_Unicode>('#')); + buf.append(mdref.Second); + return buf.makeStringAndClear(); +} + +::rtl::OUString SAL_CALL MetadatableMixin::getNamespace() + throw (::com::sun::star::uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + const uno::Reference< frame::XModel > xModel( GetModel() ); + const uno::Reference< rdf::XURI > xDMA( xModel, uno::UNO_QUERY_THROW ); + return xDMA->getStringValue(); +} + +// ::com::sun::star::rdf::XMetadatable: +beans::StringPair SAL_CALL +MetadatableMixin::getMetadataReference() +throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + Metadatable *const pObject( GetCoreObject() ); + if (!pObject) + { + throw uno::RuntimeException( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "MetadatableMixin: cannot get core object; not inserted?")), + *this); + } + return pObject->GetMetadataReference(); +} + +void SAL_CALL +MetadatableMixin::setMetadataReference( + const beans::StringPair & i_rReference) +throw (uno::RuntimeException, lang::IllegalArgumentException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + Metadatable *const pObject( GetCoreObject() ); + if (!pObject) + { + throw uno::RuntimeException( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "MetadatableMixin: cannot get core object; not inserted?")), + *this); + } + return pObject->SetMetadataReference(i_rReference); +} + +void SAL_CALL MetadatableMixin::ensureMetadataReference() +throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + Metadatable *const pObject( GetCoreObject() ); + if (!pObject) + { + throw uno::RuntimeException( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "MetadatableMixin: cannot get core object; not inserted?")), + *this); + } + return pObject->EnsureMetadataReference(); +} + +} // namespace sfx2 + + +//============================================================================= + +#if OSL_DEBUG_LEVEL > 1 + +#include <stdio.h> + +static void dump(sfx2::XmlIdList_t * pList) +#ifdef GCC +__attribute__ ((unused)) +#endif +; +static void dump(sfx2::XmlIdList_t * pList) +{ + fprintf(stderr, "\nXmlIdList(%p): ", pList); + for (sfx2::XmlIdList_t::iterator i = pList->begin(); i != pList->end(); ++i) + { + fprintf(stderr, "%p ", *i); + } + fprintf(stderr, "\n"); +} + +#endif + diff --git a/sfx2/source/doc/QuerySaveDocument.cxx b/sfx2/source/doc/QuerySaveDocument.cxx new file mode 100644 index 000000000000..642fe3c21af8 --- /dev/null +++ b/sfx2/source/doc/QuerySaveDocument.cxx @@ -0,0 +1,50 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" +#include "QuerySaveDocument.hxx" + +#include <sfx2/sfx.hrc> +#include "sfxresid.hxx" +#include <sfx2/sfxuno.hxx> +#include "doc.hrc" +#ifndef _MSGBOX_HXX //autogen +#include <vcl/msgbox.hxx> +#endif +// ----------------------------------------------------------------------------- +short ExecuteQuerySaveDocument(Window* _pParent,const String& _rTitle) +{ + String aText( SfxResId( STR_QUERY_SAVE_DOCUMENT ) ); + aText.SearchAndReplace( DEFINE_CONST_UNICODE( "$(DOC)" ), + _rTitle ); + QueryBox aQBox( _pParent, WB_YES_NO_CANCEL | WB_DEF_YES, aText ); + aQBox.SetButtonText( BUTTONID_NO, SfxResId( STR_NOSAVEANDCLOSE ) ); + aQBox.SetButtonText( BUTTONID_YES, SfxResId( STR_SAVEDOC ) ); + return aQBox.Execute(); +} +// ----------------------------------------------------------------------------- diff --git a/sfx2/source/doc/SfxDocumentMetaData.cxx b/sfx2/source/doc/SfxDocumentMetaData.cxx new file mode 100644 index 000000000000..f18e903eb6e4 --- /dev/null +++ b/sfx2/source/doc/SfxDocumentMetaData.cxx @@ -0,0 +1,2384 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sfx2.hxx" + +#include "sal/config.h" +#include "cppuhelper/factory.hxx" +#include "cppuhelper/implementationentry.hxx" +#include "cppuhelper/compbase6.hxx" +#include "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/document/XDocumentProperties.hpp" +#include "com/sun/star/lang/XInitialization.hpp" +#include "com/sun/star/util/XCloneable.hpp" +#include "com/sun/star/util/XModifiable.hpp" +#include "com/sun/star/xml/sax/XSAXSerializable.hpp" + +#include "com/sun/star/lang/WrappedTargetRuntimeException.hpp" +#include "com/sun/star/lang/EventObject.hpp" +#include "com/sun/star/beans/XPropertySet.hpp" +#include "com/sun/star/beans/XPropertySetInfo.hpp" +#include "com/sun/star/beans/PropertyAttribute.hpp" +#include "com/sun/star/task/ErrorCodeIOException.hpp" +#include "com/sun/star/embed/XStorage.hpp" +#include "com/sun/star/embed/XTransactedObject.hpp" +#include "com/sun/star/embed/ElementModes.hpp" +#include "com/sun/star/io/XActiveDataControl.hpp" +#include "com/sun/star/io/XActiveDataSource.hpp" +#include "com/sun/star/io/XStream.hpp" +#include "com/sun/star/document/XImporter.hpp" +#include "com/sun/star/document/XExporter.hpp" +#include "com/sun/star/document/XFilter.hpp" +#include "com/sun/star/xml/sax/XParser.hpp" +#include "com/sun/star/xml/dom/XDocument.hpp" +#include "com/sun/star/xml/dom/XElement.hpp" +#include "com/sun/star/xml/dom/XDocumentBuilder.hpp" +#include "com/sun/star/xml/dom/XSAXDocumentBuilder.hpp" +#include "com/sun/star/xml/dom/NodeType.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "com/sun/star/util/Date.hpp" +#include "com/sun/star/util/Time.hpp" +#include "com/sun/star/util/Duration.hpp" + +#include "SfxDocumentMetaData.hxx" +#include "rtl/ustrbuf.hxx" +#include "tools/debug.hxx" +#include "tools/string.hxx" // for DBG +#include "tools/datetime.hxx" +#include "tools/urlobj.hxx" +#include "osl/mutex.hxx" +#include "cppuhelper/basemutex.hxx" +#include "cppuhelper/interfacecontainer.hxx" +#include "comphelper/storagehelper.hxx" +#include "comphelper/mediadescriptor.hxx" +#include "comphelper/sequenceasvector.hxx" +#include "comphelper/stlunosequence.hxx" +#include "sot/storage.hxx" +#include "sfx2/docfile.hxx" +#include "sax/tools/converter.hxx" + +#include <utility> +#include <vector> +#include <map> +#include <cstring> +#include <limits> + +/** + * This file contains the implementation of the service + * com.sun.star.document.DocumentProperties. + * This service enables access to the meta-data stored in documents. + * Currently, this service only handles documents in ODF format. + * + * The implementation uses an XML DOM to store the properties. + * This approach was taken because it allows for preserving arbitrary XML data + * in loaded documents, which will be stored unmodified when saving the + * document again. + * + * Upon access, some properties are directly read from and updated in the DOM. + * Exception: it seems impossible to get notified upon addition of a property + * to a com.sun.star.beans.PropertyBag, which is used for storing user-defined + * properties; because of this, user-defined properties are updated in the + * XML DOM only when storing the document. + * Exception 2: when setting certain properties which correspond to attributes + * in the XML DOM, we want to remove the corresponding XML element. Detecting + * this condition can get messy, so we store all such properties as members, + * and update the DOM tree only when storing the document (in + * <method>updateUserDefinedAndAttributes</method>). + * + * @author mst + */ + +/// anonymous implementation namespace +namespace { + +namespace css = ::com::sun::star; + + +/// a list of attribute-lists, where attribute means name and content +typedef std::vector<std::vector<std::pair<const char*, ::rtl::OUString> > > + AttrVector; + +typedef ::cppu::WeakComponentImplHelper6< + css::lang::XServiceInfo, + css::document::XDocumentProperties, + css::lang::XInitialization, + css::util::XCloneable, + css::util::XModifiable, + css::xml::sax::XSAXSerializable> + SfxDocumentMetaData_Base; + +class SfxDocumentMetaData: + private ::cppu::BaseMutex, + public SfxDocumentMetaData_Base +{ +public: + explicit SfxDocumentMetaData( + css::uno::Reference< css::uno::XComponentContext > const & context); + + // ::com::sun::star::lang::XServiceInfo: + virtual ::rtl::OUString SAL_CALL getImplementationName() + throw (css::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL supportsService( + const ::rtl::OUString & ServiceName) throw (css::uno::RuntimeException); + virtual css::uno::Sequence< ::rtl::OUString > SAL_CALL + getSupportedServiceNames() throw (css::uno::RuntimeException); + + // ::com::sun::star::lang::XComponent: + virtual void SAL_CALL dispose() throw (css::uno::RuntimeException); + + // ::com::sun::star::document::XDocumentProperties: + virtual ::rtl::OUString SAL_CALL getAuthor() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setAuthor(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getGenerator() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setGenerator(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException); + virtual css::util::DateTime SAL_CALL getCreationDate() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setCreationDate(const css::util::DateTime & the_value) + throw (css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getTitle() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setTitle(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getSubject() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setSubject(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getDescription() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setDescription(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException); + virtual css::uno::Sequence< ::rtl::OUString > SAL_CALL getKeywords() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setKeywords( + const css::uno::Sequence< ::rtl::OUString > & the_value) + throw (css::uno::RuntimeException); + virtual css::lang::Locale SAL_CALL getLanguage() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setLanguage(const css::lang::Locale & the_value) + throw (css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getModifiedBy() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setModifiedBy(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException); + virtual css::util::DateTime SAL_CALL getModificationDate() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setModificationDate( + const css::util::DateTime & the_value) + throw (css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getPrintedBy() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setPrintedBy(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException); + virtual css::util::DateTime SAL_CALL getPrintDate() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setPrintDate(const css::util::DateTime & the_value) + throw (css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getTemplateName() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setTemplateName(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getTemplateURL() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setTemplateURL(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException); + virtual css::util::DateTime SAL_CALL getTemplateDate() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setTemplateDate(const css::util::DateTime & the_value) + throw (css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAutoloadURL() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setAutoloadURL(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException); + virtual ::sal_Int32 SAL_CALL getAutoloadSecs() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setAutoloadSecs(::sal_Int32 the_value) + throw (css::uno::RuntimeException, css::lang::IllegalArgumentException); + virtual ::rtl::OUString SAL_CALL getDefaultTarget() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setDefaultTarget(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException); + virtual css::uno::Sequence< css::beans::NamedValue > SAL_CALL + getDocumentStatistics() throw (css::uno::RuntimeException); + virtual void SAL_CALL setDocumentStatistics( + const css::uno::Sequence< css::beans::NamedValue > & the_value) + throw (css::uno::RuntimeException); + virtual ::sal_Int16 SAL_CALL getEditingCycles() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setEditingCycles(::sal_Int16 the_value) + throw (css::uno::RuntimeException, css::lang::IllegalArgumentException); + virtual ::sal_Int32 SAL_CALL getEditingDuration() + throw (css::uno::RuntimeException); + virtual void SAL_CALL setEditingDuration(::sal_Int32 the_value) + throw (css::uno::RuntimeException, css::lang::IllegalArgumentException); + virtual void SAL_CALL resetUserData(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException); + virtual css::uno::Reference< css::beans::XPropertyContainer > SAL_CALL + getUserDefinedProperties() throw (css::uno::RuntimeException); + virtual void SAL_CALL loadFromStorage( + const css::uno::Reference< css::embed::XStorage > & Storage, + const css::uno::Sequence< css::beans::PropertyValue > & Medium) + throw (css::uno::RuntimeException, css::lang::IllegalArgumentException, + css::io::WrongFormatException, + css::lang::WrappedTargetException, css::io::IOException); + virtual void SAL_CALL loadFromMedium(const ::rtl::OUString & URL, + const css::uno::Sequence< css::beans::PropertyValue > & Medium) + throw (css::uno::RuntimeException, + css::io::WrongFormatException, + css::lang::WrappedTargetException, css::io::IOException); + virtual void SAL_CALL storeToStorage( + const css::uno::Reference< css::embed::XStorage > & Storage, + const css::uno::Sequence< css::beans::PropertyValue > & Medium) + throw (css::uno::RuntimeException, css::lang::IllegalArgumentException, + css::lang::WrappedTargetException, css::io::IOException); + virtual void SAL_CALL storeToMedium(const ::rtl::OUString & URL, + const css::uno::Sequence< css::beans::PropertyValue > & Medium) + throw (css::uno::RuntimeException, + css::lang::WrappedTargetException, css::io::IOException); + + // ::com::sun::star::lang::XInitialization: + virtual void SAL_CALL initialize( + const css::uno::Sequence< css::uno::Any > & aArguments) + throw (css::uno::RuntimeException, css::uno::Exception); + + // ::com::sun::star::util::XCloneable: + virtual css::uno::Reference<css::util::XCloneable> SAL_CALL createClone() + throw (css::uno::RuntimeException); + + // ::com::sun::star::util::XModifiable: + virtual ::sal_Bool SAL_CALL isModified( ) + throw (css::uno::RuntimeException); + virtual void SAL_CALL setModified( ::sal_Bool bModified ) + throw (css::beans::PropertyVetoException, css::uno::RuntimeException); + + // ::com::sun::star::util::XModifyBroadcaster: + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener > & xListener) + throw (css::uno::RuntimeException); + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener > & xListener) + throw (css::uno::RuntimeException); + + // ::com::sun::star::xml::sax::XSAXSerializable + virtual void SAL_CALL serialize( + const css::uno::Reference<css::xml::sax::XDocumentHandler>& i_xHandler, + const css::uno::Sequence< css::beans::StringPair >& i_rNamespaces) + throw (css::uno::RuntimeException, css::xml::sax::SAXException); + +private: + SfxDocumentMetaData(SfxDocumentMetaData &); // not defined + SfxDocumentMetaData& operator =(SfxDocumentMetaData &); // not defined + + virtual ~SfxDocumentMetaData() {} + + const css::uno::Reference< css::uno::XComponentContext > m_xContext; + + /// for notification + ::cppu::OInterfaceContainerHelper m_NotifyListeners; + /// flag: false means not initialized yet, or disposed + bool m_isInitialized; + /// flag + bool m_isModified; + /// meta-data DOM tree + css::uno::Reference< css::xml::dom::XDocument > m_xDoc; + /// meta-data super node in the meta-data DOM tree + css::uno::Reference< css::xml::dom::XNode> m_xParent; + /// standard meta data (single occurrence) + std::map< ::rtl::OUString, css::uno::Reference<css::xml::dom::XNode> > + m_meta; + /// standard meta data (multiple occurrences) + std::map< ::rtl::OUString, + std::vector<css::uno::Reference<css::xml::dom::XNode> > > m_metaList; + /// user-defined meta data (meta:user-defined) @ATTENTION may be null! + css::uno::Reference<css::beans::XPropertyContainer> m_xUserDefined; + // now for some meta-data attributes; these are not updated directly in the + // DOM because updates (detecting "empty" elements) would be quite messy + ::rtl::OUString m_TemplateName; + ::rtl::OUString m_TemplateURL; + css::util::DateTime m_TemplateDate; + ::rtl::OUString m_AutoloadURL; + sal_Int32 m_AutoloadSecs; + ::rtl::OUString m_DefaultTarget; + + /// check if we are initialized properly + void SAL_CALL checkInit() const; + // throw (css::uno::RuntimeException); + /// initialize state from given DOM tree + void SAL_CALL init(css::uno::Reference<css::xml::dom::XDocument> i_xDom); + // throw (css::uno::RuntimeException, css::io::WrongFormatException, + // css::uno::Exception); + /// update element in DOM tree + void SAL_CALL updateElement(const char *i_name, + std::vector<std::pair<const char *, ::rtl::OUString> >* i_pAttrs = 0); + /// update user-defined meta data and attributes in DOM tree + void SAL_CALL updateUserDefinedAndAttributes(); + /// create empty DOM tree (XDocument) + css::uno::Reference<css::xml::dom::XDocument> SAL_CALL createDOM() const; + /// extract base URL (necessary for converting relative links) + css::uno::Reference<css::beans::XPropertySet> SAL_CALL getURLProperties( + const css::uno::Sequence<css::beans::PropertyValue> & i_rMedium) const; + // throw (css::uno::RuntimeException); + /// get text of standard meta data element + ::rtl::OUString SAL_CALL getMetaText(const char* i_name) const; + // throw (css::uno::RuntimeException); + /// set text of standard meta data element iff not equal to existing text + bool SAL_CALL setMetaText(const char* i_name, + const ::rtl::OUString & i_rValue); + // throw (css::uno::RuntimeException); + /// set text of standard meta data element iff not equal to existing text + void SAL_CALL setMetaTextAndNotify(const char* i_name, + const ::rtl::OUString & i_rValue); + // throw (css::uno::RuntimeException); + /// get text of standard meta data element's attribute + ::rtl::OUString SAL_CALL getMetaAttr(const char* i_name, + const char* i_attr) const; + // throw (css::uno::RuntimeException); + /// get text of a list of standard meta data elements (multiple occ.) + css::uno::Sequence< ::rtl::OUString > SAL_CALL getMetaList( + const char* i_name) const; + // throw (css::uno::RuntimeException); + /// set text of a list of standard meta data elements (multiple occ.) + bool SAL_CALL setMetaList(const char* i_name, + const css::uno::Sequence< ::rtl::OUString > & i_rValue, + AttrVector const* = 0); + // throw (css::uno::RuntimeException); + void createUserDefined(); +}; + +//////////////////////////////////////////////////////////////////////////// + +bool operator== (const css::util::DateTime &i_rLeft, + const css::util::DateTime &i_rRight) +{ + return i_rLeft.Year == i_rRight.Year + && i_rLeft.Month == i_rRight.Month + && i_rLeft.Day == i_rRight.Day + && i_rLeft.Hours == i_rRight.Hours + && i_rLeft.Minutes == i_rRight.Minutes + && i_rLeft.Seconds == i_rRight.Seconds + && i_rLeft.HundredthSeconds == i_rRight.HundredthSeconds; +} + +// NB: keep these two arrays in sync! +const char* s_stdStatAttrs[] = { + "meta:page-count", + "meta:table-count", + "meta:draw-count", + "meta:image-count", + "meta:object-count", + "meta:ole-object-count", + "meta:paragraph-count", + "meta:word-count", + "meta:character-count", + "meta:row-count", + "meta:frame-count", + "meta:sentence-count", + "meta:syllable-count", + "meta:non-whitespace-character-count", + "meta:cell-count", + 0 +}; + +// NB: keep these two arrays in sync! +const char* s_stdStats[] = { + "PageCount", + "TableCount", + "DrawCount", + "ImageCount", + "ObjectCount", + "OLEObjectCount", + "ParagraphCount", + "WordCount", + "CharacterCount", + "RowCount", + "FrameCount", + "SentenceCount", + "SyllableCount", + "NonWhitespaceCharacterCount", + "CellCount", + 0 +}; + +const char* s_stdMeta[] = { + "meta:generator", // string + "dc:title", // string + "dc:description", // string + "dc:subject", // string + "meta:initial-creator", // string + "dc:creator", // string + "meta:printed-by", // string + "meta:creation-date", // dateTime + "dc:date", // dateTime + "meta:print-date", // dateTime + "meta:template", // XLink + "meta:auto-reload", // ... + "meta:hyperlink-behaviour", // ... + "dc:language", // language + "meta:editing-cycles", // nonNegativeInteger + "meta:editing-duration", // duration + "meta:document-statistic", // ... // note: statistic is singular, no s! + 0 +}; + +const char* s_stdMetaList[] = { + "meta:keyword", // string* + "meta:user-defined", // ...* + 0 +}; + +const char* s_nsXLink = "http://www.w3.org/1999/xlink"; +const char* s_nsDC = "http://purl.org/dc/elements/1.1/"; +const char* s_nsODF = "urn:oasis:names:tc:opendocument:xmlns:office:1.0"; +const char* s_nsODFMeta = "urn:oasis:names:tc:opendocument:xmlns:meta:1.0"; +// const char* s_nsOOo = "http://openoffice.org/2004/office"; // not used (yet?) + +const char* s_metaXml = "meta.xml"; + + +bool isValidDate(const css::util::Date & i_rDate) +{ + return i_rDate.Month > 0; +} + +bool isValidDateTime(const css::util::DateTime & i_rDateTime) +{ + return i_rDateTime.Month > 0; +} + +std::pair< ::rtl::OUString, ::rtl::OUString > SAL_CALL +getQualifier(const char* i_name) { + ::rtl::OUString nm = ::rtl::OUString::createFromAscii(i_name); + sal_Int32 ix = nm.indexOf(static_cast<sal_Unicode> (':')); + if (ix == -1) { + return std::make_pair(::rtl::OUString(), nm); + } else { + return std::make_pair(nm.copy(0,ix), nm.copy(ix+1)); + } +} + +// get namespace for standard qualified names +// NB: only call this with statically known strings! +::rtl::OUString SAL_CALL getNameSpace(const char* i_qname) throw () +{ + DBG_ASSERT(i_qname, "SfxDocumentMetaData: getNameSpace: argument is null"); + const char * ns = ""; + ::rtl::OUString n = getQualifier(i_qname).first; + if (n.equalsAscii("xlink" )) ns = s_nsXLink; + if (n.equalsAscii("dc" )) ns = s_nsDC; + if (n.equalsAscii("office")) ns = s_nsODF; + if (n.equalsAscii("meta" )) ns = s_nsODFMeta; + DBG_ASSERT(*ns, "SfxDocumentMetaData: unknown namespace prefix"); + return ::rtl::OUString::createFromAscii(ns); +} + +bool SAL_CALL +textToDateOrDateTime(css::util::Date & io_rd, css::util::DateTime & io_rdt, + bool & o_rIsDateTime, ::rtl::OUString i_text) throw () +{ + if (::sax::Converter::convertDateOrDateTime( + io_rd, io_rdt, o_rIsDateTime, i_text)) { + return true; + } else { + DBG_WARNING1("SfxDocumentMetaData: invalid date: %s", + OUStringToOString(i_text, RTL_TEXTENCODING_UTF8).getStr()); + return false; + } +} + +// convert string to date/time +bool SAL_CALL +textToDateTime(css::util::DateTime & io_rdt, ::rtl::OUString i_text) throw () +{ + if (::sax::Converter::convertDateTime(io_rdt, i_text)) { + return true; + } else { + DBG_WARNING1("SfxDocumentMetaData: invalid date: %s", + OUStringToOString(i_text, RTL_TEXTENCODING_UTF8).getStr()); + return false; + } +} + +// convert string to date/time with default return value +css::util::DateTime SAL_CALL +textToDateTimeDefault(::rtl::OUString i_text) throw () +{ + css::util::DateTime dt; + static_cast<void> (textToDateTime(dt, i_text)); + // on conversion error: return default value (unchanged) + return dt; +} + +// convert date to string +::rtl::OUString SAL_CALL +dateToText(css::util::Date const& i_rd) throw () +{ + if (isValidDate(i_rd)) { + ::rtl::OUStringBuffer buf; + ::sax::Converter::convertDate(buf, i_rd); + return buf.makeStringAndClear(); + } else { + return ::rtl::OUString(); + } +} + + +// convert date/time to string +::rtl::OUString SAL_CALL +dateTimeToText(css::util::DateTime const& i_rdt) throw () +{ + if (isValidDateTime(i_rdt)) { + ::rtl::OUStringBuffer buf; + ::sax::Converter::convertDateTime(buf, i_rdt, true); + return buf.makeStringAndClear(); + } else { + return ::rtl::OUString(); + } +} + +// convert string to duration +bool +textToDuration(css::util::Duration& io_rDur, ::rtl::OUString const& i_rText) +throw () +{ + if (::sax::Converter::convertDuration(io_rDur, i_rText)) { + return true; + } else { + DBG_WARNING1("SfxDocumentMetaData: invalid duration: %s", + OUStringToOString(i_rText, RTL_TEXTENCODING_UTF8).getStr()); + return false; + } +} + +sal_Int32 textToDuration(::rtl::OUString const& i_rText) throw () +{ + css::util::Duration d; + if (textToDuration(d, i_rText)) { + // #i107372#: approximate years/months + const sal_Int32 days( (d.Years * 365) + (d.Months * 30) + d.Days ); + return (days * (24*3600)) + + (d.Hours * 3600) + (d.Minutes * 60) + d.Seconds; + } else { + return 0; // default + } +} + +// convert duration to string +::rtl::OUString durationToText(css::util::Duration const& i_rDur) throw () +{ + ::rtl::OUStringBuffer buf; + ::sax::Converter::convertDuration(buf, i_rDur); + return buf.makeStringAndClear(); +} + +// convert duration to string +::rtl::OUString SAL_CALL durationToText(sal_Int32 i_value) throw () +{ + css::util::Duration ud; + ud.Days = static_cast<sal_Int16>(i_value / (24 * 3600)); + ud.Hours = static_cast<sal_Int16>((i_value % (24 * 3600)) / 3600); + ud.Minutes = static_cast<sal_Int16>((i_value % 3600) / 60); + ud.Seconds = static_cast<sal_Int16>(i_value % 60); + ud.MilliSeconds = 0; + return durationToText(ud); +} + +// extract base URL (necessary for converting relative links) +css::uno::Reference< css::beans::XPropertySet > SAL_CALL +SfxDocumentMetaData::getURLProperties( + const css::uno::Sequence< css::beans::PropertyValue > & i_rMedium) const +{ + css::uno::Reference<css::lang::XMultiComponentFactory> xMsf ( + m_xContext->getServiceManager()); + css::uno::Reference< css::beans::XPropertyContainer> xPropArg( + xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii( + "com.sun.star.beans.PropertyBag"), m_xContext), + css::uno::UNO_QUERY_THROW); + try { + ::rtl::OUString dburl = + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DocumentBaseURL")); + ::rtl::OUString hdn = + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("HierarchicalDocumentName")); + for (sal_Int32 i = 0; i < i_rMedium.getLength(); ++i) { + if (i_rMedium[i].Name.equals(dburl)) { + xPropArg->addProperty( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("BaseURI")), + css::beans::PropertyAttribute::MAYBEVOID, + i_rMedium[i].Value); + } else if (i_rMedium[i].Name.equals(hdn)) { + xPropArg->addProperty( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("StreamRelPath")), + css::beans::PropertyAttribute::MAYBEVOID, + i_rMedium[i].Value); + } + } + xPropArg->addProperty(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("StreamName")), + css::beans::PropertyAttribute::MAYBEVOID, + css::uno::makeAny(::rtl::OUString::createFromAscii(s_metaXml))); + } catch (css::uno::Exception &) { + // ignore + } + return css::uno::Reference< css::beans::XPropertySet>(xPropArg, + css::uno::UNO_QUERY_THROW); +} + +// return the text of the (hopefully unique, i.e., normalize first!) text +// node _below_ the given node +::rtl::OUString SAL_CALL +getNodeText(css::uno::Reference<css::xml::dom::XNode> i_xNode) + throw (css::uno::RuntimeException) +{ + if (!i_xNode.is()) throw css::uno::RuntimeException( + ::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::getNodeText: argument is null"), i_xNode); + for (css::uno::Reference<css::xml::dom::XNode> c = i_xNode->getFirstChild(); + c.is(); + c = c->getNextSibling()) { + if (c->getNodeType() == css::xml::dom::NodeType_TEXT_NODE) { + try { + return c->getNodeValue(); + } catch (css::xml::dom::DOMException &) { // too big? + return ::rtl::OUString(); + } + } + } + return ::rtl::OUString(); +} + +::rtl::OUString SAL_CALL +SfxDocumentMetaData::getMetaText(const char* i_name) const +// throw (css::uno::RuntimeException) +{ + checkInit(); + + const ::rtl::OUString name( ::rtl::OUString::createFromAscii(i_name) ); + DBG_ASSERT(m_meta.find(name) != m_meta.end(), + "SfxDocumentMetaData::getMetaText: not found"); + css::uno::Reference<css::xml::dom::XNode> xNode = m_meta.find(name)->second; + return (xNode.is()) ? getNodeText(xNode) : ::rtl::OUString(); +} + +bool SAL_CALL +SfxDocumentMetaData::setMetaText(const char* i_name, + const ::rtl::OUString & i_rValue) + // throw (css::uno::RuntimeException) +{ + checkInit(); + + const ::rtl::OUString name( ::rtl::OUString::createFromAscii(i_name) ); + DBG_ASSERT(m_meta.find(name) != m_meta.end(), + "SfxDocumentMetaData::setMetaText: not found"); + css::uno::Reference<css::xml::dom::XNode> xNode = m_meta.find(name)->second; + + try { + if (i_rValue.equalsAscii("")) { + if (xNode.is()) { // delete + m_xParent->removeChild(xNode); + xNode.clear(); + m_meta[name] = xNode; + return true; + } else { + return false; + } + } else { + if (xNode.is()) { // update + for (css::uno::Reference<css::xml::dom::XNode> c = + xNode->getFirstChild(); + c.is(); + c = c->getNextSibling()) { + if (c->getNodeType() == css::xml::dom::NodeType_TEXT_NODE) { + if (!c->getNodeValue().equals(i_rValue)) { + c->setNodeValue(i_rValue); + return true; + } else { + return false; + } + } + } + } else { // insert + xNode.set(m_xDoc->createElementNS(getNameSpace(i_name), name), + css::uno::UNO_QUERY_THROW); + m_xParent->appendChild(xNode); + m_meta[name] = xNode; + } + css::uno::Reference<css::xml::dom::XNode> xTextNode( + m_xDoc->createTextNode(i_rValue), css::uno::UNO_QUERY_THROW); + xNode->appendChild(xTextNode); + return true; + } + } catch (css::xml::dom::DOMException & e) { + css::uno::Any a(e); + throw css::lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::setMetaText: DOM exception"), + css::uno::Reference<css::uno::XInterface>(*this), a); + } +} + +void SAL_CALL +SfxDocumentMetaData::setMetaTextAndNotify(const char* i_name, + const ::rtl::OUString & i_rValue) + // throw (css::uno::RuntimeException) +{ + ::osl::ClearableMutexGuard g(m_aMutex); + if (setMetaText(i_name, i_rValue)) { + g.clear(); + setModified(true); + } +} + +::rtl::OUString SAL_CALL +SfxDocumentMetaData::getMetaAttr(const char* i_name, const char* i_attr) const +// throw (css::uno::RuntimeException) +{ +// checkInit(); + ::rtl::OUString name = ::rtl::OUString::createFromAscii(i_name); + DBG_ASSERT(m_meta.find(name) != m_meta.end(), + "SfxDocumentMetaData::getMetaAttr: not found"); + css::uno::Reference<css::xml::dom::XNode> xNode = m_meta.find(name)->second; + if (xNode.is()) { + css::uno::Reference<css::xml::dom::XElement> xElem(xNode, + css::uno::UNO_QUERY_THROW); + return xElem->getAttributeNS(getNameSpace(i_attr), + getQualifier(i_attr).second); + } else { + return ::rtl::OUString(); + } +} + +css::uno::Sequence< ::rtl::OUString> SAL_CALL +SfxDocumentMetaData::getMetaList(const char* i_name) const +// throw (css::uno::RuntimeException) +{ + checkInit(); + ::rtl::OUString name = ::rtl::OUString::createFromAscii(i_name); + DBG_ASSERT(m_metaList.find(name) != m_metaList.end(), + "SfxDocumentMetaData::getMetaList: not found"); + std::vector<css::uno::Reference<css::xml::dom::XNode> > const & vec = + m_metaList.find(name)->second; + css::uno::Sequence< ::rtl::OUString> ret(vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + ret[i] = getNodeText(vec.at(i)); + } + return ret; +} + +bool SAL_CALL +SfxDocumentMetaData::setMetaList(const char* i_name, + const css::uno::Sequence< ::rtl::OUString> & i_rValue, + AttrVector const* i_pAttrs) + // throw (css::uno::RuntimeException) +{ + checkInit(); + DBG_ASSERT((i_pAttrs == 0) || + (static_cast<size_t>(i_rValue.getLength()) == i_pAttrs->size()), + "SfxDocumentMetaData::setMetaList: invalid args"); + + try { + ::rtl::OUString name = ::rtl::OUString::createFromAscii(i_name); + DBG_ASSERT(m_metaList.find(name) != m_metaList.end(), + "SfxDocumentMetaData::setMetaList: not found"); + std::vector<css::uno::Reference<css::xml::dom::XNode> > & vec = + m_metaList[name]; + + // if nothing changed, do nothing + // alas, this does not check for permutations, or attributes... + if ((0 == i_pAttrs)) { + if (static_cast<size_t>(i_rValue.getLength()) == vec.size()) { + bool isEqual(true); + for (sal_Int32 i = 0; i < i_rValue.getLength(); ++i) { + css::uno::Reference<css::xml::dom::XNode> xNode(vec.at(i)); + if (xNode.is()) { + ::rtl::OUString val = getNodeText(xNode); + if (!val.equals(i_rValue[i])) { + isEqual = false; + break; + } + } + } + if (isEqual) return false; + } + } + + // remove old meta data nodes + { + std::vector<css::uno::Reference<css::xml::dom::XNode> > + ::reverse_iterator it(vec.rbegin()); + try { + for ( ;it != vec.rend(); ++it) + { + m_xParent->removeChild(*it); + } + } + catch (...) + { + // Clean up already removed nodes + vec.erase(it.base(), vec.end()); + throw; + } + vec.clear(); + } + + // insert new meta data nodes into DOM tree + for (sal_Int32 i = 0; i < i_rValue.getLength(); ++i) { + css::uno::Reference<css::xml::dom::XElement> xElem( + m_xDoc->createElementNS(getNameSpace(i_name), name), + css::uno::UNO_QUERY_THROW); + css::uno::Reference<css::xml::dom::XNode> xNode(xElem, + css::uno::UNO_QUERY_THROW); + css::uno::Reference<css::xml::dom::XNode> xTextNode( + m_xDoc->createTextNode(i_rValue[i]), css::uno::UNO_QUERY_THROW); + // set attributes + if (i_pAttrs != 0) { + for (std::vector<std::pair<const char*, ::rtl::OUString> > + ::const_iterator it = (*i_pAttrs)[i].begin(); + it != (*i_pAttrs)[i].end(); ++it) { + xElem->setAttributeNS(getNameSpace(it->first), + ::rtl::OUString::createFromAscii(it->first), + it->second); + } + } + xNode->appendChild(xTextNode); + m_xParent->appendChild(xNode); + vec.push_back(xNode); + } + + return true; + } catch (css::xml::dom::DOMException & e) { + css::uno::Any a(e); + throw css::lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::setMetaList: DOM exception"), + css::uno::Reference<css::uno::XInterface>(*this), a); + } +} + +// convert property list to string list and attribute list +std::pair<css::uno::Sequence< ::rtl::OUString>, AttrVector> SAL_CALL +propsToStrings(css::uno::Reference<css::beans::XPropertySet> const & i_xPropSet) +{ + ::comphelper::SequenceAsVector< ::rtl::OUString > values; + AttrVector attrs; + + css::uno::Reference<css::beans::XPropertySetInfo> xSetInfo + = i_xPropSet->getPropertySetInfo(); + css::uno::Sequence<css::beans::Property> props = xSetInfo->getProperties(); + + for (sal_Int32 i = 0; i < props.getLength(); ++i) { + if (props[i].Attributes & css::beans::PropertyAttribute::TRANSIENT) { + continue; + } + const ::rtl::OUString name = props[i].Name; + css::uno::Any any; + try { + any = i_xPropSet->getPropertyValue(name); + } catch (css::uno::Exception &) { + // ignore + } + const css::uno::Type & type = any.getValueType(); + std::vector<std::pair<const char*, ::rtl::OUString> > as; + as.push_back(std::make_pair(static_cast<const char*>("meta:name"), + name)); + const char* vt = "meta:value-type"; + + // convert according to type + if (type == ::cppu::UnoType<bool>::get()) { + bool b = false; + any >>= b; + ::rtl::OUStringBuffer buf; + ::sax::Converter::convertBool(buf, b); + values.push_back(buf.makeStringAndClear()); + as.push_back(std::make_pair(vt, + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("boolean")))); + } else if (type == ::cppu::UnoType< ::rtl::OUString>::get()) { + ::rtl::OUString s; + any >>= s; + values.push_back(s); +// #i90847# OOo 2.x does stupid things if value-type="string"; +// fortunately string is default anyway, so we can just omit it +// #i107502#: however, OOo 2.x only reads 4 user-defined without @value-type +// => best backward compatibility: first 4 without @value-type, rest with + if (4 <= i) + { + as.push_back(std::make_pair(vt, + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("string")))); + } + } else if (type == ::cppu::UnoType<css::util::DateTime>::get()) { + css::util::DateTime dt; + any >>= dt; + values.push_back(dateTimeToText(dt)); + as.push_back(std::make_pair(vt, + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("date")))); + } else if (type == ::cppu::UnoType<css::util::Date>::get()) { + css::util::Date d; + any >>= d; + values.push_back(dateToText(d)); + as.push_back(std::make_pair(vt, + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("date")))); + } else if (type == ::cppu::UnoType<css::util::Time>::get()) { + // #i97029#: replaced by Duration + // Time is supported for backward compatibility with OOo 3.x, x<=2 + css::util::Time ut; + any >>= ut; + css::util::Duration ud; + ud.Hours = ut.Hours; + ud.Minutes = ut.Minutes; + ud.Seconds = ut.Seconds; + ud.MilliSeconds = 10 * ut.HundredthSeconds; + values.push_back(durationToText(ud)); + as.push_back(std::make_pair(vt, + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("time")))); + } else if (type == ::cppu::UnoType<css::util::Duration>::get()) { + css::util::Duration ud; + any >>= ud; + values.push_back(durationToText(ud)); + as.push_back(std::make_pair(vt, + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("time")))); + } else if (::cppu::UnoType<double>::get().isAssignableFrom(type)) { + // support not just double, but anything that can be converted + double d = 0; + any >>= d; + ::rtl::OUStringBuffer buf; + ::sax::Converter::convertDouble(buf, d); + values.push_back(buf.makeStringAndClear()); + as.push_back(std::make_pair(vt, + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("float")))); + } else { + DBG_WARNING1("SfxDocumentMetaData: unsupported property type: %s", + OUStringToOString(any.getValueTypeName(), + RTL_TEXTENCODING_UTF8).getStr()); + continue; + } + attrs.push_back(as); + } + + return std::make_pair(values.getAsConstList(), attrs); +} + +// remove the given element from the DOM, and iff i_pAttrs != 0 insert new one +void SAL_CALL +SfxDocumentMetaData::updateElement(const char *i_name, + std::vector<std::pair<const char *, ::rtl::OUString> >* i_pAttrs) +{ + ::rtl::OUString name = ::rtl::OUString::createFromAscii(i_name); + try { + // remove old element + css::uno::Reference<css::xml::dom::XNode> xNode = + m_meta.find(name)->second; + if (xNode.is()) { + m_xParent->removeChild(xNode); + xNode.clear(); + } + // add new element + if (0 != i_pAttrs) { + css::uno::Reference<css::xml::dom::XElement> xElem( + m_xDoc->createElementNS(getNameSpace(i_name), name), + css::uno::UNO_QUERY_THROW); + xNode.set(xElem, css::uno::UNO_QUERY_THROW); + // set attributes + for (std::vector<std::pair<const char *, ::rtl::OUString> > + ::const_iterator it = i_pAttrs->begin(); + it != i_pAttrs->end(); ++it) { + xElem->setAttributeNS(getNameSpace(it->first), + ::rtl::OUString::createFromAscii(it->first), it->second); + } + m_xParent->appendChild(xNode); + } + m_meta[name] = xNode; + } catch (css::xml::dom::DOMException & e) { + css::uno::Any a(e); + throw css::lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::updateElement: DOM exception"), + css::uno::Reference<css::uno::XInterface>(*this), a); + } +} + +// update user-defined meta data in DOM tree +void SAL_CALL SfxDocumentMetaData::updateUserDefinedAndAttributes() +{ + createUserDefined(); + const css::uno::Reference<css::beans::XPropertySet> xPSet(m_xUserDefined, + css::uno::UNO_QUERY_THROW); + const std::pair<css::uno::Sequence< ::rtl::OUString>, AttrVector> + udStringsAttrs( propsToStrings(xPSet) ); + (void) setMetaList("meta:user-defined", udStringsAttrs.first, + &udStringsAttrs.second); + + // update elements with attributes + std::vector<std::pair<const char *, ::rtl::OUString> > attributes; + if (!m_TemplateName.equalsAscii("") || !m_TemplateURL.equalsAscii("") + || isValidDateTime(m_TemplateDate)) { + attributes.push_back(std::make_pair( + static_cast<const char*>("xlink:type"), + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("simple")))); + attributes.push_back(std::make_pair( + static_cast<const char*>("xlink:actuate"), + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("onRequest")))); + attributes.push_back(std::make_pair( + static_cast<const char*>("xlink:title"), m_TemplateName)); + attributes.push_back(std::make_pair( + static_cast<const char*>("xlink:href" ), m_TemplateURL )); + if (isValidDateTime(m_TemplateDate)) { + attributes.push_back(std::make_pair( + static_cast<const char*>("meta:date" ), + dateTimeToText(m_TemplateDate))); + } + updateElement("meta:template", &attributes); + } else { + updateElement("meta:template"); + } + attributes.clear(); + + if (!m_AutoloadURL.equalsAscii("") || (0 != m_AutoloadSecs)) { + attributes.push_back(std::make_pair( + static_cast<const char*>("xlink:href" ), m_AutoloadURL )); + attributes.push_back(std::make_pair( + static_cast<const char*>("meta:delay" ), + durationToText(m_AutoloadSecs))); + updateElement("meta:auto-reload", &attributes); + } else { + updateElement("meta:auto-reload"); + } + attributes.clear(); + + if (!m_DefaultTarget.equalsAscii("")) { + attributes.push_back(std::make_pair( + static_cast<const char*>("office:target-frame-name"), + m_DefaultTarget)); + // xlink:show: _blank -> new, any other value -> replace + const sal_Char* show = m_DefaultTarget.equalsAscii("_blank") + ? "new" : "replace"; + attributes.push_back(std::make_pair( + static_cast<const char*>("xlink:show"), + ::rtl::OUString::createFromAscii(show))); + updateElement("meta:hyperlink-behaviour", &attributes); + } else { + updateElement("meta:hyperlink-behaviour"); + } + attributes.clear(); +} + +// create empty DOM tree (XDocument) +css::uno::Reference<css::xml::dom::XDocument> SAL_CALL +SfxDocumentMetaData::createDOM() const // throw (css::uno::RuntimeException) +{ + css::uno::Reference<css::lang::XMultiComponentFactory> xMsf ( + m_xContext->getServiceManager()); + css::uno::Reference<css::xml::dom::XDocumentBuilder> xBuilder( + xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii( + "com.sun.star.xml.dom.DocumentBuilder"), m_xContext), + css::uno::UNO_QUERY_THROW ); + if (!xBuilder.is()) throw css::uno::RuntimeException( + ::rtl::OUString::createFromAscii("SfxDocumentMetaData::createDOM: " + "cannot create DocumentBuilder service"), + *const_cast<SfxDocumentMetaData*>(this)); + css::uno::Reference<css::xml::dom::XDocument> xDoc = + xBuilder->newDocument(); + if (!xDoc.is()) throw css::uno::RuntimeException( + ::rtl::OUString::createFromAscii("SfxDocumentMetaData::createDOM: " + "cannot create new document"), + *const_cast<SfxDocumentMetaData*>(this)); + return xDoc; +} + +void SAL_CALL +SfxDocumentMetaData::checkInit() const // throw (css::uno::RuntimeException) +{ + if (!m_isInitialized) { + throw css::uno::RuntimeException(::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::checkInit: not initialized"), + *const_cast<SfxDocumentMetaData*>(this)); + } + DBG_ASSERT((m_xDoc.is() && m_xParent.is() ), + "SfxDocumentMetaData::checkInit: reference is null"); +} + +// initialize state from DOM tree +void SAL_CALL SfxDocumentMetaData::init( + css::uno::Reference<css::xml::dom::XDocument> i_xDoc) +// throw (css::uno::RuntimeException, css::io::WrongFormatException, +// css::uno::Exception) +{ + if (!i_xDoc.is()) throw css::uno::RuntimeException( + ::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::init: no DOM tree given"), *this); + + css::uno::Reference<css::lang::XMultiComponentFactory> xMsf ( + m_xContext->getServiceManager()); + css::uno::Reference<css::xml::xpath::XXPathAPI> xPath( + xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii( + "com.sun.star.xml.xpath.XPathAPI"), m_xContext), + css::uno::UNO_QUERY_THROW ); + if (!xPath.is()) throw css::uno::RuntimeException( + ::rtl::OUString::createFromAscii("SfxDocumentMetaData::init:" + " cannot create XPathAPI service"), *this); + + m_isInitialized = false; + m_xDoc = i_xDoc; + m_xDoc->normalize(); + + // select nodes for standard meta data stuff + xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("xlink")), + ::rtl::OUString::createFromAscii(s_nsXLink)); + xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("dc")), + ::rtl::OUString::createFromAscii(s_nsDC)); + xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("office")), + ::rtl::OUString::createFromAscii(s_nsODF)); + xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("meta")), + ::rtl::OUString::createFromAscii(s_nsODFMeta)); + // NB: we do not handle the single-XML-file ODF variant, which would + // have the root element office:document. + // The root of such documents must be converted in the importer! + ::rtl::OUString prefix = ::rtl::OUString::createFromAscii( + "/child::office:document-meta/child::office:meta"); + css::uno::Reference<css::xml::dom::XNode> xDocNode( + m_xDoc, css::uno::UNO_QUERY_THROW); + m_xParent.clear(); + try { + m_xParent = xPath->selectSingleNode(xDocNode, prefix); + } catch (com::sun::star::uno::Exception &) { +// DBG_WARNING("SfxDocumentMetaData::init: " +// "caught RuntimeException from libxml!"); + } + + if (!m_xParent.is()) { + // all this create/append stuff may throw DOMException + try { + css::uno::Reference<css::xml::dom::XElement> xRElem( + i_xDoc->createElementNS( + ::rtl::OUString::createFromAscii(s_nsODF), + ::rtl::OUString::createFromAscii("office:document-meta"))); + css::uno::Reference<css::xml::dom::XNode> xRNode(xRElem, + css::uno::UNO_QUERY_THROW); + // NB: the following is a _bad_idea_ with our DOM implementation + // do _not_ create attributes with xmlns prefix! +// xRElem->setAttribute(::rtl::OUString::createFromAscii("xmlns:office"), +// ::rtl::OUString::createFromAscii(s_nsODF)); + xRElem->setAttributeNS(::rtl::OUString::createFromAscii(s_nsODF), + ::rtl::OUString::createFromAscii("office:version"), + ::rtl::OUString::createFromAscii("1.0")); + i_xDoc->appendChild(xRNode); + css::uno::Reference<css::xml::dom::XNode> xParent ( + i_xDoc->createElementNS( + ::rtl::OUString::createFromAscii(s_nsODF), + ::rtl::OUString::createFromAscii("office:meta")), + css::uno::UNO_QUERY_THROW); + xRNode->appendChild(xParent); + m_xParent = xParent; + } catch (css::xml::dom::DOMException & e) { + css::uno::Any a(e); + throw css::lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::init: DOM exception"), + css::uno::Reference<css::uno::XInterface>(*this), a); + } + } + + + // select nodes for elements of which we only handle one occurrence + for (const char **pName = s_stdMeta; *pName != 0; ++pName) { + ::rtl::OUString name = ::rtl::OUString::createFromAscii(*pName); + // NB: If a document contains more than one occurrence of a + // meta-data element, we arbitrarily pick one of them here. + // We do not remove the others, i.e., when we write the + // document, it will contain the duplicates unchanged. + // The ODF spec says that handling multiple occurrences is + // application-specific. + css::uno::Reference<css::xml::dom::XNode> xNode = + xPath->selectSingleNode(m_xParent, + ::rtl::OUString::createFromAscii("child::") + name); + // Do not create an empty element if it is missing; + // for certain elements, such as dateTime, this would be invalid + m_meta[name] = xNode; + } + + // select nodes for elements of which we handle all occurrences + for (const char **pName = s_stdMetaList; *pName != 0; ++pName) { + ::rtl::OUString name = ::rtl::OUString::createFromAscii(*pName); + css::uno::Reference<css::xml::dom::XNodeList> nodes = + xPath->selectNodeList(m_xParent, + ::rtl::OUString::createFromAscii("child::") + name); + std::vector<css::uno::Reference<css::xml::dom::XNode> > v; + for (sal_Int32 i = 0; i < nodes->getLength(); ++i) { + v.push_back(nodes->item(i)); + } + m_metaList[name] = v; + } + + // initialize members corresponding to attributes from DOM nodes + m_TemplateName = getMetaAttr("meta:template", "xlink:title"); + m_TemplateURL = getMetaAttr("meta:template", "xlink:href"); + m_TemplateDate = + textToDateTimeDefault(getMetaAttr("meta:template", "meta:date")); + m_AutoloadURL = getMetaAttr("meta:auto-reload", "xlink:href"); + m_AutoloadSecs = + textToDuration(getMetaAttr("meta:auto-reload", "meta:delay")); + m_DefaultTarget = + getMetaAttr("meta:hyperlink-behaviour", "office:target-frame-name"); + + + std::vector<css::uno::Reference<css::xml::dom::XNode> > & vec = + m_metaList[::rtl::OUString::createFromAscii("meta:user-defined")]; + m_xUserDefined.clear(); // #i105826#: reset (may be re-initialization) + if ( !vec.empty() ) + { + createUserDefined(); + } + + // user-defined meta data: initialize PropertySet from DOM nodes + for (std::vector<css::uno::Reference<css::xml::dom::XNode> >::iterator + it = vec.begin(); it != vec.end(); ++it) { + css::uno::Reference<css::xml::dom::XElement> xElem(*it, + css::uno::UNO_QUERY_THROW); + css::uno::Any any; + ::rtl::OUString name = xElem->getAttributeNS( + ::rtl::OUString::createFromAscii(s_nsODFMeta), + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("name"))); + ::rtl::OUString type = xElem->getAttributeNS( + ::rtl::OUString::createFromAscii(s_nsODFMeta), + ::rtl::OUString::createFromAscii("value-type")); + ::rtl::OUString text = getNodeText(*it); + if (type.equalsAscii("float")) { + double d; + if (::sax::Converter::convertDouble(d, text)) { + any <<= d; + } else { + DBG_WARNING1("SfxDocumentMetaData: invalid float: %s", + OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr()); + continue; + } + } else if (type.equalsAscii("date")) { + bool isDateTime; + css::util::Date d; + css::util::DateTime dt; + if (textToDateOrDateTime(d, dt, isDateTime, text)) { + if (isDateTime) { + any <<= dt; + } else { + any <<= d; + } + } else { + DBG_WARNING1("SfxDocumentMetaData: invalid date: %s", + OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr()); + continue; + } + } else if (type.equalsAscii("time")) { + css::util::Duration ud; + if (textToDuration(ud, text)) { + any <<= ud; + } else { + DBG_WARNING1("SfxDocumentMetaData: invalid time: %s", + OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr()); + continue; + } + } else if (type.equalsAscii("boolean")) { + bool b; + if (::sax::Converter::convertBool(b, text)) { + any <<= b; + } else { + DBG_WARNING1("SfxDocumentMetaData: invalid boolean: %s", + OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr()); + continue; + } + } else if (type.equalsAscii("string") || true) { // default + any <<= text; + } + try { + m_xUserDefined->addProperty(name, + css::beans::PropertyAttribute::REMOVEABLE, any); + } catch (css::beans::PropertyExistException &) { + DBG_WARNING1("SfxDocumentMetaData: duplicate: %s", + OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr()); + // ignore; duplicate + } catch (css::beans::IllegalTypeException &) { + DBG_ERROR1("SfxDocumentMetaData: illegal type: %s", + OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr()); + } catch (css::lang::IllegalArgumentException &) { + DBG_ERROR1("SfxDocumentMetaData: illegal arg: %s", + OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr()); + } + } + + m_isModified = false; + m_isInitialized = true; +} + + +//////////////////////////////////////////////////////////////////////////// + +SfxDocumentMetaData::SfxDocumentMetaData( + css::uno::Reference< css::uno::XComponentContext > const & context) + : BaseMutex() + , SfxDocumentMetaData_Base(m_aMutex) + , m_xContext(context) + , m_NotifyListeners(m_aMutex) + , m_isInitialized(false) + , m_isModified(false) + , m_AutoloadSecs(0) +{ + DBG_ASSERT(context.is(), "SfxDocumentMetaData: context is null"); + DBG_ASSERT(context->getServiceManager().is(), + "SfxDocumentMetaData: context has no service manager"); + init(createDOM()); +} + +// com.sun.star.uno.XServiceInfo: +::rtl::OUString SAL_CALL +SfxDocumentMetaData::getImplementationName() throw (css::uno::RuntimeException) +{ + return comp_SfxDocumentMetaData::_getImplementationName(); +} + +::sal_Bool SAL_CALL +SfxDocumentMetaData::supportsService(::rtl::OUString const & serviceName) + throw (css::uno::RuntimeException) +{ + css::uno::Sequence< ::rtl::OUString > serviceNames = + comp_SfxDocumentMetaData::_getSupportedServiceNames(); + for (::sal_Int32 i = 0; i < serviceNames.getLength(); ++i) { + if (serviceNames[i] == serviceName) + return sal_True; + } + return sal_False; +} + +css::uno::Sequence< ::rtl::OUString > SAL_CALL +SfxDocumentMetaData::getSupportedServiceNames() + throw (css::uno::RuntimeException) +{ + return comp_SfxDocumentMetaData::_getSupportedServiceNames(); +} + + +// ::com::sun::star::lang::XComponent: +void SAL_CALL SfxDocumentMetaData::dispose() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + if (!m_isInitialized) { + return; + } + WeakComponentImplHelperBase::dispose(); // superclass + m_NotifyListeners.disposeAndClear(css::lang::EventObject( + static_cast< ::cppu::OWeakObject* >(this))); + m_isInitialized = false; + m_meta.clear(); + m_metaList.clear(); + m_xParent.clear(); + m_xDoc.clear(); + m_xUserDefined.clear(); +} + + +// ::com::sun::star::document::XDocumentProperties: +::rtl::OUString SAL_CALL +SfxDocumentMetaData::getAuthor() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + return getMetaText("meta:initial-creator"); +} + +void SAL_CALL SfxDocumentMetaData::setAuthor(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException) +{ + setMetaTextAndNotify("meta:initial-creator", the_value); +} + + +::rtl::OUString SAL_CALL +SfxDocumentMetaData::getGenerator() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + return getMetaText("meta:generator"); +} + +void SAL_CALL +SfxDocumentMetaData::setGenerator(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException) +{ + setMetaTextAndNotify("meta:generator", the_value); +} + +css::util::DateTime SAL_CALL +SfxDocumentMetaData::getCreationDate() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + return textToDateTimeDefault(getMetaText("meta:creation-date")); +} + +void SAL_CALL +SfxDocumentMetaData::setCreationDate(const css::util::DateTime & the_value) + throw (css::uno::RuntimeException) +{ + setMetaTextAndNotify("meta:creation-date", dateTimeToText(the_value)); +} + +::rtl::OUString SAL_CALL +SfxDocumentMetaData::getTitle() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + return getMetaText("dc:title"); +} + +void SAL_CALL SfxDocumentMetaData::setTitle(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException) +{ + setMetaTextAndNotify("dc:title", the_value); +} + +::rtl::OUString SAL_CALL +SfxDocumentMetaData::getSubject() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + return getMetaText("dc:subject"); +} + +void SAL_CALL +SfxDocumentMetaData::setSubject(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException) +{ + setMetaTextAndNotify("dc:subject", the_value); +} + +::rtl::OUString SAL_CALL +SfxDocumentMetaData::getDescription() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + return getMetaText("dc:description"); +} + +void SAL_CALL +SfxDocumentMetaData::setDescription(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException) +{ + setMetaTextAndNotify("dc:description", the_value); +} + +css::uno::Sequence< ::rtl::OUString > +SAL_CALL SfxDocumentMetaData::getKeywords() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + return getMetaList("meta:keyword"); +} + +void SAL_CALL +SfxDocumentMetaData::setKeywords( + const css::uno::Sequence< ::rtl::OUString > & the_value) + throw (css::uno::RuntimeException) +{ + ::osl::ClearableMutexGuard g(m_aMutex); + if (setMetaList("meta:keyword", the_value)) { + g.clear(); + setModified(true); + } +} + +css::lang::Locale SAL_CALL + SfxDocumentMetaData::getLanguage() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + css::lang::Locale loc; + ::rtl::OUString text = getMetaText("dc:language"); + sal_Int32 ix = text.indexOf(static_cast<sal_Unicode> ('-')); + if (ix == -1) { + loc.Language = text; + } else { + loc.Language = text.copy(0, ix); + loc.Country = text.copy(ix+1); + } + return loc; +} + +void SAL_CALL +SfxDocumentMetaData::setLanguage(const css::lang::Locale & the_value) + throw (css::uno::RuntimeException) +{ + ::rtl::OUString text = the_value.Language; + if (the_value.Country.getLength() > 0) { + text += ::rtl::OUString::createFromAscii("-").concat(the_value.Country); + } + setMetaTextAndNotify("dc:language", text); +} + +::rtl::OUString SAL_CALL +SfxDocumentMetaData::getModifiedBy() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + return getMetaText("dc:creator"); +} + +void SAL_CALL +SfxDocumentMetaData::setModifiedBy(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException) +{ + setMetaTextAndNotify("dc:creator", the_value); +} + +css::util::DateTime SAL_CALL +SfxDocumentMetaData::getModificationDate() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + return textToDateTimeDefault(getMetaText("dc:date")); +} + +void SAL_CALL +SfxDocumentMetaData::setModificationDate(const css::util::DateTime & the_value) + throw (css::uno::RuntimeException) +{ + setMetaTextAndNotify("dc:date", dateTimeToText(the_value)); +} + +::rtl::OUString SAL_CALL +SfxDocumentMetaData::getPrintedBy() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + return getMetaText("meta:printed-by"); +} + +void SAL_CALL +SfxDocumentMetaData::setPrintedBy(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException) +{ + setMetaTextAndNotify("meta:printed-by", the_value); +} + +css::util::DateTime SAL_CALL +SfxDocumentMetaData::getPrintDate() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + return textToDateTimeDefault(getMetaText("meta:print-date")); +} + +void SAL_CALL +SfxDocumentMetaData::setPrintDate(const css::util::DateTime & the_value) + throw (css::uno::RuntimeException) +{ + setMetaTextAndNotify("meta:print-date", dateTimeToText(the_value)); +} + +::rtl::OUString SAL_CALL +SfxDocumentMetaData::getTemplateName() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + checkInit(); + return m_TemplateName; +} + +void SAL_CALL +SfxDocumentMetaData::setTemplateName(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException) +{ + ::osl::ClearableMutexGuard g(m_aMutex); + checkInit(); + if (m_TemplateName != the_value) { + m_TemplateName = the_value; + g.clear(); + setModified(true); + } +} + +::rtl::OUString SAL_CALL +SfxDocumentMetaData::getTemplateURL() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + checkInit(); + return m_TemplateURL; +} + +void SAL_CALL +SfxDocumentMetaData::setTemplateURL(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException) +{ + ::osl::ClearableMutexGuard g(m_aMutex); + checkInit(); + if (m_TemplateURL != the_value) { + m_TemplateURL = the_value; + g.clear(); + setModified(true); + } +} + +css::util::DateTime SAL_CALL +SfxDocumentMetaData::getTemplateDate() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + checkInit(); + return m_TemplateDate; +} + +void SAL_CALL +SfxDocumentMetaData::setTemplateDate(const css::util::DateTime & the_value) + throw (css::uno::RuntimeException) +{ + ::osl::ClearableMutexGuard g(m_aMutex); + checkInit(); + if (!(m_TemplateDate == the_value)) { + m_TemplateDate = the_value; + g.clear(); + setModified(true); + } +} + +::rtl::OUString SAL_CALL +SfxDocumentMetaData::getAutoloadURL() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + checkInit(); + return m_AutoloadURL; +} + +void SAL_CALL +SfxDocumentMetaData::setAutoloadURL(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException) +{ + ::osl::ClearableMutexGuard g(m_aMutex); + checkInit(); + if (m_AutoloadURL != the_value) { + m_AutoloadURL = the_value; + g.clear(); + setModified(true); + } +} + +::sal_Int32 SAL_CALL +SfxDocumentMetaData::getAutoloadSecs() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + checkInit(); + return m_AutoloadSecs; +} + +void SAL_CALL +SfxDocumentMetaData::setAutoloadSecs(::sal_Int32 the_value) + throw (css::uno::RuntimeException, css::lang::IllegalArgumentException) +{ + if (the_value < 0) throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::setAutoloadSecs: argument is negative"), + *this, 0); + ::osl::ClearableMutexGuard g(m_aMutex); + checkInit(); + if (m_AutoloadSecs != the_value) { + m_AutoloadSecs = the_value; + g.clear(); + setModified(true); + } +} + +::rtl::OUString SAL_CALL +SfxDocumentMetaData::getDefaultTarget() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + checkInit(); + return m_DefaultTarget; +} + +void SAL_CALL +SfxDocumentMetaData::setDefaultTarget(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException) +{ + ::osl::ClearableMutexGuard g(m_aMutex); + checkInit(); + if (m_DefaultTarget != the_value) { + m_DefaultTarget = the_value; + g.clear(); + setModified(true); + } +} + +css::uno::Sequence< css::beans::NamedValue > SAL_CALL +SfxDocumentMetaData::getDocumentStatistics() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + checkInit(); + ::comphelper::SequenceAsVector<css::beans::NamedValue> stats; + for (size_t i = 0; s_stdStats[i] != 0; ++i) { + const char * aName = s_stdStatAttrs[i]; + ::rtl::OUString text = getMetaAttr("meta:document-statistic", aName); + if (text.equalsAscii("")) continue; + css::beans::NamedValue stat; + stat.Name = ::rtl::OUString::createFromAscii(s_stdStats[i]); + sal_Int32 val; + css::uno::Any any; + if (!::sax::Converter::convertNumber(val, text, 0, + std::numeric_limits<sal_Int32>::max()) || (val < 0)) { + val = 0; + DBG_WARNING1("SfxDocumentMetaData: invalid number: %s", + OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr()); + } + any <<= val; + stat.Value = any; + stats.push_back(stat); + } + + return stats.getAsConstList(); +} + +void SAL_CALL +SfxDocumentMetaData::setDocumentStatistics( + const css::uno::Sequence< css::beans::NamedValue > & the_value) + throw (css::uno::RuntimeException) +{ + ::osl::ClearableMutexGuard g(m_aMutex); + checkInit(); + std::vector<std::pair<const char *, ::rtl::OUString> > attributes; + for (sal_Int32 i = 0; i < the_value.getLength(); ++i) { + const ::rtl::OUString name = the_value[i].Name; + // inefficently search for matching attribute + for (size_t j = 0; s_stdStats[j] != 0; ++j) { + if (name.equalsAscii(s_stdStats[j])) { + const css::uno::Any any = the_value[i].Value; + sal_Int32 val = 0; + if (any >>= val) { + ::rtl::OUStringBuffer buf; + ::sax::Converter::convertNumber(buf, val); + attributes.push_back(std::make_pair(s_stdStatAttrs[j], + buf.makeStringAndClear())); + } else { + DBG_WARNING1("SfxDocumentMetaData: invalid statistic: %s", + OUStringToOString(name, RTL_TEXTENCODING_UTF8) + .getStr()); + } + break; + } + } + } + updateElement("meta:document-statistic", &attributes); + g.clear(); + setModified(true); +} + +::sal_Int16 SAL_CALL +SfxDocumentMetaData::getEditingCycles() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + ::rtl::OUString text = getMetaText("meta:editing-cycles"); + sal_Int32 ret; + if (::sax::Converter::convertNumber(ret, text, + 0, std::numeric_limits<sal_Int16>::max())) { + return static_cast<sal_Int16>(ret); + } else { + return 0; + } +} + +void SAL_CALL +SfxDocumentMetaData::setEditingCycles(::sal_Int16 the_value) + throw (css::uno::RuntimeException, css::lang::IllegalArgumentException) +{ + if (the_value < 0) throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::setEditingCycles: argument is negative"), + *this, 0); + ::rtl::OUStringBuffer buf; + ::sax::Converter::convertNumber(buf, the_value); + setMetaTextAndNotify("meta:editing-cycles", buf.makeStringAndClear()); +} + +::sal_Int32 SAL_CALL +SfxDocumentMetaData::getEditingDuration() throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + return textToDuration(getMetaText("meta:editing-duration")); +} + +void SAL_CALL +SfxDocumentMetaData::setEditingDuration(::sal_Int32 the_value) + throw (css::uno::RuntimeException, css::lang::IllegalArgumentException) +{ + if (the_value < 0) throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::setEditingDuration: argument is negative"), + *this, 0); + setMetaTextAndNotify("meta:editing-duration", durationToText(the_value)); +} + +void SAL_CALL +SfxDocumentMetaData::resetUserData(const ::rtl::OUString & the_value) + throw (css::uno::RuntimeException) +{ + ::osl::ClearableMutexGuard g(m_aMutex); + + bool bModified( false ); + bModified |= setMetaText("meta:initial-creator", the_value); + ::DateTime now = DateTime(); + css::util::DateTime uDT(now.Get100Sec(), now.GetSec(), now.GetMin(), + now.GetHour(), now.GetDay(), now.GetMonth(), now.GetYear()); + bModified |= setMetaText("meta:creation-date", dateTimeToText(uDT)); + bModified |= setMetaText("dc:creator", ::rtl::OUString()); + bModified |= setMetaText("meta:printed-by", ::rtl::OUString()); + bModified |= setMetaText("dc:date", dateTimeToText(css::util::DateTime())); + bModified |= setMetaText("meta:print-date", + dateTimeToText(css::util::DateTime())); + bModified |= setMetaText("meta:editing-duration", durationToText(0)); + bModified |= setMetaText("meta:editing-cycles", + ::rtl::OUString::createFromAscii("1")); + + if (bModified) { + g.clear(); + setModified(true); + } +} + + +css::uno::Reference< css::beans::XPropertyContainer > SAL_CALL +SfxDocumentMetaData::getUserDefinedProperties() + throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + checkInit(); + createUserDefined(); + return m_xUserDefined; +} + + +void SAL_CALL +SfxDocumentMetaData::loadFromStorage( + const css::uno::Reference< css::embed::XStorage > & xStorage, + const css::uno::Sequence< css::beans::PropertyValue > & Medium) + throw (css::uno::RuntimeException, css::lang::IllegalArgumentException, + css::io::WrongFormatException, + css::lang::WrappedTargetException, css::io::IOException) +{ + if (!xStorage.is()) throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("SfxDocumentMetaData::loadFromStorage:" + " argument is null"), *this, 0); + ::osl::MutexGuard g(m_aMutex); + + // open meta data file + css::uno::Reference<css::io::XStream> xStream( + xStorage->openStreamElement( + ::rtl::OUString::createFromAscii(s_metaXml), + css::embed::ElementModes::READ) ); + if (!xStream.is()) throw css::uno::RuntimeException(); + css::uno::Reference<css::io::XInputStream> xInStream = + xStream->getInputStream(); + if (!xInStream.is()) throw css::uno::RuntimeException(); + + // create DOM parser service + css::uno::Reference<css::lang::XMultiComponentFactory> xMsf ( + m_xContext->getServiceManager()); + css::uno::Reference<css::xml::sax::XParser> xParser ( + xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii( + "com.sun.star.xml.sax.Parser"), m_xContext), + css::uno::UNO_QUERY_THROW); + if (!xParser.is()) throw css::uno::RuntimeException( + ::rtl::OUString::createFromAscii("SfxDocumentMetaData::loadFromStorage:" + " cannot create Parser service"), *this); + css::xml::sax::InputSource input; + input.aInputStream = xInStream; + + sal_uInt64 version = SotStorage::GetVersion( xStorage ); + // Oasis is also the default (0) + sal_Bool bOasis = ( version > SOFFICE_FILEFORMAT_60 || version == 0 ); + const sal_Char *pServiceName = bOasis + ? "com.sun.star.document.XMLOasisMetaImporter" + : "com.sun.star.document.XMLMetaImporter"; + + // set base URL + css::uno::Reference<css::beans::XPropertySet> xPropArg = + getURLProperties(Medium); + try { + xPropArg->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("BaseURI"))) + >>= input.sSystemId; + input.sSystemId += ::rtl::OUString::createFromAscii("/").concat( + ::rtl::OUString::createFromAscii(s_metaXml)); + } catch (css::uno::Exception &) { + input.sSystemId = ::rtl::OUString::createFromAscii(s_metaXml); + } + css::uno::Sequence< css::uno::Any > args(1); + args[0] <<= xPropArg; + + css::uno::Reference<css::xml::sax::XDocumentHandler> xDocHandler ( + xMsf->createInstanceWithArgumentsAndContext( + ::rtl::OUString::createFromAscii(pServiceName), args, m_xContext), + css::uno::UNO_QUERY_THROW); + if (!xDocHandler.is()) throw css::uno::RuntimeException( + ::rtl::OUString::createFromAscii("SfxDocumentMetaData::loadFromStorage:" + " cannot create XMLOasisMetaImporter service"), *this); + css::uno::Reference<css::document::XImporter> xImp (xDocHandler, + css::uno::UNO_QUERY_THROW); + xImp->setTargetDocument(css::uno::Reference<css::lang::XComponent>(this)); + xParser->setDocumentHandler(xDocHandler); + try { + xParser->parseStream(input); + } catch (css::xml::sax::SAXException &) { + throw css::io::WrongFormatException(::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::loadFromStorage:" + " XML parsing exception"), *this); + } + // NB: the implementation of XMLOasisMetaImporter calls initialize +// init(xDocBuilder->getDocument()); + checkInit(); +} + +void SAL_CALL +SfxDocumentMetaData::storeToStorage( + const css::uno::Reference< css::embed::XStorage > & xStorage, + const css::uno::Sequence< css::beans::PropertyValue > & Medium) + throw (css::uno::RuntimeException, css::lang::IllegalArgumentException, + css::lang::WrappedTargetException, css::io::IOException) +{ + if (!xStorage.is()) throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("SfxDocumentMetaData::storeToStorage:" + " argument is null"), *this, 0); + ::osl::MutexGuard g(m_aMutex); + checkInit(); + + // update user-defined meta data in DOM tree +// updateUserDefinedAndAttributes(); // this will be done in serialize! + + // write into storage + css::uno::Reference<css::io::XStream> xStream = + xStorage->openStreamElement(::rtl::OUString::createFromAscii(s_metaXml), + css::embed::ElementModes::WRITE + | css::embed::ElementModes::TRUNCATE); + if (!xStream.is()) throw css::uno::RuntimeException(); + css::uno::Reference< css::beans::XPropertySet > xStreamProps(xStream, + css::uno::UNO_QUERY_THROW); + xStreamProps->setPropertyValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("MediaType")), + css::uno::makeAny(::rtl::OUString::createFromAscii("text/xml"))); + xStreamProps->setPropertyValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Compressed")), + css::uno::makeAny(static_cast<sal_Bool> (sal_False))); + xStreamProps->setPropertyValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("UseCommonStoragePasswordEncryption")), + css::uno::makeAny(static_cast<sal_Bool> (sal_False))); + css::uno::Reference<css::io::XOutputStream> xOutStream = + xStream->getOutputStream(); + if (!xOutStream.is()) throw css::uno::RuntimeException(); + css::uno::Reference<css::lang::XMultiComponentFactory> xMsf ( + m_xContext->getServiceManager()); + css::uno::Reference<css::io::XActiveDataSource> xSaxWriter( + xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii( + "com.sun.star.xml.sax.Writer"), m_xContext), + css::uno::UNO_QUERY_THROW); + xSaxWriter->setOutputStream(xOutStream); + css::uno::Reference<css::xml::sax::XDocumentHandler> xDocHandler ( + xSaxWriter, css::uno::UNO_QUERY_THROW); + + const sal_uInt64 version = SotStorage::GetVersion( xStorage ); + // Oasis is also the default (0) + const sal_Bool bOasis = ( version > SOFFICE_FILEFORMAT_60 || version == 0 ); + const sal_Char *pServiceName = bOasis + ? "com.sun.star.document.XMLOasisMetaExporter" + : "com.sun.star.document.XMLMetaExporter"; + + // set base URL + css::uno::Reference<css::beans::XPropertySet> xPropArg = + getURLProperties(Medium); + css::uno::Sequence< css::uno::Any > args(2); + args[0] <<= xDocHandler; + args[1] <<= xPropArg; + + css::uno::Reference<css::document::XExporter> xExp( + xMsf->createInstanceWithArgumentsAndContext( + ::rtl::OUString::createFromAscii(pServiceName), args, m_xContext), + css::uno::UNO_QUERY_THROW); + xExp->setSourceDocument(css::uno::Reference<css::lang::XComponent>(this)); + css::uno::Reference<css::document::XFilter> xFilter(xExp, + css::uno::UNO_QUERY_THROW); + if (xFilter->filter(css::uno::Sequence< css::beans::PropertyValue >())) { + css::uno::Reference<css::embed::XTransactedObject> xTransaction( + xStorage, css::uno::UNO_QUERY); + if (xTransaction.is()) { + xTransaction->commit(); + } + } else { + throw css::io::IOException(::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::storeToStorage: cannot filter"), *this); + } +} + +void SAL_CALL +SfxDocumentMetaData::loadFromMedium(const ::rtl::OUString & URL, + const css::uno::Sequence< css::beans::PropertyValue > & Medium) + throw (css::uno::RuntimeException, css::io::WrongFormatException, + css::lang::WrappedTargetException, css::io::IOException) +{ + css::uno::Reference<css::io::XInputStream> xIn; + ::comphelper::MediaDescriptor md(Medium); + // if we have an URL parameter, it replaces the one in the media descriptor + if (!URL.equalsAscii("")) { + md[ ::comphelper::MediaDescriptor::PROP_URL() ] <<= URL; + } + if (sal_True == md.addInputStream()) { + md[ ::comphelper::MediaDescriptor::PROP_INPUTSTREAM() ] >>= xIn; + } + css::uno::Reference<css::embed::XStorage> xStorage; + css::uno::Reference<css::lang::XMultiServiceFactory> xMsf ( + m_xContext->getServiceManager(), css::uno::UNO_QUERY_THROW); + try { + if (xIn.is()) { + xStorage = ::comphelper::OStorageHelper::GetStorageFromInputStream( + xIn, xMsf); + } else { // fallback to url parameter + xStorage = ::comphelper::OStorageHelper::GetStorageFromURL( + URL, css::embed::ElementModes::READ, xMsf); + } + } catch (css::uno::RuntimeException &) { + throw; + } catch (css::io::IOException &) { + throw; + } catch (css::uno::Exception & e) { + throw css::lang::WrappedTargetException( + ::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::loadFromMedium: exception"), + css::uno::Reference<css::uno::XInterface>(*this), + css::uno::makeAny(e)); + } + if (!xStorage.is()) { + throw css::uno::RuntimeException(::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::loadFromMedium: cannot get Storage"), + *this); + } + loadFromStorage(xStorage, md.getAsConstPropertyValueList()); +} + +void SAL_CALL +SfxDocumentMetaData::storeToMedium(const ::rtl::OUString & URL, + const css::uno::Sequence< css::beans::PropertyValue > & Medium) + throw (css::uno::RuntimeException, + css::lang::WrappedTargetException, css::io::IOException) +{ + ::comphelper::MediaDescriptor md(Medium); + if (!URL.equalsAscii("")) { + md[ ::comphelper::MediaDescriptor::PROP_URL() ] <<= URL; + } + SfxMedium aMedium(md.getAsConstPropertyValueList()); + css::uno::Reference<css::embed::XStorage> xStorage + = aMedium.GetOutputStorage(); + + + if (!xStorage.is()) { + throw css::uno::RuntimeException(::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::storeToMedium: cannot get Storage"), + *this); + } + // set MIME type of the storage + ::comphelper::MediaDescriptor::const_iterator iter + = md.find(::comphelper::MediaDescriptor::PROP_MEDIATYPE()); + if (iter != md.end()) { + css::uno::Reference< css::beans::XPropertySet > xProps(xStorage, + css::uno::UNO_QUERY_THROW); + xProps->setPropertyValue( + ::comphelper::MediaDescriptor::PROP_MEDIATYPE(), + iter->second); + } + storeToStorage(xStorage, md.getAsConstPropertyValueList()); + + + const sal_Bool bOk = aMedium.Commit(); + aMedium.Close(); + if ( !bOk ) { + sal_uInt32 nError = aMedium.GetError(); + if ( nError == ERRCODE_NONE ) { + nError = ERRCODE_IO_GENERAL; + } + + throw css::task::ErrorCodeIOException( ::rtl::OUString(), + css::uno::Reference< css::uno::XInterface >(), nError); + + } +} + +// ::com::sun::star::lang::XInitialization: +void SAL_CALL +SfxDocumentMetaData::initialize( + const css::uno::Sequence< ::com::sun::star::uno::Any > & aArguments) + throw (css::uno::RuntimeException, css::uno::Exception) +{ + // possible arguments: + // - no argument: default initialization (empty DOM) + // - 1 argument, XDocument: initialize with given DOM and empty base URL + // NB: links in document must be absolute + + ::osl::MutexGuard g(m_aMutex); + css::uno::Reference<css::xml::dom::XDocument> xDoc; + + for (sal_Int32 i = 0; i < aArguments.getLength(); ++i) { + const css::uno::Any any = aArguments[i]; + if (any >>= xDoc) { + if (!xDoc.is()) { + throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("SfxDocumentMetaData::" + "initialize: argument is null"), + *this, static_cast<sal_Int16>(i)); + } + } else { + throw css::lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("SfxDocumentMetaData::" + "initialize: argument must be XDocument"), + *this, static_cast<sal_Int16>(i)); + } + } + + if (!xDoc.is()) { + // For a new document, we create a new DOM tree here. + xDoc = createDOM(); + } + + init(xDoc); +} + +// ::com::sun::star::util::XCloneable: +css::uno::Reference<css::util::XCloneable> SAL_CALL +SfxDocumentMetaData::createClone() + throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + checkInit(); + + SfxDocumentMetaData *pNew = new SfxDocumentMetaData(m_xContext); + + // NB: do not copy the modification listeners, only DOM + css::uno::Reference<css::xml::dom::XDocument> xDoc = createDOM(); + try { + updateUserDefinedAndAttributes(); + // deep copy of root node + css::uno::Reference<css::xml::dom::XNode> xRoot( + m_xDoc->getDocumentElement(), css::uno::UNO_QUERY_THROW); + css::uno::Reference<css::xml::dom::XNode> xRootNew( + xDoc->importNode(xRoot, true)); + xDoc->appendChild(xRootNew); + pNew->init(xDoc); + } catch (css::uno::RuntimeException &) { + throw; + } catch (css::uno::Exception & e) { + css::uno::Any a(e); + throw css::lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "SfxDocumentMetaData::createClone: exception"), + css::uno::Reference<css::uno::XInterface>(*this), a); + } +// return static_cast< ::cppu::OWeakObject * > (pNew); + return css::uno::Reference<css::util::XCloneable> (pNew); +} + +// ::com::sun::star::util::XModifiable: +::sal_Bool SAL_CALL SfxDocumentMetaData::isModified( ) + throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + checkInit(); + css::uno::Reference<css::util::XModifiable> xMB(m_xUserDefined, + css::uno::UNO_QUERY); + return m_isModified || (xMB.is() ? xMB->isModified() : sal_False); +} + +void SAL_CALL SfxDocumentMetaData::setModified( ::sal_Bool bModified ) + throw (css::beans::PropertyVetoException, css::uno::RuntimeException) +{ + css::uno::Reference<css::util::XModifiable> xMB; + { // do not lock mutex while notifying (#i93514#) to prevent deadlock + ::osl::MutexGuard g(m_aMutex); + checkInit(); + m_isModified = bModified; + if ( !bModified && m_xUserDefined.is() ) + { + xMB.set(m_xUserDefined, css::uno::UNO_QUERY); + DBG_ASSERT(xMB.is(), + "SfxDocumentMetaData::setModified: PropertyBag not Modifiable?"); + } + } + if (bModified) { + try { + css::uno::Reference<css::uno::XInterface> xThis(*this); + css::lang::EventObject event(xThis); + m_NotifyListeners.notifyEach(&css::util::XModifyListener::modified, + event); + } catch (css::uno::RuntimeException &) { + throw; + } catch (css::uno::Exception & e) { + // ignore + DBG_WARNING1("SfxDocumentMetaData::setModified: exception:\n%s", + OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); + (void) e; + } + } else { + if (xMB.is()) { + xMB->setModified(false); + } + } +} + +// ::com::sun::star::util::XModifyBroadcaster: +void SAL_CALL SfxDocumentMetaData::addModifyListener( + const css::uno::Reference< css::util::XModifyListener > & xListener) + throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + checkInit(); + m_NotifyListeners.addInterface(xListener); + css::uno::Reference<css::util::XModifyBroadcaster> xMB(m_xUserDefined, + css::uno::UNO_QUERY); + if (xMB.is()) { + xMB->addModifyListener(xListener); + } +} + +void SAL_CALL SfxDocumentMetaData::removeModifyListener( + const css::uno::Reference< css::util::XModifyListener > & xListener) + throw (css::uno::RuntimeException) +{ + ::osl::MutexGuard g(m_aMutex); + checkInit(); + m_NotifyListeners.removeInterface(xListener); + css::uno::Reference<css::util::XModifyBroadcaster> xMB(m_xUserDefined, + css::uno::UNO_QUERY); + if (xMB.is()) { + xMB->removeModifyListener(xListener); + } +} + +// ::com::sun::star::xml::sax::XSAXSerializable +void SAL_CALL SfxDocumentMetaData::serialize( + const css::uno::Reference<css::xml::sax::XDocumentHandler>& i_xHandler, + const css::uno::Sequence< css::beans::StringPair >& i_rNamespaces) + throw (css::uno::RuntimeException, css::xml::sax::SAXException) +{ + ::osl::MutexGuard g(m_aMutex); + checkInit(); + updateUserDefinedAndAttributes(); + css::uno::Reference<css::xml::sax::XSAXSerializable> xSAXable(m_xDoc, + css::uno::UNO_QUERY_THROW); + xSAXable->serialize(i_xHandler, i_rNamespaces); +} + +void SfxDocumentMetaData::createUserDefined() +{ + // user-defined meta data: create PropertyBag which only accepts property + // values of allowed types + if ( !m_xUserDefined.is() ) + { + css::uno::Sequence<css::uno::Type> types(11); + types[0] = ::cppu::UnoType<bool>::get(); + types[1] = ::cppu::UnoType< ::rtl::OUString>::get(); + types[2] = ::cppu::UnoType<css::util::DateTime>::get(); + types[3] = ::cppu::UnoType<css::util::Date>::get(); + types[4] = ::cppu::UnoType<css::util::Duration>::get(); + types[5] = ::cppu::UnoType<float>::get(); + types[6] = ::cppu::UnoType<double>::get(); + types[7] = ::cppu::UnoType<sal_Int16>::get(); + types[8] = ::cppu::UnoType<sal_Int32>::get(); + types[9] = ::cppu::UnoType<sal_Int64>::get(); + // Time is supported for backward compatibility with OOo 3.x, x<=2 + types[10] = ::cppu::UnoType<css::util::Time>::get(); + css::uno::Sequence<css::uno::Any> args(2); + args[0] <<= css::beans::NamedValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AllowedTypes")), + css::uno::makeAny(types)); + // #i94175#: ODF allows empty user-defined property names! + args[1] <<= css::beans::NamedValue( ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("AllowEmptyPropertyName")), + css::uno::makeAny(sal_True)); + + const css::uno::Reference<css::lang::XMultiComponentFactory> xMsf( + m_xContext->getServiceManager()); + m_xUserDefined.set( + xMsf->createInstanceWithContext( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.beans.PropertyBag")), m_xContext), + css::uno::UNO_QUERY_THROW); + const css::uno::Reference<css::lang::XInitialization> xInit( + m_xUserDefined, css::uno::UNO_QUERY); + if (xInit.is()) { + xInit->initialize(args); + } + + const css::uno::Reference<css::util::XModifyBroadcaster> xMB( + m_xUserDefined, css::uno::UNO_QUERY); + if (xMB.is()) + { + const css::uno::Sequence<css::uno::Reference<css::uno::XInterface> > + listeners(m_NotifyListeners.getElements()); + for (css::uno::Reference< css::uno::XInterface > const * iter = + ::comphelper::stl_begin(listeners); + iter != ::comphelper::stl_end(listeners); ++iter) { + xMB->addModifyListener( + css::uno::Reference< css::util::XModifyListener >(*iter, + css::uno::UNO_QUERY)); + } + } + } +} + +} // closing anonymous implementation namespace + + +// component helper namespace +namespace comp_SfxDocumentMetaData { + +::rtl::OUString SAL_CALL _getImplementationName() { + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "SfxDocumentMetaData")); +} + +css::uno::Sequence< ::rtl::OUString > SAL_CALL _getSupportedServiceNames() +{ + css::uno::Sequence< ::rtl::OUString > s(1); + s[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.document.DocumentProperties")); + return s; +} + +css::uno::Reference< css::uno::XInterface > SAL_CALL _create( + const css::uno::Reference< css::uno::XComponentContext > & context) + SAL_THROW((css::uno::Exception)) +{ + return static_cast< ::cppu::OWeakObject * > + (new SfxDocumentMetaData(context)); +} + +} // closing component helper namespace + +static ::cppu::ImplementationEntry const entries[] = { + { &comp_SfxDocumentMetaData::_create, + &comp_SfxDocumentMetaData::_getImplementationName, + &comp_SfxDocumentMetaData::_getSupportedServiceNames, + &::cppu::createSingleComponentFactory, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } +}; + +#if 0 +extern "C" void SAL_CALL component_getImplementationEnvironment( + const char ** envTypeName, uno_Environment **) +{ + *envTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + +extern "C" void * SAL_CALL component_getFactory( + const char * implName, void * serviceManager, void * registryKey) +{ + return ::cppu::component_getFactoryHelper( + implName, serviceManager, registryKey, entries); +} +#endif + diff --git a/sfx2/source/doc/applet.cxx b/sfx2/source/doc/applet.cxx new file mode 100644 index 000000000000..844eb5726b1a --- /dev/null +++ b/sfx2/source/doc/applet.cxx @@ -0,0 +1,383 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include "applet.hxx" +#include <sfx2/sfxdlg.hxx> +#include <sfx2/sfxsids.hrc> + +#include "com/sun/star/uno/XComponentContext.hpp" +#include "cppuhelper/factory.hxx" +#include <tools/urlobj.hxx> +#include <tools/debug.hxx> +#include <sj2/sjapplet.hxx> +#include <vcl/syschild.hxx> +#include <rtl/ustring.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <unotools/javaoptions.hxx> +#include <svtools/miscopt.hxx> +#include <comphelper/TypeGeneration.hxx> + +using namespace ::com::sun::star; +using namespace ::comphelper; + +namespace sfx2 +{ +class AppletWindow_Impl : public SystemChildWindow +{ +public: + SjApplet2* pApplet; + AppletWindow_Impl( Window* pParent, SjApplet2* pApp ) + : SystemChildWindow( pParent, WB_CLIPCHILDREN ) + , pApplet(pApp) + {} + + virtual void Resize(); +}; + +void AppletWindow_Impl::Resize() +{ + Size aSize( GetOutputSizePixel() ); + if ( pApplet ) + pApplet->setSizePixel( aSize ); +} + +class AppletWrapper_Impl : public SjApplet2 +{ + virtual void appletResize( const Size & ); + virtual void showDocument( const INetURLObject &, const XubString & ); + virtual void showStatus( const XubString & ); +}; + +void AppletWrapper_Impl::appletResize( const Size & ) {} +void AppletWrapper_Impl::showDocument( const INetURLObject &, const XubString & ) {} +void AppletWrapper_Impl::showStatus( const XubString & ) {} + +#define PROPERTY_UNBOUND 0 +#define PROPERTY_MAYBEVOID ::com::sun::star::beans::PropertyAttribute::MAYBEVOID + +#define WID_APPLET_CODE 1 +#define WID_APPLET_CODEBASE 2 +#define WID_APPLET_COMMANDS 3 +#define WID_APPLET_DOCBASE 4 +#define WID_APPLET_ISSCRIPT 5 +#define WID_APPLET_NAME 6 +const SfxItemPropertyMapEntry* lcl_GetAppletPropertyMap_Impl() +{ + static SfxItemPropertyMapEntry aAppletPropertyMap_Impl[] = + { + { MAP_CHAR_LEN("AppletCode") , WID_APPLET_CODE , CPPU_E2T(CPPUTYPE_OUSTRING), PROPERTY_UNBOUND, 0 }, + { MAP_CHAR_LEN("AppletCodeBase"), WID_APPLET_CODEBASE , CPPU_E2T(CPPUTYPE_OUSTRING), PROPERTY_UNBOUND, 0 }, + { MAP_CHAR_LEN("AppletCommands"), WID_APPLET_COMMANDS , CPPU_E2T(CPPUTYPE_PROPERTYVALUE), PROPERTY_UNBOUND, 0 }, + { MAP_CHAR_LEN("AppletDocBase"), WID_APPLET_DOCBASE , CPPU_E2T(CPPUTYPE_OUSTRING), PROPERTY_UNBOUND, 0 }, + { MAP_CHAR_LEN("AppletIsScript"), WID_APPLET_ISSCRIPT , CPPU_E2T(CPPUTYPE_BOOLEAN), PROPERTY_UNBOUND, 0 }, + { MAP_CHAR_LEN("AppletName") , WID_APPLET_NAME , CPPU_E2T(CPPUTYPE_OUSTRING), PROPERTY_UNBOUND, 0 }, + {0,0,0,0,0,0} + }; +return aAppletPropertyMap_Impl; +} + +::rtl::OUString AppletObject::getImplementationName() + throw( ::com::sun::star::uno::RuntimeException ) +{ + return impl_getStaticImplementationName(); +} + +::sal_Bool AppletObject::supportsService( const ::rtl::OUString& sServiceName ) + throw( ::com::sun::star::uno::RuntimeException ) +{ + ::com::sun::star::uno::Sequence< ::rtl::OUString > seqServiceNames = + getSupportedServiceNames(); + const ::rtl::OUString* pArray = seqServiceNames.getConstArray(); + for ( ::sal_Int32 nCounter=0; nCounter<seqServiceNames.getLength(); + nCounter++ ) + { + if ( pArray[nCounter] == sServiceName ) + { + return sal_True ; + } + } + return sal_False ; +} + +::com::sun::star::uno::Sequence< ::rtl::OUString > +AppletObject::getSupportedServiceNames() + throw( ::com::sun::star::uno::RuntimeException ) +{ + return impl_getStaticSupportedServiceNames(); +} + +::com::sun::star::uno::Sequence< ::rtl::OUString > +AppletObject::impl_getStaticSupportedServiceNames() +{ + ::com::sun::star::uno::Sequence< ::rtl::OUString > seqServiceNames( 1 ); + seqServiceNames.getArray() [0] = ::rtl::OUString::createFromAscii( + "com.sun.star.embed.SpecialEmbeddedObject" ); + return seqServiceNames ; +} + +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > +AppletObject::impl_createInstance( + const ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext >& xContext ) + throw( ::com::sun::star::uno::Exception ) +{ + return static_cast< ::cppu::OWeakObject * >( new AppletObject( xContext ) ); +} + +::rtl::OUString AppletObject::impl_getStaticImplementationName() +{ + return ::rtl::OUString::createFromAscii( + "com.sun.star.comp.sfx2.AppletObject" ); +} + +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > +AppletObject::impl_createFactory() +{ + return uno::Reference< uno::XInterface >( + cppu::createSingleComponentFactory( + impl_createInstance, impl_getStaticImplementationName(), + impl_getStaticSupportedServiceNames() ), + uno::UNO_QUERY_THROW ); +} + +AppletObject::AppletObject( + const uno::Reference < uno::XComponentContext >& rContext ) + : mxContext( rContext ) + , maPropMap( lcl_GetAppletPropertyMap_Impl() ) + , mpApplet( NULL ) + , mbMayScript( FALSE ) +{ +} + +AppletObject::~AppletObject() +{ +} + +void SAL_CALL AppletObject::initialize( const uno::Sequence< uno::Any >& aArguments ) throw ( uno::Exception, uno::RuntimeException ) +{ + if ( aArguments.getLength() ) + aArguments[0] >>= mxObj; +} + +sal_Bool SAL_CALL AppletObject::load( + const uno::Sequence < com::sun::star::beans::PropertyValue >& /*lDescriptor*/, + const uno::Reference < frame::XFrame >& xFrame ) +throw( uno::RuntimeException ) +{ + if ( SvtJavaOptions().IsExecuteApplets() && SvtMiscOptions().IsPluginsEnabled() ) + { + mpApplet = new AppletWrapper_Impl; + + Window* pParent = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() ); + Window* pWin = new AppletWindow_Impl( pParent, mpApplet ); + pWin->SetBackground(); + pWin->Show(); + + // aCmdList.Append( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "width" ) ), String( aPosSize.GetWidth() ) ); + // aCmdList.Append( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "height" ) ), String( aPosSize.GetHeight() ) ); + + if( maName.getLength() ) + maCmdList.Append( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "name" ) ), maName ); + + if( maCodeBase.getLength() ) + { + for ( sal_uInt32 nParams=0; nParams<maCmdList.Count(); nParams++ ) + { + if ( maCmdList[nParams].GetCommand().EqualsAscii("codebase") ) + { + maCmdList.Remove(nParams); + break; + } + } + + maCmdList.Append( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "codebase" ) ), maCodeBase ); + } + + if( maClass.getLength() ) + maCmdList.Append( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "code" ) ), maClass ); + + if( mbMayScript ) + maCmdList.Append( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "mayscript" ) ), String() ); + + INetURLObject aDocBase( maDocBase ); + mpApplet->Init( mxContext, pWin, aDocBase, maCmdList ); + uno::Reference < awt::XWindow > xWindow( pWin->GetComponentInterface(), uno::UNO_QUERY ); + + // we must destroy the applet before the parent is destroyed + xWindow->addEventListener( this ); + + xFrame->setComponent( xWindow, uno::Reference < frame::XController >() ); + return TRUE; + } + + return FALSE; +} + +void SAL_CALL AppletObject::cancel() throw( com::sun::star::uno::RuntimeException ) +{ + if ( mpApplet ) + { + mpApplet->appletClose(); // reparenting window + DELETEZ( mpApplet ); + } +} + +void SAL_CALL AppletObject::close( sal_Bool /*bDeliverOwnership*/ ) throw( com::sun::star::util::CloseVetoException, com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL AppletObject::addCloseListener( const com::sun::star::uno::Reference < com::sun::star::util::XCloseListener >& ) throw( com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL AppletObject::removeCloseListener( const com::sun::star::uno::Reference < com::sun::star::util::XCloseListener >& ) throw( com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL AppletObject::disposing( const com::sun::star::lang::EventObject& ) throw (com::sun::star::uno::RuntimeException) +{ + cancel(); +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL AppletObject::getPropertySetInfo() throw( ::com::sun::star::uno::RuntimeException ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo = new SfxItemPropertySetInfo( &maPropMap ); + return xInfo; +} + +void SAL_CALL AppletObject::setPropertyValue(const ::rtl::OUString& aPropertyName, const uno::Any& aAny) + throw ( beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException) +{ + + const SfxItemPropertySimpleEntry* pEntry = maPropMap.getByName( aPropertyName ); + if( !pEntry ) + throw beans::UnknownPropertyException(); + switch( pEntry->nWID ) + { + case WID_APPLET_CODE : + aAny >>= maClass; + break; + case WID_APPLET_CODEBASE : + //pImpl->aCodeBase = rURL.GetMainURL( INetURLObject::NO_DECODE ); + //if( rURL.GetProtocol() == INET_PROT_FILE + // && pImpl->aCodeBase.GetChar( 9 ) == INET_ENC_DELIM_TOKEN ) + // // Laufwerksbuchstabe auf ':' patchen + // pImpl->aCodeBase.SetChar( 9, INET_DELIM_TOKEN ); + + aAny >>= maCodeBase; + break; + case WID_APPLET_COMMANDS : + { + maCmdList.Clear(); + uno::Sequence < beans::PropertyValue > aCommandSequence; + if( aAny >>= aCommandSequence ) + maCmdList.FillFromSequence( aCommandSequence ); + } + break; + case WID_APPLET_DOCBASE : + aAny >>= maDocBase; + break; + case WID_APPLET_ISSCRIPT : + aAny >>= mbMayScript; + break; + case WID_APPLET_NAME : + aAny >>= maName; + break; + default:; + + } +} + +uno::Any SAL_CALL AppletObject::getPropertyValue(const ::rtl::OUString& aPropertyName) throw ( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + uno::Any aAny; + const SfxItemPropertySimpleEntry* pEntry = maPropMap.getByName( aPropertyName ); + if( !pEntry ) + throw beans::UnknownPropertyException(); + switch( pEntry->nWID ) + { + case WID_APPLET_CODE : + aAny <<= maClass; + break; + case WID_APPLET_CODEBASE : + aAny <<= maCodeBase; + break; + case WID_APPLET_COMMANDS : + { + uno::Sequence< beans::PropertyValue > aCommandSequence; + maCmdList.FillSequence( aCommandSequence ); + aAny <<= aCommandSequence; + } + break; + case WID_APPLET_DOCBASE : + break; + case WID_APPLET_ISSCRIPT : + aAny <<= mbMayScript; + break; + case WID_APPLET_NAME : + aAny <<= maName; + break; + default:; + + } + return aAny; +} + +void SAL_CALL AppletObject::addPropertyChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL AppletObject::removePropertyChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL AppletObject::addVetoableChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL AppletObject::removeVetoableChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException ) +{ +} + +::sal_Int16 SAL_CALL AppletObject::execute() throw (::com::sun::star::uno::RuntimeException) +{ + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + uno::Reference < beans::XPropertySet > xSet( this ); + VclAbstractDialog* pDlg = pFact->CreateEditObjectDialog( NULL, SID_INSERT_APPLET, mxObj ); + if ( pDlg ) + pDlg->Execute(); + return 0; +} + +void SAL_CALL AppletObject::setTitle( const ::rtl::OUString& ) throw (::com::sun::star::uno::RuntimeException) +{ +} + +} diff --git a/sfx2/source/doc/doc.hrc b/sfx2/source/doc/doc.hrc new file mode 100644 index 000000000000..838168e64526 --- /dev/null +++ b/sfx2/source/doc/doc.hrc @@ -0,0 +1,222 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _SFX_DOC_HRC +#define _SFX_DOC_HRC + +#include <sfx2/sfx.hrc> + +// #defines ***************************************************************** + +#define RID_SFX_DOC_END (RID_SFX_DIALOG_START-1) + +#define STR_NODEFPRINTER (RID_SFX_DOC_START+ 0) +#define STR_PRINTER_NOTAVAIL_1 (RID_SFX_DOC_START+ 1) +#define STR_PRINTER_NOTAVAIL_2 (RID_SFX_DOC_START+ 2) +#define STR_PRINTER_NOTAVAIL_3 (RID_SFX_DOC_START+ 3) +#define STR_PRINTER_NOTAVAIL_4 (RID_SFX_DOC_START+ 4) +#define STR_PRINTER_NOTAVAIL_5 (RID_SFX_DOC_START+ 5) +#define STR_PRINT_OPTIONS (RID_SFX_DOC_START+ 6) +#define STR_ERROR_PRINTER_BUSY (RID_SFX_DOC_START+ 7) +#define STR_NOSTARTPRINTER (RID_SFX_DOC_START+ 8) +#define MSG_CONFIRM_FILTER (RID_SFX_DOC_START+11) +#define MSG_CONFIRM_OVERWRITE_TEMPLATE (RID_SFX_DOC_START+12) +#define MSG_QUERY_LOAD_TEMPLATE (RID_SFX_DOC_START+13) + +#define STR_DELETE_REGION (RID_SFX_DOC_START+14) +#define STR_DELETE_TEMPLATE (RID_SFX_DOC_START+15) +#define MSG_REGION_NOTEMPTY (RID_SFX_DOC_START+17) + +#define DLG_NEW_FILE (RID_SFX_DOC_START+1) +#define DLG_DOC_TEMPLATE (RID_SFX_DOC_START+2) +#define DLG_ORGANIZE (RID_SFX_DOC_START+3) + +#define BMP_STYLES_CLOSED (RID_SFX_DOC_START+ 0) +#define BMP_STYLES_OPENED (RID_SFX_DOC_START+ 1) + +#define BMP_STYLES_FAMILY1 (RID_SFX_DOC_START+ 2) +#define BMP_STYLES_FAMILY2 (RID_SFX_DOC_START+ 3) +#define BMP_STYLES_FAMILY3 (RID_SFX_DOC_START+ 4) +#define BMP_STYLES_FAMILY4 (RID_SFX_DOC_START+ 5) + +#define BMP_STYLES_CLOSED_HC (RID_SFX_DOC_START+ 6) +#define BMP_STYLES_OPENED_HC (RID_SFX_DOC_START+ 7) + +#define BMP_STYLES_FAMILY1_HC (RID_SFX_DOC_START+ 8) +#define BMP_STYLES_FAMILY2_HC (RID_SFX_DOC_START+ 9) +#define BMP_STYLES_FAMILY3_HC (RID_SFX_DOC_START+ 10) +#define BMP_STYLES_FAMILY4_HC (RID_SFX_DOC_START+ 11) + +#define STR_STYLES (RID_SFX_DOC_START+ 18) +#define STR_MACROS (RID_SFX_DOC_START+ 19) + +#define STR_PRINT_STYLES (RID_SFX_DOC_START+ 20) +#define STR_PRINT_STYLES_HEADER (RID_SFX_DOC_START+ 21) +#define MSG_PRINT_ERROR (RID_SFX_DOC_START+ 22) +#define STR_BACKUP_COPY (RID_SFX_DOC_START+ 23) +// #define MSG_WARNING_BACKUP (RID_SFX_DOC_START+ 24) +#define MSG_CANT_OPEN_TEMPLATE (RID_SFX_DOC_START+ 25) +#define MSG_VIEW_OPEN_CANT_SAVE (RID_SFX_DOC_START+ 26) +#define STR_ERROR_SAVE (RID_SFX_DOC_START+ 27) +#define STR_TEMPLATE_FILTER (RID_SFX_DOC_START+ 28) +#define STR_ERROR_COPY_TEMPLATE (RID_SFX_DOC_START+ 29) + +#define STR_ERROR_DELETE_TEMPLATE (RID_SFX_DOC_START+ 30) +#define STR_ERROR_MOVE_TEMPLATE (RID_SFX_DOC_START+ 32) +#define MSG_ERROR_RESCAN (RID_SFX_DOC_START+ 33) +#define STR_ERROR_SAVE_TEMPLATE (RID_SFX_DOC_START+ 34) +#define MSG_ERROR_RENAME_TEMPLATE (RID_SFX_DOC_START+ 34) +#define MSG_ERROR_RENAME_TEMPLATE_REGION (RID_SFX_DOC_START+ 35) +#define STR_CONFIG (RID_SFX_DOC_START+ 37) +#define MSG_ERROR_EMPTY_NAME (RID_SFX_DOC_START+ 37) +#define MSG_ERROR_UNIQ_NAME (RID_SFX_DOC_START+ 38) +#define STR_QUERY_DEFAULT_TEMPLATE (RID_SFX_DOC_START+ 39) +#define MSG_QUERY_RESET_DEFAULT_TEMPLATE (RID_SFX_DOC_START+ 39) +#define MSG_TEMPLATE_DIR_NOT_EXIST (RID_SFX_DOC_START+ 40) +#define MSG_DOCINFO_CANTREAD (RID_SFX_DOC_START+ 41) +#define STR_ERROR_NOSTORAGE (RID_SFX_DOC_START+ 42) +// #define STR_QUERY_SAVEOWNFORMAT (RID_SFX_DOC_START+ 43) +#define STR_QUERY_MUSTOWNFORMAT (RID_SFX_DOC_START+ 44) +#define STR_SAVEDOC (RID_SFX_DOC_START+ 45) +#define STR_UPDATEDOC (RID_SFX_DOC_START+ 46) +#define STR_SAVEASDOC (RID_SFX_DOC_START+ 47) +#define STR_SAVECOPYDOC (RID_SFX_DOC_START+ 48) +#define STR_CLOSEDOC (RID_SFX_DOC_START+ 49) +#define STR_CLOSEDOC_ANDRETURN (RID_SFX_DOC_START+ 50) +#define STR_WIZARD (RID_SFX_DOC_START+ 51) +#define RID_STR_FILTCONFIG (RID_SFX_DOC_START+ 52) +#define RID_STR_FILTBASIC (RID_SFX_DOC_START+ 53) +#define RID_STR_WARNSTYLEOVERWRITE (RID_SFX_DOC_START+ 54) +#define RID_DLSTATUS (RID_SFX_DOC_START+ 55) + +#define STR_DOC_LOADING (RID_SFX_DOC_START+ 57) +#define MSG_OPEN_READONLY (RID_SFX_DOC_START+ 58) + +#define RID_OFFICEFILTER (RID_SFX_DOC_START+ 59) +#define RID_OFFICEFILTER_WILDCARD (RID_SFX_DOC_START+ 60) +#define RID_OFFICEFILTER_MACTYPE (RID_SFX_DOC_START+ 61) +#define RID_OFFICEFILTER_OS2TYPE (RID_SFX_DOC_START+ 62) +#define STR_FRAMEOBJECT_PROPERTIES (RID_SFX_DOC_START+ 63) + +#define STR_FSET_FILTERNAME0 (RID_SFX_DOC_START+ 64) +#define STR_FSET_FILTERNAME1 (RID_SFX_DOC_START+ 65) + +#define STR_TEMPL_MOVED (RID_SFX_DOC_START+ 66) +#define STR_TEMPL_RESET (RID_SFX_DOC_START+ 67) +#define STR_AUTOMATICVERSION (RID_SFX_DOC_START+ 68) + +#define STR_DOCTYPENAME_SW (RID_SFX_DOC_START+ 69) +#define STR_DOCTYPENAME_SWWEB (RID_SFX_DOC_START+ 70) +#define STR_DOCTYPENAME_SWGLOB (RID_SFX_DOC_START+ 71) +#define STR_DOCTYPENAME_SC (RID_SFX_DOC_START+ 72) +#define STR_DOCTYPENAME_SI (RID_SFX_DOC_START+ 73) +#define STR_DOCTYPENAME_SD (RID_SFX_DOC_START+ 74) +#define STR_DOCTYPENAME_MESSAGE (RID_SFX_DOC_START+ 75) +#define RID_STR_NEW_TASK (RID_SFX_DOC_START+ 76) + +#define STR_SAVEANDCLOSE (RID_SFX_DOC_START+ 77) +#define STR_NOSAVEANDCLOSE (RID_SFX_DOC_START+ 78) +#define STR_PACKNGO_NOACCESS (RID_SFX_DOC_START+ 79) +#define STR_PACKNGO_NEWMEDIUM (RID_SFX_DOC_START+ 80) + +#define TEMPLATE_LONG_NAMES_ARY (RID_SFX_DOC_START+ 81) +#define TEMPLATE_SHORT_NAMES_ARY (RID_SFX_DOC_START+ 82) +#define RID_CNT_STR_WAITING (RID_SFX_DOC_START+ 83) + +#define STR_OBJECT (RID_SFX_DOC_START+ 84) +#define STR_EDITOBJECT (RID_SFX_DOC_START+ 85) +// --> PB 2004-08-20 #i33095# +/* obsolete +#define STR_OPENOBJECT (RID_SFX_DOC_START+ 86) +*/ + +#define DLOAD_URL 1 +#define DLOAD_STATUS 2 +#define DLOAD_NAME 3 +#define DLOAD_TEXT 4 +#define DLOAD_CANCEL 1 + +#define DLG_MACROQUERY (RID_SFX_DOC_START+87) +#define BTN_OK (RID_SFX_DOC_START+88) +#define BTN_CANCEL (RID_SFX_DOC_START+89) +#define FT_OK (RID_SFX_DOC_START+90) +#define FT_CANCEL (RID_SFX_DOC_START+91) + +#define STR_EXPORTASPDF_TITLE (RID_SFX_DOC_START+92) +#define STR_EXPORTBUTTON (RID_SFX_DOC_START+93) +#define STR_EXPORTWITHCFGBUTTON (RID_SFX_DOC_START+94) + +#define RID_SVXSTR_SECURITY_ADDPATH (RID_SFX_DOC_START+95) + +#define STR_LABEL_FILEFORMAT (RID_SFX_DOC_START+96) + +// some icons are commented out since they are removed +#define BMP_SIGNATURE (RID_SFX_DOC_START+97) +// #define BMP_128X128_BASE_DOC (RID_SFX_DOC_START+98) +#define BMP_128X128_CALC_DOC (RID_SFX_DOC_START+99) +// #define BMP_128X128_CALC_TEMP (RID_SFX_DOC_START+100) +#define BMP_128X128_CHART_DOC (RID_SFX_DOC_START+101) +#define BMP_128X128_DRAW_DOC (RID_SFX_DOC_START+102) +// #define BMP_128X128_DRAW_TEMP (RID_SFX_DOC_START+103) +#define BMP_128X128_IMPRESS_DOC (RID_SFX_DOC_START+104) +// #define BMP_128X128_IMPRESS_TEMP (RID_SFX_DOC_START+105) +// #define BMP_128X128_MASTER_DOC (RID_SFX_DOC_START+106) +#define BMP_128X128_MATH_DOC (RID_SFX_DOC_START+107) +#define BMP_128X128_WRITER_DOC (RID_SFX_DOC_START+108) +// #define BMP_128X128_WRITER_TEMP (RID_SFX_DOC_START+109) + +#define STR_HIDDENINFO_CONTAINS (RID_SFX_DOC_START+110) +#define STR_HIDDENINFO_RECORDCHANGES (RID_SFX_DOC_START+111) +#define STR_HIDDENINFO_NOTES (RID_SFX_DOC_START+112) +#define STR_HIDDENINFO_DOCVERSIONS (RID_SFX_DOC_START+113) +#define STR_HIDDENINFO_FIELDS (RID_SFX_DOC_START+114) +#define STR_HIDDENINFO_LINKDATA (RID_SFX_DOC_START+115) +#define STR_HIDDENINFO_CONTINUE_SAVING (RID_SFX_DOC_START+116) +#define STR_HIDDENINFO_CONTINUE_PRINTING (RID_SFX_DOC_START+117) +#define STR_HIDDENINFO_CONTINUE_SIGNING (RID_SFX_DOC_START+118) +#define STR_HIDDENINFO_CONTINUE_CREATEPDF (RID_SFX_DOC_START+119) + +// #define MSG_WARNING_MACRO_ISDISABLED (RID_SFX_DOC_START+120) +#define STR_NEW_FILENAME_SAVE (RID_SFX_DOC_START+121) +// #define STR_MACROS_DISABLED (RID_SFX_DOC_START+122) +#define STR_ERROR_DELETE_TEMPLATE_DIR (RID_SFX_DOC_START+123) +#define STR_DOCINFO_INFOFIELD (RID_SFX_DOC_START+124) + +#define MSG_XMLSEC_QUERY_SAVESIGNEDBEFORESIGN (RID_SFX_DOC_START+125) +#define STR_XMLSEC_ODF12_EXPECTED (RID_SFX_DOC_START+126) + +#define STR_QRYTEMPL_MESSAGE (RID_SFX_DOC_START+127) +#define STR_QRYTEMPL_UPDATE_BTN (RID_SFX_DOC_START+128) +#define STR_QRYTEMPL_KEEP_BTN (RID_SFX_DOC_START+129) + +// please update to the last id +#define ACT_SFX_DOC_END STR_QRYTEMPL_KEEP_BTN +#if ACT_SFX_DOC_END > RID_SFX_DOC_END +#error resource overflow in #line, #file +#endif + +#endif + diff --git a/sfx2/source/doc/doc.src b/sfx2/source/doc/doc.src new file mode 100644 index 000000000000..d17b62c9b52a --- /dev/null +++ b/sfx2/source/doc/doc.src @@ -0,0 +1,536 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include <sfx2/sfx.hrc> +#include "doc.hrc" +#define __RSC +#include <svl/inetdef.hxx> +//#include <so3/so2defs.hxx> + + // ----------------------------------------------------------------------- +QueryBox MSG_CONFIRM_FILTER +{ + Buttons = WB_YES_NO ; + DefButton = WB_DEF_YES ; + Message [ en-US ] = "Saving in external formats may have caused\n information loss. Do you still want to close?" ; +}; +QueryBox MSG_CONFIRM_OVERWRITE_TEMPLATE +{ + Buttons = WB_YES_NO ; + DefButton = WB_DEF_NO ; + Message [ en-US ] = "Name already in use.\nDo you want to overwrite document template?" ; +}; +QueryBox MSG_QUERY_LOAD_TEMPLATE +{ + BUTTONS = WB_YES_NO ; + DEFBUTTON = WB_DEF_NO ; + HelpId = MSG_QUERY_LOAD_TEMPLATE; + + Message [ en-US ] = "The Styles in this document do not match your current Styles. Should your current Styles be applied to this document?"; +}; +String STR_DELETE_REGION +{ + Text [ en-US ] = "Are you sure you want to delete the region \"$1\"?" ; +}; +String STR_DELETE_TEMPLATE +{ + Text [ en-US ] = "Are you sure you want to delete the entry \"$1\"?" ; +}; +QueryBox MSG_REGION_NOTEMPTY +{ + Buttons = WB_YES_NO ; + DefButton = WB_DEF_NO ; + Message [ en-US ] = "The category is not empty.\nDelete anyway?" ; +}; +String STR_QUERY_SAVE_DOCUMENT +{ + Text [ en-US ] = "The document \"$(DOC)\" has been modified.\nDo you want to save your changes?" ; +}; +Bitmap BMP_STYLES_CLOSED { File = "newex.bmp" ; }; +Bitmap BMP_STYLES_OPENED { File = "newex.bmp" ; }; + +Bitmap BMP_STYLES_CLOSED_HC { File = "newex_h.bmp" ; }; +Bitmap BMP_STYLES_OPENED_HC { File = "newex_h.bmp" ; }; + +String STR_STYLES +{ + Text [ en-US ] = "Styles" ; +}; +String STR_MACROS +{ + Text [ en-US ] = "Macros" ; +}; +String STR_CONFIG +{ + Text [ en-US ] = "Configuration" ; +}; +String STR_PRINT_STYLES_HEADER +{ + Text [ en-US ] = "Styles in " ; +}; +String STR_PRINT_STYLES +{ + Text [ en-US ] = "Printing Styles" ; +}; +Bitmap BMP_STYLES_FAMILY1 { File = "styfam1.bmp" ; }; +Bitmap BMP_STYLES_FAMILY2 { File = "styfam2.bmp" ; }; +Bitmap BMP_STYLES_FAMILY3 { File = "styfam3.bmp" ; }; +Bitmap BMP_STYLES_FAMILY4 { File = "styfam4.bmp" ; }; + +Bitmap BMP_STYLES_FAMILY1_HC { File = "styfam1_h.bmp" ; }; +Bitmap BMP_STYLES_FAMILY2_HC { File = "styfam2_h.bmp" ; }; +Bitmap BMP_STYLES_FAMILY3_HC { File = "styfam3_h.bmp" ; }; +Bitmap BMP_STYLES_FAMILY4_HC { File = "styfam4_h.bmp" ; }; + +ErrorBox MSG_PRINT_ERROR +{ + BUTTONS = WB_OK ; + DEFBUTTON = WB_DEF_OK ; + Message [ en-US ] = "The print job could not be started." ; +}; +String STR_BACKUP_COPY +{ + Text [ en-US ] = "Copy" ; +}; +InfoBox MSG_CANT_OPEN_TEMPLATE +{ + Message [ en-US ] = "The template could not be opened." ; +}; +InfoBox MSG_VIEW_OPEN_CANT_SAVE +{ + BUTTONS = WB_OK ; + DEFBUTTON = WB_DEF_OK ; + Message [ en-US ] = "Document already open for editing." ; +}; +String STR_ERROR_SAVE +{ + Text [ en-US ] = "Error recording document " ; +}; +String STR_TEMPLATE_FILTER +{ + Text [ en-US ] = "Templates" ; +}; +String STR_ERROR_COPY_TEMPLATE +{ + Text [ en-US ] = "Error copying template \"$1\". \nA template with this name may already exist." ; +}; +String STR_ERROR_DELETE_TEMPLATE +{ + Text [ en-US ] = "The template \"$1\" can not be deleted." ; +}; +String STR_ERROR_MOVE_TEMPLATE +{ + Text [ en-US ] = "Error moving template \"$1\"." ; +}; +ErrorBox MSG_ERROR_RESCAN +{ + BUTTONS = WB_OK ; + DEFBUTTON = WB_DEF_OK ; + Message [ en-US ] = "The update could not be saved." ; +}; +String STR_ERROR_SAVE_TEMPLATE +{ + Text [ en-US ] = "Error saving template " ; +}; +ErrorBox MSG_ERROR_RENAME_TEMPLATE +{ + BUTTONS = WB_OK ; + DEFBUTTON = WB_DEF_OK ; + Message [ en-US ] = "Error renaming template." ; +}; +ErrorBox MSG_ERROR_RENAME_TEMPLATE_REGION +{ + BUTTONS = WB_OK ; + DEFBUTTON = WB_DEF_OK ; + Message [ en-US ] = "Error renaming template category." ; +}; +ErrorBox MSG_ERROR_EMPTY_NAME +{ + BUTTONS = WB_OK ; + DEFBUTTON = WB_DEF_OK ; + Message [ en-US ] = "Please specify a name." ; +}; +ErrorBox MSG_ERROR_UNIQ_NAME +{ + BUTTONS = WB_OK ; + DEFBUTTON = WB_DEF_OK ; + Message [ en-US ] = "Please specify a unique name.\nEntries must not be case specific." ; +}; +String STR_QUERY_DEFAULT_TEMPLATE +{ + Text [ en-US ] = "Should the template \"$(TEXT)\" become the default template?" ; +}; +QueryBox MSG_QUERY_RESET_DEFAULT_TEMPLATE +{ + Buttons = WB_YES_NO ; + DefButton = WB_DEF_NO ; + Message [ en-US ] = "Do you want to reset the default template?" ; +}; +InfoBox MSG_TEMPLATE_DIR_NOT_EXIST +{ + Message [ en-US ] = "Template directory\n$(DIR)\ndoes not exist." ; +}; +InfoBox MSG_DOCINFO_CANTREAD +{ + Message [ en-US ] = "Document info cannot be read." ; +}; +String STR_ERROR_NOSTORAGE +{ + /* ### ACHTUNG: Neuer Text in Resource? Die ausgew�hlte Datei besitzt ein falsches Format. : Die ausgew�hlte Datei besitzt ein falsches Format. */ + /* ### ACHTUNG: Neuer Text in Resource? Die ausgew�hlte Datei besitzt ein falsches Format. : Die ausgew�hlte Datei besitzt ein falsches Format. */ + Text [ en-US ] = "The selected file has an incorrect format." ; +}; +String STR_QUERY_MUSTOWNFORMAT +{ + Text [ en-US ] = "Documents cannot be saved in $(FORMAT) format. Do you\nwant to save your changes using the $(OWNFORMAT) format?" ; +}; +String STR_SAVEDOC +{ + Text [ en-US ] = "~Save" ; +}; +String STR_UPDATEDOC +{ + Text [ en-US ] = "~Update" ; +}; +String STR_SAVEASDOC +{ + Text [ en-US ] = "Save ~As..." ; +}; +String STR_SAVECOPYDOC +{ + Text [ en-US ] = "Save Copy ~as..." ; +}; +String STR_CLOSEDOC +{ + Text [ en-US ] = "~Close" ; +}; +String STR_CLOSEDOC_ANDRETURN +{ + /* ### ACHTUNG: Neuer Text in Resource? S~chlie�en & zur�ck zu : S~chlie�en & zur�ck zu */ + /* ### ACHTUNG: Neuer Text in Resource? S~chlie�en & zur�ck zu : S~chlie�en & zur�ck zu */ + Text [ en-US ] = "~Close & Return to " ; +}; +String STR_WIZARD +{ + Text [ en-US ] = " AutoPilot" ; +}; +String RID_STR_FILTCONFIG +{ + Text [ en-US ] = "Configurations" ; +}; +String RID_STR_FILTBASIC +{ + Text [ en-US ] = "%PRODUCTNAME Basic libraries" ; +}; +String RID_STR_WARNSTYLEOVERWRITE +{ + Text [ en-US ] = "Should the \"$(ARG1)\" Style be replaced?" ; +}; +String STR_DOC_LOADING +{ + Text [ en-US ] = "Loading Document" ; +}; +Resource RID_DLSTATUS +{ + String INET_NAME_RESOLVE_START + { + Text [ en-US ] = "Connection to: $(HOST). Waiting for response..." ; + }; + String INET_CONNECT_START + { + Text [ en-US ] = "Opening $(TARGET) at $(HOST)" ; + }; + String INET_READ_STATUS + { + Text [ en-US ] = "Loading: $(TARGET) from $(HOST). Loaded: $(BYTE)" ; + }; + String INET_CONNECTION_CLOSED + { + Text [ en-US ] = "Disconnected" ; + }; +}; +QueryBox MSG_OPEN_READONLY +{ + BUTTONS = WB_YES_NO ; + DEFBUTTON = WB_DEF_YES ; + Message [ en-US ] = "Document cannot be opened for editing.\nDo you want to open it as read-only?" ; +}; +String STR_EDIT +{ + Text [ en-US ] = "Edit" ; +}; +String RID_OFFICEFILTER +{ + Text [ en-US ] = "%PRODUCTNAME Documents" ; +}; +String RID_OFFICEFILTER_WILDCARD +{ + Text = "*.sdw;*.sdd;*.sda;*.sdc;*.smf;*.sds;*.sd;*.sdm;*.smd" ; +}; +String RID_OFFICEFILTER_MACTYPE +{ + Text = "SVsd0;SW/\2510;SVsc0;SVsm0;SVsh0;SVsd1;SW/\2511;SVsc1;SVsm1;SVsh1;MAIL" ; +}; +String RID_OFFICEFILTER_OS2TYPE +{ + Text = "StarWriter 4.0;StarWriter 3.0;StarDraw 4.0;StarDraw 3.0;StarCalc 4.0;StarCalc 3.0;StarMath 4.0;StarMath 3.0;StarChart 4.0;StarChart 3.0;StarFrameSet;StarMessage" ; +}; +String STR_FRAMEOBJECT_PROPERTIES +{ + Text [ en-US ] = "Propert~ies..." ; +}; +String STR_FSET_FILTERNAME0 +{ + Text [ en-US ] = "HTML (FrameSet)" ; +}; +String STR_FSET_FILTERNAME1 +{ + // nur 'Dokument' "ubersetzen - only translate 'Document' + Text [ en-US ] = "%PRODUCTNAME Frame Document" ; +}; +String STR_TEMPL_MOVED +{ + Text [ en-US ] = "The template \"$(TEMPLATE)\" was not found at the original location. A template with the same name exists at \"$(FOUND)\". Should this template be used in the future when comparing?" ; +}; +String STR_TEMPL_RESET +{ + Text [ en-US ] = "The template \"$(TEMPLATE)\" has not been found. Should the template be looked for the next time the document is opened ?" ; +}; +String STR_AUTOMATICVERSION +{ + Text [ en-US ] = "Automatically saved version" ; +}; + +String STR_DOCTYPENAME_SW +{ + Text [ en-US ] = "Text Document"; +}; + +String STR_DOCTYPENAME_SWWEB +{ + Text [ en-US ] = "HTML Document"; +}; + +String STR_DOCTYPENAME_SWGLOB +{ + Text [ en-US ] = "Master Document"; +}; + +String STR_DOCTYPENAME_SC +{ + Text [ en-US ] = "Spreadsheet"; +}; + +String STR_DOCTYPENAME_SI +{ + Text [ en-US ] = "Presentation"; +}; + +String STR_DOCTYPENAME_SD +{ + Text [ en-US ] = "Drawing"; +}; + +String STR_DOCTYPENAME_MESSAGE +{ + Text [ en-US ] = "Message"; +}; + +String STR_NOSAVEANDCLOSE +{ + Text [ en-US ] = "~Discard" ; +}; + +String STR_PACKNGO_NOACCESS +{ + Text [ en-US ] = "Access to the current data medium not possible." ; +}; + +String STR_PACKNGO_NEWMEDIUM +{ + Text [ en-US ] = "Insert the next data carrier and click OK." ; +}; + +String STR_OBJECT +{ + Text [ en-US ] = "Object" ; +}; + +String STR_EDITOBJECT +{ + Text [ en-US ] = "~Edit"; +}; + +// --> PB 2004-08-20 #i33095# +/* obsolete +String STR_OPENOBJECT +{ + Text [ en-US ] = "~Open"; +}; +*/ + +QueryBox DLG_MACROQUERY +{ + Buttons = WB_OK_CANCEL; + Title [ en-US ] = "Run Macro" ; + + Message [ en-US ] = "This document contains macros. $(TEXT)"; +}; + +String BTN_OK +{ + Text [ en-US ] = "Run" ; +}; +String BTN_CANCEL +{ + Text [ en-US ] = "Do Not Run" ; +}; +String FT_CANCEL +{ + Text [ en-US ] = "According to the security settings, the macros in this document should not be run. Do you want to run them anyway?"; +}; +String FT_OK +{ + Text [ en-US ] = "Do you want to allow these macros to be run?"; +}; + +String STR_EXPORTASPDF_TITLE +{ + Text [ en-US ] = "Export as PDF"; +}; + +String STR_EXPORTWITHCFGBUTTON +{ + Text [ en-US ] = "Export..."; +}; + +String STR_EXPORTBUTTON +{ + Text [ en-US ] = "Export" ; +}; + +String RID_SVXSTR_SECURITY_ADDPATH +{ + Text [ en-US ] = "Add this directory to the list of secure paths: " ; +}; + +String STR_LABEL_FILEFORMAT +{ + Text [ en-US ] = "File format:" ; +}; + +String STR_HIDDENINFO_CONTAINS +{ + Text [ en-US ] = "This document contains:\n\n" ; +}; +String STR_HIDDENINFO_RECORDCHANGES +{ + Text [ en-US ] = "Recorded changes" ; +}; +String STR_HIDDENINFO_NOTES +{ + Text [ en-US ] = "Notes" ; +}; +String STR_HIDDENINFO_DOCVERSIONS +{ + Text [ en-US ] = "Document versions" ; +}; +String STR_HIDDENINFO_FIELDS +{ + Text [ en-US ] = "Fields" ; +}; +String STR_HIDDENINFO_LINKDATA +{ + Text [ en-US ] = "Linked data..." ; +}; +String STR_HIDDENINFO_CONTINUE_SAVING +{ + Text [ en-US ] = "Do you want to continue saving the document?" ; +}; +String STR_HIDDENINFO_CONTINUE_PRINTING +{ + Text [ en-US ] = "Do you want to continue printing the document?" ; +}; +String STR_HIDDENINFO_CONTINUE_SIGNING +{ + Text [ en-US ] = "Do you want to continue signing the document?" ; +}; +String STR_HIDDENINFO_CONTINUE_CREATEPDF +{ + Text [ en-US ] = "Do you want to continue creating a PDF file?" ; +}; + +String STR_NEW_FILENAME_SAVE +{ + Text [ en-US ] = "If you do not want to overwrite the original document, you should save your work under a new filename." ; +}; + +String STR_ERROR_DELETE_TEMPLATE_DIR +{ + Text [ en-US ] = "Some template files are protected and can not be deleted."; +}; + +String STR_DOCINFO_INFOFIELD +{ + Text [ en-US ] = "Info %1"; + Text [ x-comment ] = "pb: %1 == a number [1-4]"; +}; + +String STR_SHARED +{ + Text [ en-US ] = " (shared)"; + Text [ x-comment ] = "Used in the title of a shared document."; +}; + +String STR_XMLSEC_ODF12_EXPECTED +{ + Text [ en-US ] = "The document format version is set to ODF 1.1 (OpenOffice.org 2.x) in Tools-Options-Load/Save-General. Signing documents requires ODF 1.2 (OpenOffice.org 3.x)."; +}; + +QueryBox MSG_XMLSEC_QUERY_SAVESIGNEDBEFORESIGN +{ + Buttons = WB_YES_NO ; + DefButton = WB_DEF_YES ; + Message [ en-US ] = "The document has to be saved before it can be signed. Saving the document removes all present signatures.\nDo you want to save the document?"; +}; + +String STR_QRYTEMPL_MESSAGE +{ + Text [ en-US ] = "The template '$(ARG1)' on which this document is based, has been modified. Do you want to update style based formattings according to the modified template?"; +}; + +String STR_QRYTEMPL_UPDATE_BTN +{ + Text [ en-US ] = "~Update Styles"; +}; + +String STR_QRYTEMPL_KEEP_BTN +{ + Text [ en-US ] = "~Keep Old Styles"; +}; + +// ******************************************************************* EOF + diff --git a/sfx2/source/doc/docfac.cxx b/sfx2/source/doc/docfac.cxx new file mode 100644 index 000000000000..4311559f94af --- /dev/null +++ b/sfx2/source/doc/docfac.cxx @@ -0,0 +1,491 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" +#include <com/sun/star/registry/MergeConflictException.hpp> +#include <com/sun/star/registry/XSimpleRegistry.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/document/XTypeDetection.hpp> +#include <com/sun/star/frame/XLoadable.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <comphelper/processfactory.hxx> +#include <tools/config.hxx> +#include <unotools/pathoptions.hxx> +#include <unotools/moduleoptions.hxx> +#include <tools/urlobj.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <unotools/localfilehelper.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <comphelper/configurationhelper.hxx> + +#include <sfx2/sfx.hrc> +#include <sfx2/docfilt.hxx> +#include <sfx2/docfac.hxx> +#include "viewfac.hxx" +#include "fltfnc.hxx" +#include "arrdecl.hxx" +#include <sfx2/app.hxx> +#include <sfx2/module.hxx> +#include <sfx2/mnumgr.hxx> +#include "sfxresid.hxx" +#include <sfx2/sfxuno.hxx> +#include "syspath.hxx" +#include <osl/file.hxx> +#include <osl/security.hxx> +#include "doc.hrc" + +#include <assert.h> + +namespace css = ::com::sun::star; +using namespace ::com::sun::star; + +//======================================================================== + +DECL_PTRARRAY( SfxViewFactoryArr_Impl, SfxViewFactory*, 2, 2 ) + +//======================================================================== + +DBG_NAME(SfxObjectFactory) + +//static SfxObjectFactoryArr_Impl* pObjFac = 0; + +//======================================================================== + +struct SfxObjectFactory_Impl +{ + SfxViewFactoryArr_Impl aViewFactoryArr;// Liste von <SfxViewFactory>s + SfxFilterArr_Impl aFilterArr; // Liste von <SFxFilter>n + ResId* pNameResId; + ::rtl::OUString aServiceName; + SfxFilterContainer* pFilterContainer; + SfxModule* pModule; + sal_uInt16 nImageId; + String aStandardTemplate; + sal_Bool bTemplateInitialized; + SvGlobalName aClassName; + + SfxObjectFactory_Impl() : + pNameResId ( NULL ), + pFilterContainer ( NULL ), + pModule ( NULL ), + nImageId ( 0 ), + bTemplateInitialized( sal_False ) + {} +}; + +//======================================================================== + +SfxFilterContainer* SfxObjectFactory::GetFilterContainer( sal_Bool /*bForceLoad*/ ) const +{ + return pImpl->pFilterContainer; +} + +//-------------------------------------------------------------------- + +SfxObjectFactory::SfxObjectFactory +( + const SvGlobalName& rName, + SfxObjectShellFlags nFlagsP, + const char* pName +) : pShortName( pName ), + pImpl( new SfxObjectFactory_Impl ), + nFlags( nFlagsP ) +{ + DBG_CTOR(SfxObjectFactory, 0); + pImpl->pFilterContainer = new SfxFilterContainer( String::CreateFromAscii( pName ) ); + + String aShortName( String::CreateFromAscii( pShortName ) ); + aShortName.ToLowerAscii(); + pImpl->aClassName = rName; + if ( aShortName.EqualsAscii( "swriter" ) ) + pImpl->pNameResId = new SfxResId( STR_DOCTYPENAME_SW ); + else if ( aShortName.EqualsAscii( "swriter/web" ) ) + pImpl->pNameResId = new SfxResId( STR_DOCTYPENAME_SWWEB ); + else if ( aShortName.EqualsAscii( "swriter/globaldocument" ) ) + pImpl->pNameResId = new SfxResId( STR_DOCTYPENAME_SWGLOB ); + else if ( aShortName.EqualsAscii( "scalc" ) ) + pImpl->pNameResId = new SfxResId( STR_DOCTYPENAME_SC ); + else if ( aShortName.EqualsAscii( "simpress" ) ) + pImpl->pNameResId = new SfxResId( STR_DOCTYPENAME_SI ); + else if ( aShortName.EqualsAscii( "sdraw" ) ) + pImpl->pNameResId = new SfxResId( STR_DOCTYPENAME_SD ); + else if ( aShortName.EqualsAscii( "message" ) ) + pImpl->pNameResId = new SfxResId( STR_DOCTYPENAME_MESSAGE ); +} + +//-------------------------------------------------------------------- + +SfxObjectFactory::~SfxObjectFactory() +{ + DBG_DTOR(SfxObjectFactory, 0); + + const sal_uInt16 nCount = pImpl->aFilterArr.Count(); + for ( sal_uInt16 i = 0; i < nCount; ++i ) + delete pImpl->aFilterArr[i]; + delete pImpl->pNameResId; + delete pImpl; +} + +//-------------------------------------------------------------------- + +void SfxObjectFactory::RegisterViewFactory +( + SfxViewFactory &rFactory +) +{ +#if OSL_DEBUG_LEVEL > 0 + { + const String sViewName( rFactory.GetAPIViewName() ); + for ( sal_uInt16 i = 0; i < pImpl->aViewFactoryArr.Count(); ++i ) + { + if ( !pImpl->aViewFactoryArr[i]->GetAPIViewName().Equals( sViewName ) ) + continue; + ByteString sMessage( "SfxObjectFactory::RegisterViewFactory: duplicate view name '" ); + sMessage += ByteString( sViewName, RTL_TEXTENCODING_ASCII_US ); + sMessage += "'!"; + OSL_ENSURE( false, sMessage.GetBuffer() ); + break; + } + } +#endif + sal_uInt16 nPos; + for ( nPos = 0; + nPos < pImpl->aViewFactoryArr.Count() && + pImpl->aViewFactoryArr[nPos]->GetOrdinal() <= rFactory.GetOrdinal(); + ++nPos ) + /* empty loop */; + pImpl->aViewFactoryArr.Insert(nPos, &rFactory); +} + +//-------------------------------------------------------------------- + +sal_uInt16 SfxObjectFactory::GetViewFactoryCount() const +{ + return pImpl->aViewFactoryArr.Count(); +} + +//-------------------------------------------------------------------- + +SfxViewFactory& SfxObjectFactory::GetViewFactory(sal_uInt16 i) const +{ + return *pImpl->aViewFactoryArr[i]; +} + +//-------------------------------------------------------------------- + +SfxModule* SfxObjectFactory::GetModule() const +{ + return pImpl->pModule; +} + +void SfxObjectFactory::SetModule_Impl( SfxModule *pMod ) +{ + pImpl->pModule = pMod; +} + +void SfxObjectFactory::SetSystemTemplate( const String& rServiceName, const String& rTemplateName ) +{ + static const int nMaxPathSize = 16000; + static ::rtl::OUString SERVICE_FILTER_FACTORY = ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ); + static ::rtl::OUString SERVICE_TYPE_DECTECTION = ::rtl::OUString::createFromAscii( "com.sun.star.document.TypeDetection" ); + static ::rtl::OUString SERVICE_SIMPLE_ACCESS = ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ); + + static ::rtl::OUString CONF_ROOT = ::rtl::OUString::createFromAscii( "/org.openoffice.Setup"); + static ::rtl::OUString CONF_PATH = ::rtl::OUString::createFromAscii( "Office/Factories/" ) + ::rtl::OUString( rServiceName ); + static ::rtl::OUString PROP_DEF_TEMPL_CHANGED = ::rtl::OUString::createFromAscii( "ooSetupFactorySystemDefaultTemplateChanged" ); + static ::rtl::OUString PROP_ACTUAL_FILTER = ::rtl::OUString::createFromAscii( "ooSetupFactoryActualFilter" ); + + static ::rtl::OUString DEF_TPL_STR = ::rtl::OUString::createFromAscii("/soffice."); + + String sURL; + String sPath; + sal_Unicode aPathBuffer[nMaxPathSize]; + if ( SystemPath::GetUserTemplateLocation( aPathBuffer, nMaxPathSize )) + sPath = String( aPathBuffer ); + ::utl::LocalFileHelper::ConvertPhysicalNameToURL( sPath, sURL ); + + ::rtl::OUString aUserTemplateURL( sURL ); + if ( aUserTemplateURL.getLength() != 0) + { + try + { + uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); + uno::Reference< uno::XInterface > xConfig = ::comphelper::ConfigurationHelper::openConfig( + xFactory, CONF_ROOT, ::comphelper::ConfigurationHelper::E_STANDARD ); + + ::rtl::OUString aActualFilter; + ::comphelper::ConfigurationHelper::readRelativeKey( xConfig, CONF_PATH, PROP_ACTUAL_FILTER ) >>= aActualFilter; + sal_Bool bChanged(sal_False); + ::comphelper::ConfigurationHelper::readRelativeKey( xConfig, CONF_PATH, PROP_DEF_TEMPL_CHANGED ) >>= bChanged; + + uno::Reference< container::XNameAccess > xFilterFactory( + xFactory->createInstance( SERVICE_FILTER_FACTORY ), uno::UNO_QUERY_THROW ); + uno::Reference< container::XNameAccess > xTypeDetection( + xFactory->createInstance( SERVICE_TYPE_DECTECTION ), uno::UNO_QUERY_THROW ); + + ::rtl::OUString aActualFilterTypeName; + uno::Sequence< beans::PropertyValue > aActuralFilterData; + xFilterFactory->getByName( aActualFilter ) >>= aActuralFilterData; + for ( sal_Int32 nInd = 0; nInd < aActuralFilterData.getLength(); nInd++ ) + if ( aActuralFilterData[nInd].Name.equalsAscii( "Type" ) ) + aActuralFilterData[nInd].Value >>= aActualFilterTypeName; + ::comphelper::SequenceAsHashMap aProps1( xTypeDetection->getByName( aActualFilterTypeName ) ); + uno::Sequence< ::rtl::OUString > aAllExt = + aProps1.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "Extensions" ), uno::Sequence< ::rtl::OUString >() ); + //To-do: check if aAllExt is empty first + ::rtl::OUString aExt = aAllExt[0]; + + aUserTemplateURL += DEF_TPL_STR; + aUserTemplateURL += aExt; + + uno::Reference< ucb::XSimpleFileAccess > xSimpleFileAccess( + xFactory->createInstance( SERVICE_SIMPLE_ACCESS ), uno::UNO_QUERY_THROW ); + + ::rtl::OUString aBackupURL; + ::osl::Security().getConfigDir(aBackupURL); + aBackupURL += ::rtl::OUString::createFromAscii( "/temp" ); + + if ( !xSimpleFileAccess->exists( aBackupURL ) ) + xSimpleFileAccess->createFolder( aBackupURL ); + + aBackupURL += DEF_TPL_STR; + aBackupURL += aExt; + + if ( rTemplateName.Len() != 0 ) + { + if ( xSimpleFileAccess->exists( aUserTemplateURL ) && !bChanged ) + xSimpleFileAccess->copy( aUserTemplateURL, aBackupURL ); + + uno::Reference< document::XTypeDetection > xTypeDetector( xTypeDetection, uno::UNO_QUERY ); + ::comphelper::SequenceAsHashMap aProps2( xTypeDetection->getByName( xTypeDetector->queryTypeByURL( rTemplateName ) ) ); + ::rtl::OUString aFilterName = + aProps2.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii("PreferredFilter"), ::rtl::OUString() ); + + uno::Sequence< beans::PropertyValue > aArgs( 3 ); + aArgs[0].Name = ::rtl::OUString::createFromAscii( "FilterName" ); + aArgs[0].Value <<= aFilterName; + aArgs[1].Name = ::rtl::OUString::createFromAscii( "AsTemplate" ); + aArgs[1].Value <<= sal_True; + aArgs[2].Name = ::rtl::OUString::createFromAscii( "URL" ); + aArgs[2].Value <<= ::rtl::OUString( rTemplateName ); + + uno::Reference< frame::XLoadable > xLoadable( xFactory->createInstance( ::rtl::OUString( rServiceName ) ), uno::UNO_QUERY ); + xLoadable->load( aArgs ); + + aArgs.realloc( 2 ); + aArgs[1].Name = ::rtl::OUString::createFromAscii( "Overwrite" ); + aArgs[1].Value <<= sal_True; + + uno::Reference< frame::XStorable > xStorable( xLoadable, uno::UNO_QUERY ); + xStorable->storeToURL( aUserTemplateURL, aArgs ); + ::comphelper::ConfigurationHelper::writeRelativeKey( xConfig, CONF_PATH, PROP_DEF_TEMPL_CHANGED, uno::makeAny( sal_True )); + ::comphelper::ConfigurationHelper::flush( xConfig ); + } + else + { + DBG_ASSERT( bChanged, "invalid ooSetupFactorySystemDefaultTemplateChanged value!" ); + + xSimpleFileAccess->copy( aBackupURL, aUserTemplateURL ); + xSimpleFileAccess->kill( aBackupURL ); + ::comphelper::ConfigurationHelper::writeRelativeKey( xConfig, CONF_PATH, PROP_DEF_TEMPL_CHANGED, uno::makeAny( sal_False )); + ::comphelper::ConfigurationHelper::flush( xConfig ); + } + } + catch( uno::Exception& ) + { + } + } +} + +void SfxObjectFactory::SetStandardTemplate( const String& rServiceName, const String& rTemplate ) +{ + SvtModuleOptions::EFactory eFac = SvtModuleOptions::ClassifyFactoryByServiceName(rServiceName); + if (eFac == SvtModuleOptions::E_UNKNOWN_FACTORY) + eFac = SvtModuleOptions::ClassifyFactoryByShortName(rServiceName); + if (eFac != SvtModuleOptions::E_UNKNOWN_FACTORY) + { + SetSystemTemplate( rServiceName, rTemplate ); + SvtModuleOptions().SetFactoryStandardTemplate(eFac, rTemplate); + } +} + +String SfxObjectFactory::GetStandardTemplate( const String& rServiceName ) +{ + SvtModuleOptions::EFactory eFac = SvtModuleOptions::ClassifyFactoryByServiceName(rServiceName); + if (eFac == SvtModuleOptions::E_UNKNOWN_FACTORY) + eFac = SvtModuleOptions::ClassifyFactoryByShortName(rServiceName); + + String sTemplate; + if (eFac != SvtModuleOptions::E_UNKNOWN_FACTORY) + sTemplate = SvtModuleOptions().GetFactoryStandardTemplate(eFac); + + return sTemplate; +} + +/* +const SfxObjectFactory* SfxObjectFactory::GetFactory( const String& rFactoryURL ) +{ + const SfxObjectFactory* pFactory = 0; + String aFact( rFactoryURL ); + String aPrefix( DEFINE_CONST_UNICODE( "private:factory/" ) ); + if ( aPrefix.Len() == aFact.Match( aPrefix ) ) + // Aufruf m"oglich mit z.B. "swriter" oder "private:factory/swriter" + aFact.Erase( 0, aPrefix.Len() ); + sal_uInt16 nPos = aFact.Search( '?' ); + + // Etwaige Parameter abschneiden + aFact.Erase( nPos, aFact.Len() ); + + SfxApplication *pApp = SFX_APP(); + + // "swriter4" durch "swriter" ersetzen, zum Vergleichen uppercase verwenden + WildCard aSearchedFac( aFact.EraseAllChars('4').ToUpperAscii() ); + for( sal_uInt16 n = GetObjectFactoryCount_Impl(); !pFactory && n--; ) + { + pFactory = &GetObjectFactory_Impl( n ); + String aCompareTo = String::CreateFromAscii( pFactory->GetShortName() ); + aCompareTo.ToUpperAscii(); + if( !aSearchedFac.Matches( aCompareTo ) ) + pFactory = 0; + } + + return pFactory; +} +*/ + +const SfxFilter* SfxObjectFactory::GetTemplateFilter() const +{ + USHORT nVersion=0; + SfxFilterMatcher aMatcher ( String::CreateFromAscii( pShortName ) ); + SfxFilterMatcherIter aIter( &aMatcher ); + const SfxFilter *pFilter = 0; + const SfxFilter *pTemp = aIter.First(); + while ( pTemp ) + { + if( pTemp->IsOwnFormat() && pTemp->IsOwnTemplateFormat() && ( pTemp->GetVersion() > nVersion ) ) + { + pFilter = pTemp; + nVersion = (USHORT) pTemp->GetVersion(); + } + + pTemp = aIter.Next(); + } + + return pFilter; +} + +void SfxObjectFactory::SetDocumentTypeNameResource( const ResId& rId ) +{ + DBG_ASSERT( !pImpl->pNameResId, "UI-Namensresource mehrfach gesetzt!" ); + pImpl->pNameResId = new ResId( rId ); +} + +String SfxObjectFactory::GetDocumentTypeName() const +{ + if ( pImpl->pNameResId ) + return String( *pImpl->pNameResId ); + return String(); +} + +void SfxObjectFactory::SetDocumentServiceName( const ::rtl::OUString& rServiceName ) +{ + pImpl->aServiceName = rServiceName; +} + +const ::rtl::OUString& SfxObjectFactory::GetDocumentServiceName() const +{ + return pImpl->aServiceName; +} + +const SvGlobalName& SfxObjectFactory::GetClassId() const +{ + return pImpl->aClassName; +} + +String SfxObjectFactory::GetFactoryURL() const +{ + ::rtl::OUStringBuffer aURLComposer; + aURLComposer.appendAscii( "private:factory/" ); + aURLComposer.appendAscii( GetShortName() ); + return aURLComposer.makeStringAndClear(); +} + +String SfxObjectFactory::GetModuleName() const +{ + static ::rtl::OUString SERVICENAME_MODULEMANAGER = ::rtl::OUString::createFromAscii("com.sun.star.frame.ModuleManager"); + static ::rtl::OUString PROP_MODULEUINAME = ::rtl::OUString::createFromAscii("ooSetupFactoryUIName"); + + try + { + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = ::comphelper::getProcessServiceFactory(); + + css::uno::Reference< css::container::XNameAccess > xModuleManager( + xSMGR->createInstance(SERVICENAME_MODULEMANAGER), + css::uno::UNO_QUERY_THROW); + + ::rtl::OUString sDocService(GetDocumentServiceName()); + ::comphelper::SequenceAsHashMap aPropSet( xModuleManager->getByName(sDocService) ); + ::rtl::OUString sModuleName = aPropSet.getUnpackedValueOrDefault(PROP_MODULEUINAME, ::rtl::OUString()); + return String(sModuleName); + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception&) + {} + + return String(); +} + + +sal_uInt16 SfxObjectFactory::GetViewNo_Impl( const sal_uInt16 i_nViewId, const sal_uInt16 i_nFallback ) const +{ + for ( sal_uInt16 curViewNo = 0; curViewNo < GetViewFactoryCount(); ++curViewNo ) + { + const sal_uInt16 curViewId = GetViewFactory( curViewNo ).GetOrdinal(); + if ( i_nViewId == curViewId ) + return curViewNo; + } + return i_nFallback; +} + +SfxViewFactory* SfxObjectFactory::GetViewFactoryByViewName( const String& i_rViewName ) const +{ + for ( USHORT nViewNo = 0; + nViewNo < GetViewFactoryCount(); + ++nViewNo + ) + { + SfxViewFactory& rViewFac( GetViewFactory( nViewNo ) ); + if ( ( rViewFac.GetAPIViewName() == i_rViewName ) + || ( rViewFac.GetLegacyViewName() == i_rViewName ) + ) + return &rViewFac; + } + return NULL; +} diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx new file mode 100644 index 000000000000..29081e8e8418 --- /dev/null +++ b/sfx2/source/doc/docfile.cxx @@ -0,0 +1,3931 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" +#include <sfx2/docfile.hxx> +#include "sfx2/signaturestate.hxx" + +#include <uno/mapping.hxx> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/document/XDocumentRevisionListPersistence.hpp> +#include <com/sun/star/document/LockedDocumentRequest.hpp> +#include <com/sun/star/document/OwnLockOnDocumentRequest.hpp> +#include <com/sun/star/document/LockedOnSavingRequest.hpp> +#include <com/sun/star/document/LockFileIgnoreRequest.hpp> +#include <com/sun/star/document/ChangedByOthersRequest.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/UseBackupException.hpp> +#include <com/sun/star/embed/XOptimizedStorage.hpp> +#include <com/sun/star/ucb/InteractiveIOException.hpp> +#include <com/sun/star/ucb/UnsupportedDataSinkException.hpp> +#include <com/sun/star/ucb/CommandFailedException.hpp> +#include <com/sun/star/ucb/CommandAbortedException.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/ucb/XContentIdentifierFactory.hpp> +#include <com/sun/star/ucb/XContentProvider.hpp> +#include <com/sun/star/ucb/XProgressHandler.hpp> +#include <com/sun/star/ucb/XCommandInfo.hpp> +#include <com/sun/star/util/XArchiver.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/io/XStreamListener.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/ucb/InsertCommandArgument.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <com/sun/star/ucb/TransferInfo.hpp> +#include <com/sun/star/ucb/OpenCommandArgument2.hpp> +#include <com/sun/star/ucb/OpenMode.hpp> +#include <com/sun/star/ucb/NameClashException.hpp> +#include <com/sun/star/logging/XSimpleLogRing.hpp> +#include <cppuhelper/implbase1.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#ifndef _COM_SUN_STAR_SECURITY_DOCUMENTSIGNATURESINFORMATION_HPP_ +#include <com/sun/star/security/DocumentSignatureInformation.hpp> +#endif +#include <com/sun/star/security/XDocumentDigitalSignatures.hpp> +#include <tools/zcodec.hxx> +#include <tools/cachestr.hxx> +#include <tools/urlobj.hxx> +#include <unotools/tempfile.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/componentcontext.hxx> +#include <framework/interaction.hxx> +#include <unotools/streamhelper.hxx> +#include <unotools/localedatawrapper.hxx> +#ifndef _MSGBOX_HXX //autogen +#include <vcl/msgbox.hxx> +#endif +#include <svl/stritem.hxx> +#include <svl/eitem.hxx> +#include <svl/lckbitem.hxx> +#include <svtools/sfxecode.hxx> +#include <svl/itemset.hxx> +#include <svl/intitem.hxx> +#include <svtools/svparser.hxx> // SvKeyValue +#include <cppuhelper/weakref.hxx> +#include <cppuhelper/implbase1.hxx> + +#define _SVSTDARR_ULONGS +#define _SVSTDARR_STRINGSDTOR +#include <svl/svstdarr.hxx> + +#include <unotools/streamwrap.hxx> + +#include <rtl/logfile.hxx> +#include <osl/file.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::io; + +#include <comphelper/storagehelper.hxx> +#include <comphelper/mediadescriptor.hxx> +#include <comphelper/configurationhelper.hxx> +#include <comphelper/docpasswordhelper.hxx> +#include <tools/urlobj.hxx> +#include <tools/inetmime.hxx> +#include <unotools/ucblockbytes.hxx> +#include <unotools/pathoptions.hxx> +#include <svtools/asynclink.hxx> +#include <svl/inettype.hxx> +#include <ucbhelper/contentbroker.hxx> +#include <ucbhelper/commandenvironment.hxx> +#include <unotools/localfilehelper.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <unotools/ucbhelper.hxx> +#include <unotools/progresshandlerwrap.hxx> +#include <ucbhelper/content.hxx> +#include <ucbhelper/interactionrequest.hxx> +#include <sot/stg.hxx> +#include <unotools/saveopt.hxx> +#include <svl/documentlockfile.hxx> + +#include "helper.hxx" +#include <sfx2/request.hxx> // SFX_ITEMSET_SET +#include <sfx2/app.hxx> // GetFilterMatcher +#include <sfx2/frame.hxx> // LoadTargetFrame +#include "fltfnc.hxx" // SfxFilterMatcher +#include <sfx2/docfilt.hxx> // SfxFilter +#include <sfx2/objsh.hxx> // CheckOpenMode +#include <sfx2/docfac.hxx> // GetFilterContainer +#include "doc.hrc" +#include "openflag.hxx" // SFX_STREAM_READONLY etc. +#include "sfxresid.hxx" +#include <sfx2/appuno.hxx> + +//#include "xmlversion.hxx" + +#define MAX_REDIRECT 5 + + +sal_Bool IsReadonlyAccordingACL( const sal_Unicode* pFilePath ); + +//========================================================== +namespace { + +static const sal_Int8 LOCK_UI_NOLOCK = 0; +static const sal_Int8 LOCK_UI_SUCCEEDED = 1; +static const sal_Int8 LOCK_UI_TRY = 2; + +//---------------------------------------------------------------- +sal_Bool IsSystemFileLockingUsed() +{ + // check whether system file locking has been used, the default value is false + sal_Bool bUseSystemLock = sal_False; + try + { + + uno::Reference< uno::XInterface > xCommonConfig = ::comphelper::ConfigurationHelper::openConfig( + ::comphelper::getProcessServiceFactory(), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common" ) ), + ::comphelper::ConfigurationHelper::E_STANDARD ); + if ( !xCommonConfig.is() ) + throw uno::RuntimeException(); + + ::comphelper::ConfigurationHelper::readRelativeKey( + xCommonConfig, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Misc/" ) ), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseDocumentSystemFileLocking" ) ) ) >>= bUseSystemLock; + } + catch( const uno::Exception& ) + { + } + + return bUseSystemLock; +} + +//---------------------------------------------------------------- +sal_Bool IsOOoLockFileUsed() +{ + // check whether system file locking has been used, the default value is false + sal_Bool bOOoLockFileUsed = sal_False; + try + { + + uno::Reference< uno::XInterface > xCommonConfig = ::comphelper::ConfigurationHelper::openConfig( + ::comphelper::getProcessServiceFactory(), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common" ) ), + ::comphelper::ConfigurationHelper::E_STANDARD ); + if ( !xCommonConfig.is() ) + throw uno::RuntimeException(); + + ::comphelper::ConfigurationHelper::readRelativeKey( + xCommonConfig, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Misc/" ) ), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseDocumentOOoLockFile" ) ) ) >>= bOOoLockFileUsed; + } + catch( const uno::Exception& ) + { + } + + return bOOoLockFileUsed; +} + +} // anonymous namespace +//========================================================== + + +//---------------------------------------------------------------- +class SfxMediumHandler_Impl : public ::cppu::WeakImplHelper1< com::sun::star::task::XInteractionHandler > +{ + com::sun::star::uno::Reference< com::sun::star::task::XInteractionHandler > m_xInter; + +public: + virtual void SAL_CALL handle( const com::sun::star::uno::Reference< com::sun::star::task::XInteractionRequest >& xRequest ) + throw( com::sun::star::uno::RuntimeException ); + + SfxMediumHandler_Impl( com::sun::star::uno::Reference< com::sun::star::task::XInteractionHandler > xInteraction ) + : m_xInter( xInteraction ) + {} + + ~SfxMediumHandler_Impl(); +}; + +//---------------------------------------------------------------- +SfxMediumHandler_Impl::~SfxMediumHandler_Impl() +{ +} + +//---------------------------------------------------------------- +void SAL_CALL SfxMediumHandler_Impl::handle( const com::sun::star::uno::Reference< com::sun::star::task::XInteractionRequest >& xRequest ) + throw( com::sun::star::uno::RuntimeException ) +{ + if( !m_xInter.is() ) + return; + + com::sun::star::uno::Any aRequest = xRequest->getRequest(); + com::sun::star::ucb::InteractiveIOException aIoException; + com::sun::star::ucb::UnsupportedDataSinkException aSinkException; + if ( (aRequest >>= aIoException) && ( aIoException.Code == IOErrorCode_ACCESS_DENIED || aIoException.Code == IOErrorCode_LOCKING_VIOLATION ) ) + return; + else + if ( aRequest >>= aSinkException ) + return; + else + m_xInter->handle( xRequest ); +} + +//---------------------------------------------------------------- +class SfxMedium_Impl : public SvCompatWeakBase +{ +public: + ::ucbhelper::Content aContent; + sal_Bool bUpdatePickList : 1; + sal_Bool bIsTemp : 1; + sal_Bool bForceSynchron : 1; + sal_Bool bDownloadDone : 1; + sal_Bool bDontCallDoneLinkOnSharingError : 1; + sal_Bool bIsStorage: 1; + sal_Bool bUseInteractionHandler: 1; + sal_Bool bAllowDefaultIntHdl: 1; + sal_Bool bIsCharsetInitialized: 1; + sal_Bool bDisposeStorage: 1; + sal_Bool bStorageBasedOnInStream: 1; + sal_Bool m_bSalvageMode: 1; + sal_Bool m_bVersionsAlreadyLoaded: 1; + sal_Bool m_bLocked: 1; + sal_Bool m_bGotDateTime: 1; + + uno::Reference < embed::XStorage > xStorage; + + SfxMedium* pAntiImpl; + + long nFileVersion; + + const SfxFilter* pOrigFilter; + String aOrigURL; + String aPreRedirectionURL; + String aReferer; + DateTime aExpireTime; + SfxFrameWeak wLoadTargetFrame; + SvKeyValueIteratorRef xAttributes; + + svtools::AsynchronLink aDoneLink; + svtools::AsynchronLink aAvailableLink; + + uno::Sequence < util::RevisionTag > aVersions; + + ::utl::TempFile* pTempFile; + + uno::Reference < embed::XStorage > m_xZipStorage; + Reference < XInputStream > xInputStream; + Reference < XStream > xStream; + + uno::Reference< io::XStream > m_xLockingStream; + + sal_uInt32 nLastStorageError; + ::rtl::OUString aCharset; + + ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler > xInteraction; + + sal_Bool m_bRemoveBackup; + ::rtl::OUString m_aBackupURL; + + // the following member is changed and makes sence only during saving + // TODO/LATER: in future the signature state should be controlled by the medium not by the document + // in this case the member will hold this information + sal_uInt16 m_nSignatureState; + + util::DateTime m_aDateTime; + + uno::Reference< logging::XSimpleLogRing > m_xLogRing; + + SfxMedium_Impl( SfxMedium* pAntiImplP ); + ~SfxMedium_Impl(); +}; + +void SfxMedium::DataAvailable_Impl() +{ + pImp->aAvailableLink.ClearPendingCall(); + pImp->aAvailableLink.Call( NULL ); +} + +void SfxMedium::Cancel_Impl() +{ + SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); +} + +//------------------------------------------------------------------ +SfxMedium_Impl::SfxMedium_Impl( SfxMedium* pAntiImplP ) + : SvCompatWeakBase( pAntiImplP ), + bUpdatePickList(sal_True), + bIsTemp( sal_False ), + bForceSynchron( sal_False ), + bDownloadDone( sal_True ), + bDontCallDoneLinkOnSharingError( sal_False ), + bIsStorage( sal_False ), + bUseInteractionHandler( sal_True ), + bAllowDefaultIntHdl( sal_False ), + bIsCharsetInitialized( sal_False ), + bStorageBasedOnInStream( sal_False ), + m_bSalvageMode( sal_False ), + m_bVersionsAlreadyLoaded( sal_False ), + m_bLocked( sal_False ), + m_bGotDateTime( sal_False ), + pAntiImpl( pAntiImplP ), + nFileVersion( 0 ), + pOrigFilter( 0 ), + aExpireTime( Date() + 10, Time() ), + pTempFile( NULL ), + nLastStorageError( 0 ), + m_bRemoveBackup( sal_False ), + m_nSignatureState( SIGNATURESTATE_NOSIGNATURES ) +{ + aDoneLink.CreateMutex(); +} + +//------------------------------------------------------------------ +SfxMedium_Impl::~SfxMedium_Impl() +{ + + aDoneLink.ClearPendingCall(); + aAvailableLink.ClearPendingCall(); + + if ( pTempFile ) + delete pTempFile; +} + +//================================================================ + +#define IMPL_CTOR(rootVal,URLVal) \ + eError( SVSTREAM_OK ), \ + \ + bDirect( sal_False ), \ + bRoot( rootVal ), \ + bSetFilter( sal_False ), \ + bTriedStorage( sal_False ), \ + \ + nStorOpenMode( SFX_STREAM_READWRITE ), \ + pURLObj( URLVal ), \ + pInStream(0), \ + pOutStream( 0 ) + +//------------------------------------------------------------------ +void SfxMedium::ResetError() +{ + eError = SVSTREAM_OK; + if( pInStream ) + pInStream->ResetError(); + if( pOutStream ) + pOutStream->ResetError(); +} + +//------------------------------------------------------------------ +sal_uInt32 SfxMedium::GetLastStorageCreationState() +{ + return pImp->nLastStorageError; +} + +//------------------------------------------------------------------ +void SfxMedium::AddLog( const ::rtl::OUString& aMessage ) +{ + if ( !pImp->m_xLogRing.is() ) + { + try + { + ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); + if ( aContext.is() ) + pImp->m_xLogRing.set( aContext.getSingleton( "com.sun.star.logging.DocumentIOLogRing" ), UNO_QUERY_THROW ); + } + catch( uno::Exception& ) + {} + } + + if ( pImp->m_xLogRing.is() ) + pImp->m_xLogRing->logString( aMessage ); +} + +//------------------------------------------------------------------ +void SfxMedium::SetError( sal_uInt32 nError, const ::rtl::OUString& aLogMessage ) +{ + eError = nError; + if ( eError != ERRCODE_NONE && aLogMessage.getLength() ) + AddLog( aLogMessage ); +} + +//------------------------------------------------------------------ +sal_uInt32 SfxMedium::GetErrorCode() const +{ + sal_uInt32 lError=eError; + if(!lError && pInStream) + lError=pInStream->GetErrorCode(); + if(!lError && pOutStream) + lError=pOutStream->GetErrorCode(); + return lError; +} + +//------------------------------------------------------------------ +void SfxMedium::CheckFileDate( const util::DateTime& aInitDate ) +{ + GetInitFileDate( sal_True ); + if ( pImp->m_aDateTime.Seconds != aInitDate.Seconds + || pImp->m_aDateTime.Minutes != aInitDate.Minutes + || pImp->m_aDateTime.Hours != aInitDate.Hours + || pImp->m_aDateTime.Day != aInitDate.Day + || pImp->m_aDateTime.Month != aInitDate.Month + || pImp->m_aDateTime.Year != aInitDate.Year ) + { + uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler(); + + if ( xHandler.is() ) + { + try + { + ::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny( + document::ChangedByOthersRequest() ) ); + uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( 3 ); + aContinuations[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl.get() ); + aContinuations[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl.get() ); + xInteractionRequestImpl->setContinuations( aContinuations ); + + xHandler->handle( xInteractionRequestImpl.get() ); + + ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xInteractionRequestImpl->getSelection(); + if ( uno::Reference< task::XInteractionAbort >( xSelected.get(), uno::UNO_QUERY ).is() ) + { + SetError( ERRCODE_ABORT, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + } + catch ( uno::Exception& ) + {} + } + } +} + +//------------------------------------------------------------------ +sal_Bool SfxMedium::DocNeedsFileDateCheck() +{ + return ( !IsReadOnly() && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) ); +} + +//------------------------------------------------------------------ +util::DateTime SfxMedium::GetInitFileDate( sal_Bool bIgnoreOldValue ) +{ + if ( ( bIgnoreOldValue || !pImp->m_bGotDateTime ) && aLogicName.Len() ) + { + try + { + uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv; + ::ucbhelper::Content aContent( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv ); + + aContent.getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "DateModified" )) ) >>= pImp->m_aDateTime; + pImp->m_bGotDateTime = sal_True; + } + catch ( ::com::sun::star::uno::Exception& ) + { + } + } + + return pImp->m_aDateTime; +} + +//------------------------------------------------------------------ +Reference < XContent > SfxMedium::GetContent() const +{ + if ( !pImp->aContent.get().is() ) + { + Reference < ::com::sun::star::ucb::XContent > xContent; + Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv; + + SFX_ITEMSET_ARG( pSet, pItem, SfxUnoAnyItem, SID_CONTENT, sal_False); + if ( pItem ) + pItem->GetValue() >>= xContent; + + if ( xContent.is() ) + { + try + { + pImp->aContent = ::ucbhelper::Content( xContent, xEnv ); + } + catch ( Exception& ) + { + } + } + else + { + // TODO: DBG_ERROR("SfxMedium::GetContent()\nCreate Content? This code exists as fallback only. Please clarify, why its used."); + String aURL; + if ( aName.Len() ) + ::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aURL ); + else if ( aLogicName.Len() ) + aURL = GetURLObject().GetMainURL( INetURLObject::NO_DECODE ); + if ( aURL.Len() ) + ::ucbhelper::Content::create( aURL, xEnv, pImp->aContent ); + } + } + + return pImp->aContent.get(); +} + +//------------------------------------------------------------------ +::rtl::OUString SfxMedium::GetBaseURL( bool bForSaving ) +{ + ::rtl::OUString aBaseURL; + const SfxStringItem* pBaseURLItem = static_cast<const SfxStringItem*>( GetItemSet()->GetItem(SID_DOC_BASEURL) ); + if ( pBaseURLItem ) + aBaseURL = pBaseURLItem->GetValue(); + else if ( GetContent().is() ) + { + try + { + Any aAny = pImp->aContent.getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("BaseURI" )) ); + aAny >>= aBaseURL; + } + catch ( ::com::sun::star::uno::Exception& ) + { + } + + if ( !aBaseURL.getLength() ) + aBaseURL = GetURLObject().GetMainURL( INetURLObject::NO_DECODE ); + } + + if ( bForSaving ) + { + SvtSaveOptions aOpt; + sal_Bool bIsRemote = IsRemote(); + if( (bIsRemote && !aOpt.IsSaveRelINet()) || (!bRemote && !aOpt.IsSaveRelFSys()) ) + return ::rtl::OUString(); + } + + return aBaseURL; +} + +//------------------------------------------------------------------ +SvStream* SfxMedium::GetInStream() +{ + if ( pInStream ) + return pInStream; + + if ( pImp->pTempFile ) + { + pInStream = new SvFileStream( aName, nStorOpenMode ); + + eError = pInStream->GetError(); + + if( !eError && (nStorOpenMode & STREAM_WRITE) + && ! pInStream->IsWritable() ) + { + eError = ERRCODE_IO_ACCESSDENIED; + delete pInStream; + pInStream = NULL; + } + else + return pInStream; + } + + GetMedium_Impl(); + + if ( GetError() ) + return NULL; + + return pInStream; +} + +//------------------------------------------------------------------ +void SfxMedium::CloseInStream() +{ + CloseInStream_Impl(); +} + +void SfxMedium::CloseInStream_Impl() +{ + // if there is a storage based on the InStream, we have to + // close the storage, too, because otherwise the storage + // would use an invalid ( deleted ) stream. + if ( pInStream && pImp->xStorage.is() ) + { + if ( pImp->bStorageBasedOnInStream ) + CloseStorage(); + } + + if ( pInStream && !GetContent().is() ) + { + CreateTempFile( sal_True ); + return; + } + + DELETEZ( pInStream ); + if ( pSet ) + pSet->ClearItem( SID_INPUTSTREAM ); + + CloseZipStorage_Impl(); + pImp->xInputStream = uno::Reference< io::XInputStream >(); + + if ( !pOutStream ) + { + // output part of the stream is not used so the whole stream can be closed + // TODO/LATER: is it correct? + pImp->xStream = uno::Reference< io::XStream >(); + if ( pSet ) + pSet->ClearItem( SID_STREAM ); + } +} + +//------------------------------------------------------------------ +SvStream* SfxMedium::GetOutStream() +{ + if ( !pOutStream ) + { + // Create a temp. file if there is none because we always + // need one. + CreateTempFile( sal_False ); + + if ( pImp->pTempFile ) + { + pOutStream = new SvFileStream( aName, STREAM_STD_READWRITE ); + CloseStorage(); + } + } + + return pOutStream; +} + +//------------------------------------------------------------------ +sal_Bool SfxMedium::CloseOutStream() +{ + CloseOutStream_Impl(); + return sal_True; +} + +sal_Bool SfxMedium::CloseOutStream_Impl() +{ + if ( pOutStream ) + { + // if there is a storage based on the OutStream, we have to + // close the storage, too, because otherwise the storage + // would use an invalid ( deleted ) stream. + //TODO/MBA: how to deal with this?! + //maybe we need a new flag when the storage was created from the outstream + if ( pImp->xStorage.is() ) + { + //const SvStream *pStorage = aStorage->GetSvStream(); + //if ( pStorage == pOutStream ) + CloseStorage(); + } + + delete pOutStream; + pOutStream = NULL; + } + + if ( !pInStream ) + { + // input part of the stream is not used so the whole stream can be closed + // TODO/LATER: is it correct? + pImp->xStream = uno::Reference< io::XStream >(); + if ( pSet ) + pSet->ClearItem( SID_STREAM ); + } + + return sal_True; +} + +//------------------------------------------------------------------ +const String& SfxMedium::GetPhysicalName() const +{ + if ( !aName.Len() && aLogicName.Len() ) + (( SfxMedium*)this)->CreateFileStream(); + + // return the name then + return aName; +} + +//------------------------------------------------------------------ +void SfxMedium::CreateFileStream() +{ + ForceSynchronStream_Impl( TRUE ); + GetInStream(); + if( pInStream ) + { + CreateTempFile( sal_False ); + pImp->bIsTemp = sal_True; + CloseInStream_Impl(); + } +} + +//------------------------------------------------------------------ +sal_Bool SfxMedium::Commit() +{ + if( pImp->xStorage.is() ) + StorageCommit_Impl(); + else if( pOutStream ) + pOutStream->Flush(); + else if( pInStream ) + pInStream->Flush(); + + if ( GetError() == SVSTREAM_OK ) + { + // does something only in case there is a temporary file ( means aName points to different location than aLogicName ) + Transfer_Impl(); + } + + sal_Bool bResult = ( GetError() == SVSTREAM_OK ); + + if ( bResult && DocNeedsFileDateCheck() ) + GetInitFileDate( sal_True ); + + // remove truncation mode from the flags + nStorOpenMode &= (~STREAM_TRUNC); + return bResult; +} + +//------------------------------------------------------------------ +sal_Bool SfxMedium::IsStorage() +{ + if ( pImp->xStorage.is() ) + return TRUE; + + if ( bTriedStorage ) + return pImp->bIsStorage; + + if ( pImp->pTempFile ) + { + String aURL; + if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aURL ) ) + { + DBG_ERROR("Physical name not convertable!"); + } + pImp->bIsStorage = SotStorage::IsStorageFile( aURL ) && !SotStorage::IsOLEStorage( aURL); + if ( !pImp->bIsStorage ) + bTriedStorage = TRUE; + } + else if ( GetInStream() ) + { + pImp->bIsStorage = SotStorage::IsStorageFile( pInStream ) && !SotStorage::IsOLEStorage( pInStream ); + if ( !pInStream->GetError() && !pImp->bIsStorage ) + bTriedStorage = TRUE; + } + + return pImp->bIsStorage; +} + +//------------------------------------------------------------------ +Link SfxMedium::GetDataAvailableLink() const +{ + return pImp->aAvailableLink.GetLink(); +} + +//------------------------------------------------------------------ +Link SfxMedium::GetDoneLink() const +{ + return pImp->aDoneLink.GetLink(); +} + +//------------------------------------------------------------------ +sal_Bool SfxMedium::IsPreview_Impl() +{ + sal_Bool bPreview = sal_False; + SFX_ITEMSET_ARG( GetItemSet(), pPreview, SfxBoolItem, SID_PREVIEW, sal_False); + if ( pPreview ) + bPreview = pPreview->GetValue(); + else + { + SFX_ITEMSET_ARG( GetItemSet(), pFlags, SfxStringItem, SID_OPTIONS, sal_False); + if ( pFlags ) + { + String aFileFlags = pFlags->GetValue(); + aFileFlags.ToUpperAscii(); + if ( STRING_NOTFOUND != aFileFlags.Search( 'B' ) ) + bPreview = sal_True; + } + } + + return bPreview; +} + +//------------------------------------------------------------------ +void SfxMedium::StorageBackup_Impl() +{ + ::ucbhelper::Content aOriginalContent; + Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv; + + sal_Bool bBasedOnOriginalFile = ( !pImp->pTempFile && !( aLogicName.Len() && pImp->m_bSalvageMode ) + && GetURLObject().GetMainURL( INetURLObject::NO_DECODE ).getLength() + && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) + && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) ); + + if ( bBasedOnOriginalFile && !pImp->m_aBackupURL.getLength() + && ::ucbhelper::Content::create( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv, aOriginalContent ) ) + { + DoInternalBackup_Impl( aOriginalContent ); + if( !pImp->m_aBackupURL.getLength() ) + SetError( ERRCODE_SFX_CANTCREATEBACKUP, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } +} + +//------------------------------------------------------------------ +::rtl::OUString SfxMedium::GetBackup_Impl() +{ + if ( !pImp->m_aBackupURL.getLength() ) + StorageBackup_Impl(); + + return pImp->m_aBackupURL; +} + +//------------------------------------------------------------------ +uno::Reference < embed::XStorage > SfxMedium::GetOutputStorage() +{ + if ( GetError() ) + return uno::Reference< embed::XStorage >(); + + // if the medium was constructed with a Storage: use this one, not a temp. storage + // if a temporary storage already exists: use it + if ( pImp->xStorage.is() && ( !aLogicName.Len() || pImp->pTempFile ) ) + return pImp->xStorage; + + // if necessary close stream that was used for reading + if ( pInStream && !pInStream->IsWritable() ) + CloseInStream(); + + DBG_ASSERT( !pOutStream, "OutStream in a readonly Medium?!" ); + + // TODO/LATER: The current solution is to store the document temporary and then copy it to the target location; + // in future it should be stored directly and then copied to the temporary location, since in this case no + // file attributes have to be preserved and system copying mechanics could be used instead of streaming. + CreateTempFileNoCopy(); + + return GetStorage(); +} + +//------------------------------------------------------------------ +void SfxMedium::SetPasswordToStorage_Impl() +{ + // in case media-descriptor contains password it should be used on opening + if ( pImp->xStorage.is() && pSet ) + { + ::rtl::OUString aPasswd; + if ( GetPasswd_Impl( pSet, aPasswd ) ) + { + try + { + ::comphelper::OStorageHelper::SetCommonStoragePassword( pImp->xStorage, aPasswd ); + } + catch( uno::Exception& ) + { + OSL_ENSURE( sal_False, "It must be possible to set a common password for the storage" ); + // TODO/LATER: set the error code in case of problem + // SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + } + } +} + +//------------------------------------------------------------------ +sal_Int8 SfxMedium::ShowLockedDocumentDialog( const uno::Sequence< ::rtl::OUString >& aData, sal_Bool bIsLoading, sal_Bool bOwnLock ) +{ + sal_Int8 nResult = LOCK_UI_NOLOCK; + + // show the interaction regarding the document opening + uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler(); + + if ( ::svt::DocumentLockFile::IsInteractionAllowed() && xHandler.is() && ( bIsLoading || bOwnLock ) ) + { + ::rtl::OUString aDocumentURL = GetURLObject().GetLastName(); + ::rtl::OUString aInfo; + ::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl; + + if ( bOwnLock ) + { + if ( aData.getLength() > LOCKFILE_EDITTIME_ID ) + aInfo = aData[LOCKFILE_EDITTIME_ID]; + + xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny( + document::OwnLockOnDocumentRequest( ::rtl::OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo, !bIsLoading ) ) ); + } + else + { + if ( aData.getLength() > LOCKFILE_EDITTIME_ID ) + { + if ( aData[LOCKFILE_OOOUSERNAME_ID].getLength() ) + aInfo = aData[LOCKFILE_OOOUSERNAME_ID]; + else + aInfo = aData[LOCKFILE_SYSUSERNAME_ID]; + + if ( aInfo.getLength() && aData[LOCKFILE_EDITTIME_ID].getLength() ) + { + aInfo += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( " ( " ) ); + aInfo += aData[LOCKFILE_EDITTIME_ID]; + aInfo += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( " )" ) ); + } + } + + if ( bIsLoading ) + { + xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny( + document::LockedDocumentRequest( ::rtl::OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo ) ) ); + } + else + { + xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny( + document::LockedOnSavingRequest( ::rtl::OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo ) ) ); + + } + } + + uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( 3 ); + aContinuations[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl.get() ); + aContinuations[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl.get() ); + aContinuations[2] = new ::ucbhelper::InteractionDisapprove( xInteractionRequestImpl.get() ); + xInteractionRequestImpl->setContinuations( aContinuations ); + + xHandler->handle( xInteractionRequestImpl.get() ); + + ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xInteractionRequestImpl->getSelection(); + if ( uno::Reference< task::XInteractionAbort >( xSelected.get(), uno::UNO_QUERY ).is() ) + { + SetError( ERRCODE_ABORT, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + else if ( uno::Reference< task::XInteractionDisapprove >( xSelected.get(), uno::UNO_QUERY ).is() ) + { + // own lock on loading, user has selected to ignore the lock + // own lock on saving, user has selected to ignore the lock + // alien lock on loading, user has selected to edit a copy of document + // TODO/LATER: alien lock on saving, user has selected to do SaveAs to different location + if ( bIsLoading && !bOwnLock ) + { + // means that a copy of the document should be opened + GetItemSet()->Put( SfxBoolItem( SID_TEMPLATE, sal_True ) ); + } + else if ( bOwnLock ) + nResult = LOCK_UI_SUCCEEDED; + } + else // if ( XSelected == aContinuations[1] ) + { + // own lock on loading, user has selected to open readonly + // own lock on saving, user has selected to open readonly + // alien lock on loading, user has selected to retry saving + // TODO/LATER: alien lock on saving, user has selected to retry saving + + if ( bIsLoading ) + GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, sal_True ) ); + else + nResult = LOCK_UI_TRY; + } + } + else + { + if ( bIsLoading ) + { + // if no interaction handler is provided the default answer is open readonly + // that usually happens in case the document is loaded per API + // so the document must be opened readonly for backward compatibility + GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, sal_True ) ); + } + else + SetError( ERRCODE_IO_ACCESSDENIED, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + + } + + return nResult; +} + +//------------------------------------------------------------------ +sal_Bool SfxMedium::LockOrigFileOnDemand( sal_Bool bLoading, sal_Bool bNoUI ) +{ + // returns true if the document can be opened for editing ( even if it should be a copy ) + // otherwise the document should be opened readonly + // if user cancel the loading the ERROR_ABORT is set + + if ( pImp->m_bLocked && bLoading && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) ) + { + // if the document is already locked the system locking might be temporarely off after storing + // check whether the system file locking should be taken again + GetLockingStream_Impl(); + } + + sal_Bool bResult = pImp->m_bLocked; + + if ( !bResult ) + { + // no read-write access is necessary on loading if the document is explicitly opened as copy + SFX_ITEMSET_ARG( GetItemSet(), pTemplateItem, SfxBoolItem, SID_TEMPLATE, sal_False); + bResult = ( bLoading && pTemplateItem && pTemplateItem->GetValue() ); + } + + if ( !bResult && !IsReadOnly() ) + { + sal_Bool bContentReadonly = sal_False; + if ( bLoading && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) ) + { + // let the original document be opened to check the possibility to open it for editing + // and to let the writable stream stay open to hold the lock on the document + GetLockingStream_Impl(); + } + + // "IsReadOnly" property does not allow to detect whether the file is readonly always + // so we try always to open the file for editing + // the file is readonly only in case the read-write stream can not be opened + if ( bLoading && !pImp->m_xLockingStream.is() ) + { + try + { + // MediaDescriptor does this check also, the duplication should be avoided in future + Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv; + ::ucbhelper::Content aContent( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv ); + aContent.getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsReadOnly" ) ) ) >>= bContentReadonly; + } + catch( uno::Exception ) + {} + + if ( !bContentReadonly ) + { + // the file is not readonly, check the ACL + + String aPhysPath; + if ( ::utl::LocalFileHelper::ConvertURLToPhysicalName( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), aPhysPath ) ) + bContentReadonly = IsReadonlyAccordingACL( aPhysPath.GetBuffer() ); + } + } + + // do further checks only if the file not readonly in fs + if ( !bContentReadonly ) + { + // the special file locking should be used only for file URLs + if ( ::utl::LocalFileHelper::IsLocalFile( aLogicName ) ) + { + + // in case of storing the document should request the output before locking + if ( bLoading ) + { + // let the stream be opened to check the system file locking + GetMedium_Impl(); + } + + sal_Int8 bUIStatus = LOCK_UI_NOLOCK; + + // check whether system file locking has been used, the default value is false + sal_Bool bUseSystemLock = IsSystemFileLockingUsed(); + + // TODO/LATER: This implementation does not allow to detect the system lock on saving here, actually this is no big problem + // if system lock is used the writeable stream should be available + sal_Bool bHandleSysLocked = ( bLoading && bUseSystemLock && !pImp->xStream.is() && !pOutStream ); + + do + { + try + { + ::svt::DocumentLockFile aLockFile( aLogicName ); + if ( !bHandleSysLocked ) + { + try + { + bResult = aLockFile.CreateOwnLockFile(); + } + catch ( ucb::InteractiveIOException& e ) + { + // exception means that the lock file can not be successfuly accessed + // in this case it should be ignored if system file locking is anyway active + if ( bUseSystemLock || !IsOOoLockFileUsed() ) + { + bResult = sal_True; + // take the ownership over the lock file + aLockFile.OverwriteOwnLockFile(); + } + else if ( e.Code == IOErrorCode_INVALID_PARAMETER ) + { + // system file locking is not active, ask user whether he wants to open the document without any locking + uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler(); + + if ( xHandler.is() ) + { + ::rtl::Reference< ::ucbhelper::InteractionRequest > xIgnoreRequestImpl + = new ::ucbhelper::InteractionRequest( uno::makeAny( document::LockFileIgnoreRequest() ) ); + + uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( 2 ); + aContinuations[0] = new ::ucbhelper::InteractionAbort( xIgnoreRequestImpl.get() ); + aContinuations[1] = new ::ucbhelper::InteractionApprove( xIgnoreRequestImpl.get() ); + xIgnoreRequestImpl->setContinuations( aContinuations ); + + xHandler->handle( xIgnoreRequestImpl.get() ); + + ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xIgnoreRequestImpl->getSelection(); + bResult = ( uno::Reference< task::XInteractionApprove >( xSelected.get(), uno::UNO_QUERY ).is() ); + } + } + } + catch ( uno::Exception& ) + { + // exception means that the lock file can not be successfuly accessed + // in this case it should be ignored if system file locking is anyway active + if ( bUseSystemLock || !IsOOoLockFileUsed() ) + { + bResult = sal_True; + // take the ownership over the lock file + aLockFile.OverwriteOwnLockFile(); + } + } + + // in case OOo locking is turned off the lock file is still written if possible + // but it is ignored while deciding whether the document should be opened for editing or not + if ( !bResult && !IsOOoLockFileUsed() ) + { + bResult = sal_True; + // take the ownership over the lock file + aLockFile.OverwriteOwnLockFile(); + } + } + + + if ( !bResult ) + { + uno::Sequence< ::rtl::OUString > aData; + try + { + // impossibility to get data is no real problem + aData = aLockFile.GetLockData(); + } + catch( uno::Exception ) {} + + sal_Bool bOwnLock = sal_False; + + if ( !bHandleSysLocked ) + { + uno::Sequence< ::rtl::OUString > aOwnData = aLockFile.GenerateOwnEntry(); + bOwnLock = ( aData.getLength() > LOCKFILE_USERURL_ID + && aOwnData.getLength() > LOCKFILE_USERURL_ID + && aOwnData[LOCKFILE_SYSUSERNAME_ID].equals( aData[LOCKFILE_SYSUSERNAME_ID] ) ); + + if ( bOwnLock + && aOwnData[LOCKFILE_LOCALHOST_ID].equals( aData[LOCKFILE_LOCALHOST_ID] ) + && aOwnData[LOCKFILE_USERURL_ID].equals( aData[LOCKFILE_USERURL_ID] ) ) + { + // this is own lock from the same installation, it could remain because of crash + bResult = sal_True; + } + } + + if ( !bResult && !bNoUI ) + { + bUIStatus = ShowLockedDocumentDialog( aData, bLoading, bOwnLock ); + if ( bUIStatus == LOCK_UI_SUCCEEDED ) + { + // take the ownership over the lock file + bResult = aLockFile.OverwriteOwnLockFile(); + } + } + + bHandleSysLocked = sal_False; + } + } + catch( uno::Exception& ) + { + } + } while( !bResult && bUIStatus == LOCK_UI_TRY ); + + pImp->m_bLocked = bResult; + } + else + { + // this is no file URL, check whether the file is readonly + bResult = !bContentReadonly; + } + } + } + + if ( !bResult && GetError() == ERRCODE_NONE ) + { + // the error should be set in case it is storing process + // or the document has been opened for editing explicitly + + SFX_ITEMSET_ARG( pSet, pReadOnlyItem, SfxBoolItem, SID_DOC_READONLY, FALSE ); + if ( !bLoading || (pReadOnlyItem && !pReadOnlyItem->GetValue()) ) + SetError( ERRCODE_IO_ACCESSDENIED, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + else + GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, sal_True ) ); + } + + // when the file is locked, get the current file date + if ( bResult && DocNeedsFileDateCheck() ) + GetInitFileDate( sal_True ); + + return bResult; +} + +//------------------------------------------------------------------ +uno::Reference < embed::XStorage > SfxMedium::GetStorage( sal_Bool bCreateTempIfNo ) +{ + if ( pImp->xStorage.is() || bTriedStorage ) + return pImp->xStorage; + + uno::Sequence< uno::Any > aArgs( 2 ); + + // the medium should be retrieved before temporary file creation + // to let the MediaDescriptor be filled with the streams + GetMedium_Impl(); + + if ( bCreateTempIfNo ) + CreateTempFile( sal_False ); + + GetMedium_Impl(); + + if ( GetError() ) + return pImp->xStorage; + + SFX_ITEMSET_ARG( GetItemSet(), pRepairItem, SfxBoolItem, SID_REPAIRPACKAGE, sal_False); + if ( pRepairItem && pRepairItem->GetValue() ) + { + // the storage should be created for repairing mode + CreateTempFile( sal_False ); + GetMedium_Impl(); + + Reference< ::com::sun::star::ucb::XProgressHandler > xProgressHandler; + Reference< ::com::sun::star::task::XStatusIndicator > xStatusIndicator; + + SFX_ITEMSET_ARG( GetItemSet(), pxProgressItem, SfxUnoAnyItem, SID_PROGRESS_STATUSBAR_CONTROL, sal_False ); + if( pxProgressItem && ( pxProgressItem->GetValue() >>= xStatusIndicator ) ) + xProgressHandler = Reference< ::com::sun::star::ucb::XProgressHandler >( + new utl::ProgressHandlerWrap( xStatusIndicator ) ); + + uno::Sequence< beans::PropertyValue > aAddProps( 2 ); + aAddProps[0].Name = ::rtl::OUString::createFromAscii( "RepairPackage" ); + aAddProps[0].Value <<= (sal_Bool)sal_True; + aAddProps[1].Name = ::rtl::OUString::createFromAscii( "StatusIndicator" ); + aAddProps[1].Value <<= xProgressHandler; + + // the first arguments will be filled later + aArgs.realloc( 3 ); + aArgs[2] <<= aAddProps; + } + + if ( pImp->xStream.is() ) + { + // since the storage is based on temporary stream we open it always read-write + aArgs[0] <<= pImp->xStream; + aArgs[1] <<= embed::ElementModes::READWRITE; + pImp->bStorageBasedOnInStream = sal_True; + } + else if ( pImp->xInputStream.is() ) + { + // since the storage is based on temporary stream we open it always read-write + aArgs[0] <<= pImp->xInputStream; + aArgs[1] <<= embed::ElementModes::READ; + pImp->bStorageBasedOnInStream = sal_True; + } + else + { + CloseStreams_Impl(); + aArgs[0] <<= ::rtl::OUString( aName ); + aArgs[1] <<= embed::ElementModes::READ; + pImp->bStorageBasedOnInStream = sal_False; + } + + try + { + pImp->xStorage = uno::Reference< embed::XStorage >( + ::comphelper::OStorageHelper::GetStorageFactory()->createInstanceWithArguments( aArgs ), + uno::UNO_QUERY ); + } + catch( uno::Exception& ) + { + // impossibility to create the storage is no error + } + + if( ( pImp->nLastStorageError = GetError() ) != SVSTREAM_OK ) + { + pImp->xStorage = 0; + if ( pInStream ) + pInStream->Seek(0); + return uno::Reference< embed::XStorage >(); + } + + bTriedStorage = sal_True; + + // TODO/LATER: Get versionlist on demand + if ( pImp->xStorage.is() ) + { + SetPasswordToStorage_Impl(); + GetVersionList(); + } + + SFX_ITEMSET_ARG( pSet, pVersion, SfxInt16Item, SID_VERSION, sal_False); + + BOOL bResetStorage = FALSE; + if ( pVersion && pVersion->GetValue() ) + { + // Alle verf"ugbaren Versionen einlesen + if ( pImp->aVersions.getLength() ) + { + // Die zum Kommentar passende Version suchen + // Die Versionen sind von 1 an durchnumeriert, mit negativen + // Versionsnummern werden die Versionen von der aktuellen aus + // r"uckw"arts gez"ahlt + short nVersion = pVersion ? pVersion->GetValue() : 0; + if ( nVersion<0 ) + nVersion = ( (short) pImp->aVersions.getLength() ) + nVersion; + else if ( nVersion ) + nVersion--; + + util::RevisionTag& rTag = pImp->aVersions[nVersion]; + { + // SubStorage f"ur alle Versionen "offnen + uno::Reference < embed::XStorage > xSub = pImp->xStorage->openStorageElement( DEFINE_CONST_UNICODE( "Versions" ), + embed::ElementModes::READ ); + + DBG_ASSERT( xSub.is(), "Versionsliste, aber keine Versionen!" ); + + // Dort ist die Version als gepackter Stream gespeichert + uno::Reference < io::XStream > xStr = xSub->openStreamElement( rTag.Identifier, embed::ElementModes::READ ); + SvStream* pStream = utl::UcbStreamHelper::CreateStream( xStr ); + if ( pStream && pStream->GetError() == SVSTREAM_OK ) + { + // Stream ins TempDir auspacken + ::utl::TempFile aTempFile; + String aTmpName = aTempFile.GetURL(); + SvFileStream aTmpStream( aTmpName, SFX_STREAM_READWRITE ); + + *pStream >> aTmpStream; + aTmpStream.Close(); + + // Datei als Storage "offnen + nStorOpenMode = SFX_STREAM_READONLY; + pImp->xStorage = comphelper::OStorageHelper::GetStorageFromURL( aTmpName, embed::ElementModes::READ ); + pImp->bStorageBasedOnInStream = sal_False; + String aTemp; + ::utl::LocalFileHelper::ConvertURLToPhysicalName( aTmpName, aTemp ); + SetPhysicalName_Impl( aTemp ); + + pImp->bIsTemp = sal_True; + GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, sal_True ) ); + // TODO/MBA + pImp->aVersions.realloc(0); + } + else + bResetStorage = TRUE; + } + } + else + bResetStorage = TRUE; + } + + if ( bResetStorage ) + { + pImp->xStorage = 0; + if ( pInStream ) + pInStream->Seek( 0L ); + } + + pImp->bIsStorage = pImp->xStorage.is(); + return pImp->xStorage; +} + +//------------------------------------------------------------------ +uno::Reference< embed::XStorage > SfxMedium::GetZipStorageToSign_Impl( sal_Bool bReadOnly ) +{ + if ( !GetError() && !pImp->m_xZipStorage.is() ) + { + // very careful!!! + // if bReadOnly == sal_False and there is no temporary file the original file might be used + GetMedium_Impl(); + + try + { + // we can not sign document if there is no stream + // should it be possible at all? + if ( !bReadOnly && pImp->xStream.is() ) + { + pImp->m_xZipStorage = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING, pImp->xStream, embed::ElementModes::READWRITE ); + } + else if ( pImp->xInputStream.is() ) + { + pImp->m_xZipStorage = ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream( ZIP_STORAGE_FORMAT_STRING, pImp->xInputStream ); + } + } + catch( uno::Exception& ) + { + OSL_ENSURE( sal_False, "No possibility to get readonly version of storage from medium!\n" ); + } + + if ( GetError() ) // do not remove warnings + ResetError(); + } + + return pImp->m_xZipStorage; +} + +//------------------------------------------------------------------ +void SfxMedium::CloseZipStorage_Impl() +{ + if ( pImp->m_xZipStorage.is() ) + { + try { + pImp->m_xZipStorage->dispose(); + } catch( uno::Exception& ) + {} + + pImp->m_xZipStorage = uno::Reference< embed::XStorage >(); + } +} + +//------------------------------------------------------------------ +void SfxMedium::CloseStorage() +{ + if ( pImp->xStorage.is() ) + { + uno::Reference < lang::XComponent > xComp( pImp->xStorage, uno::UNO_QUERY ); + // in the salvage mode the medium does not own the storage + if ( pImp->bDisposeStorage && !pImp->m_bSalvageMode ) + { + try { + xComp->dispose(); + } catch( uno::Exception& ) + { + OSL_ENSURE( sal_False, "Medium's storage is already disposed!\n" ); + } + } + + pImp->xStorage = 0; + pImp->bStorageBasedOnInStream = sal_False; + } + + bTriedStorage = sal_False; + pImp->bIsStorage = sal_False; +} + +void SfxMedium::CanDisposeStorage_Impl( sal_Bool bDisposeStorage ) +{ + pImp->bDisposeStorage = bDisposeStorage; +} + +sal_Bool SfxMedium::WillDisposeStorageOnClose_Impl() +{ + return pImp->bDisposeStorage; +} + +//------------------------------------------------------------------ +void SfxMedium::SetOpenMode( StreamMode nStorOpen, + sal_Bool bDirectP, + sal_Bool bDontClose ) +{ + if ( nStorOpenMode != nStorOpen ) + { + nStorOpenMode = nStorOpen; + + if( !bDontClose ) + { + if ( pImp->xStorage.is() ) + CloseStorage(); + + CloseStreams_Impl(); + } + } + + bDirect = bDirectP; + bSetFilter = sal_False; +} + +//------------------------------------------------------------------ +sal_Bool SfxMedium::UseBackupToRestore_Impl( ::ucbhelper::Content& aOriginalContent, + const Reference< ::com::sun::star::ucb::XCommandEnvironment >& xComEnv ) +{ + try + { + ::ucbhelper::Content aTransactCont( pImp->m_aBackupURL, xComEnv ); + + Reference< XInputStream > aOrigInput = aTransactCont.openStream(); + aOriginalContent.writeStream( aOrigInput, sal_True ); + return sal_True; + } + catch( Exception& ) + { + // in case of failure here the backup file should not be removed + // TODO/LATER: a message should be used to let user know about the backup + pImp->m_bRemoveBackup = sal_False; + // TODO/LATER: needs a specific error code + eError = ERRCODE_IO_GENERAL; + } + + return sal_False; +} + +//------------------------------------------------------------------ +sal_Bool SfxMedium::StorageCommit_Impl() +{ + sal_Bool bResult = sal_False; + Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv; + ::ucbhelper::Content aOriginalContent; + + if ( pImp->xStorage.is() ) + { + if ( !GetError() ) + { + uno::Reference < embed::XTransactedObject > xTrans( pImp->xStorage, uno::UNO_QUERY ); + if ( xTrans.is() ) + { + try + { + xTrans->commit(); + CloseZipStorage_Impl(); + bResult = sal_True; + } + catch ( embed::UseBackupException& aBackupExc ) + { + // since the temporary file is created always now, the scenario is close to be impossible + if ( !pImp->pTempFile ) + { + OSL_ENSURE( pImp->m_aBackupURL.getLength(), "No backup on storage commit!\n" ); + if ( pImp->m_aBackupURL.getLength() + && ::ucbhelper::Content::create( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), + xDummyEnv, + aOriginalContent ) ) + { + // use backup to restore the file + // the storage has already disconnected from original location + CloseAndReleaseStreams_Impl(); + if ( !UseBackupToRestore_Impl( aOriginalContent, xDummyEnv ) ) + { + // connect the medium to the temporary file of the storage + pImp->aContent = ::ucbhelper::Content(); + aName = aBackupExc.TemporaryFileURL; + OSL_ENSURE( aName.Len(), "The exception _must_ contain the temporary URL!\n" ); + } + } + + if ( !GetError() ) + SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + } + catch ( uno::Exception& ) + { + //TODO/LATER: improve error handling + SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + } + } + } + + return bResult; +} + +//------------------------------------------------------------------ +sal_Bool SfxMedium::TransactedTransferForFS_Impl( const INetURLObject& aSource, + const INetURLObject& aDest, + const Reference< ::com::sun::star::ucb::XCommandEnvironment >& xComEnv ) +{ + sal_Bool bResult = sal_False; + Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv; + Reference< XOutputStream > aDestStream; + ::ucbhelper::Content aOriginalContent; + + try + { + aOriginalContent = ::ucbhelper::Content( aDest.GetMainURL( INetURLObject::NO_DECODE ), xComEnv ); + } + catch ( ::com::sun::star::ucb::CommandAbortedException& ) + { + eError = ERRCODE_ABORT; + } + catch ( ::com::sun::star::ucb::CommandFailedException& ) + { + eError = ERRCODE_ABORT; + } + catch (const ::com::sun::star::ucb::ContentCreationException& ex) + { + eError = ERRCODE_IO_GENERAL; + if ( + (ex.eError == ::com::sun::star::ucb::ContentCreationError_NO_CONTENT_PROVIDER ) || + (ex.eError == ::com::sun::star::ucb::ContentCreationError_CONTENT_CREATION_FAILED) + ) + { + eError = ERRCODE_IO_NOTEXISTSPATH; + } + } + catch (const ::com::sun::star::uno::Exception&) + { + eError = ERRCODE_IO_GENERAL; + } + + if( !eError || (eError & ERRCODE_WARNING_MASK) ) + { + if ( pImp->xStorage.is() ) + CloseStorage(); + + CloseStreams_Impl(); + + ::ucbhelper::Content aTempCont; + if( ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv, aTempCont ) ) + { + sal_Bool bTransactStarted = sal_False; + SFX_ITEMSET_ARG( GetItemSet(), pOverWrite, SfxBoolItem, SID_OVERWRITE, sal_False ); + SFX_ITEMSET_ARG( GetItemSet(), pRename, SfxBoolItem, SID_RENAME, sal_False ); + sal_Bool bRename = pRename ? pRename->GetValue() : FALSE; + sal_Bool bOverWrite = pOverWrite ? pOverWrite->GetValue() : !bRename; + + try + { + if( bOverWrite && ::utl::UCBContentHelper::IsDocument( aDest.GetMainURL( INetURLObject::NO_DECODE ) ) ) + { + if( ! pImp->m_aBackupURL.getLength() ) + DoInternalBackup_Impl( aOriginalContent ); + + if( pImp->m_aBackupURL.getLength() ) + { + Reference< XInputStream > aTempInput = aTempCont.openStream(); + bTransactStarted = sal_True; + aOriginalContent.setPropertyValue( ::rtl::OUString::createFromAscii( "Size" ), + uno::makeAny( (sal_Int64)0 ) ); + aOriginalContent.writeStream( aTempInput, bOverWrite ); + bResult = sal_True; + } + else + { + eError = ERRCODE_SFX_CANTCREATEBACKUP; + } + } + else + { + Reference< XInputStream > aTempInput = aTempCont.openStream(); + aOriginalContent.writeStream( aTempInput, bOverWrite ); + bResult = sal_True; + } + } + catch ( ::com::sun::star::ucb::CommandAbortedException& ) + { + eError = ERRCODE_ABORT; + } + catch ( ::com::sun::star::ucb::CommandFailedException& ) + { + eError = ERRCODE_ABORT; + } + catch ( ::com::sun::star::ucb::InteractiveIOException& r ) + { + if ( r.Code == IOErrorCode_ACCESS_DENIED ) + eError = ERRCODE_IO_ACCESSDENIED; + else if ( r.Code == IOErrorCode_NOT_EXISTING ) + eError = ERRCODE_IO_NOTEXISTS; + else if ( r.Code == IOErrorCode_CANT_READ ) + eError = ERRCODE_IO_CANTREAD; + else + eError = ERRCODE_IO_GENERAL; + } + catch ( ::com::sun::star::uno::Exception& ) + { + eError = ERRCODE_IO_GENERAL; + } + + if ( bResult ) + { + if ( pImp->pTempFile ) + { + pImp->pTempFile->EnableKillingFile( sal_True ); + delete pImp->pTempFile; + pImp->pTempFile = NULL; + } + } + else if ( bTransactStarted ) + { + UseBackupToRestore_Impl( aOriginalContent, xDummyEnv ); + } + } + else + eError = ERRCODE_IO_CANTREAD; + } + + return bResult; +} + +//------------------------------------------------------------------ +sal_Bool SfxMedium::TryDirectTransfer( const ::rtl::OUString& aURL, SfxItemSet& aTargetSet ) +{ + if ( GetError() ) + return sal_False; + + // if the document had no password it should be stored without password + // if the document had password it should be stored with the same password + // otherwise the stream copying can not be done + SFX_ITEMSET_ARG( &aTargetSet, pNewPassItem, SfxStringItem, SID_PASSWORD, sal_False ); + SFX_ITEMSET_ARG( GetItemSet(), pOldPassItem, SfxStringItem, SID_PASSWORD, sal_False ); + if ( ( !pNewPassItem && !pOldPassItem ) + || ( pNewPassItem && pOldPassItem && pNewPassItem->GetValue().Equals( pOldPassItem->GetValue() ) ) ) + { + // the filter must be the same + SFX_ITEMSET_ARG( &aTargetSet, pNewFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False ); + SFX_ITEMSET_ARG( GetItemSet(), pOldFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False ); + if ( pNewFilterItem && pOldFilterItem && pNewFilterItem->GetValue().Equals( pOldFilterItem->GetValue() ) ) + { + // get the input stream and copy it + // in case of success return true + uno::Reference< io::XInputStream > xInStream = GetInputStream(); + + ResetError(); + if ( xInStream.is() ) + { + try + { + uno::Reference< io::XSeekable > xSeek( xInStream, uno::UNO_QUERY ); + sal_Int64 nPos = 0; + if ( xSeek.is() ) + { + nPos = xSeek->getPosition(); + xSeek->seek( 0 ); + } + + uno::Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv; + ::ucbhelper::Content aTargetContent( aURL, xEnv ); + + InsertCommandArgument aInsertArg; + aInsertArg.Data = xInStream; + SFX_ITEMSET_ARG( &aTargetSet, pRename, SfxBoolItem, SID_RENAME, sal_False ); + SFX_ITEMSET_ARG( &aTargetSet, pOverWrite, SfxBoolItem, SID_OVERWRITE, sal_False ); + if ( (pOverWrite && !pOverWrite->GetValue()) // argument says: never overwrite + || (pRename && pRename->GetValue()) ) // argument says: rename file + aInsertArg.ReplaceExisting = sal_False; + else + aInsertArg.ReplaceExisting = sal_True; // default is overwrite existing files + + Any aCmdArg; + aCmdArg <<= aInsertArg; + aTargetContent.executeCommand( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert" ) ), + aCmdArg ); + + if ( xSeek.is() ) + xSeek->seek( nPos ); + + return sal_True; + } + catch( uno::Exception& ) + {} + } + } + } + + return sal_False; +} + +//------------------------------------------------------------------ +void SfxMedium::Transfer_Impl() +{ + // The transfer is required only in two cases: either if there is a temporary file or if there is a salvage item + String aNameURL; + if ( pImp->pTempFile ) + aNameURL = pImp->pTempFile->GetURL(); + else if ( aLogicName.Len() && pImp->m_bSalvageMode ) + { + // makes sence only in case logic name is set + if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aNameURL ) ) + OSL_ENSURE( sal_False, "The medium name is not convertable!\n" ); + } + + if ( aNameURL.Len() && ( !eError || (eError & ERRCODE_WARNING_MASK) ) ) + { + RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxMedium::Transfer_Impl, copying to target" ); + + Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv; + Reference< XOutputStream > rOutStream; + + // in case an output stream is provided from outside and the URL is correct + // commit to the stream + if( aLogicName.CompareToAscii( "private:stream", 14 ) == COMPARE_EQUAL ) + { + // TODO/LATER: support storing to SID_STREAM + SFX_ITEMSET_ARG( pSet, pOutStreamItem, SfxUnoAnyItem, SID_OUTPUTSTREAM, sal_False); + if( pOutStreamItem && ( pOutStreamItem->GetValue() >>= rOutStream ) ) + { + if ( pImp->xStorage.is() ) + CloseStorage(); + + CloseStreams_Impl(); + + INetURLObject aSource( aNameURL ); + ::ucbhelper::Content aTempCont; + if( ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xEnv, aTempCont ) ) + { + try + { + sal_Int32 nRead; + sal_Int32 nBufferSize = 32767; + Sequence < sal_Int8 > aSequence ( nBufferSize ); + Reference< XInputStream > aTempInput = aTempCont.openStream(); + + do + { + nRead = aTempInput->readBytes ( aSequence, nBufferSize ); + if ( nRead < nBufferSize ) + { + Sequence < sal_Int8 > aTempBuf ( aSequence.getConstArray(), nRead ); + rOutStream->writeBytes ( aTempBuf ); + } + else + rOutStream->writeBytes ( aSequence ); + } + while ( nRead == nBufferSize ); + + // remove temporary file + if ( pImp->pTempFile ) + { + pImp->pTempFile->EnableKillingFile( sal_True ); + delete pImp->pTempFile; + pImp->pTempFile = NULL; + } + } + catch( Exception& ) + {} + } + } + else + { + DBG_ERROR( "Illegal Output stream parameter!\n" ); + SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + + // free the reference + if ( pSet ) + pSet->ClearItem( SID_OUTPUTSTREAM ); + + return; + } + + GetContent(); + if ( !pImp->aContent.get().is() ) + { + eError = ERRCODE_IO_NOTEXISTS; + return; + } + + SFX_ITEMSET_ARG( GetItemSet(), pSegmentSize, SfxInt32Item, SID_SEGMENTSIZE, sal_False); + if ( pSegmentSize ) + { + // this file must be stored into a disk spanned package + try + { + uno::Reference < embed::XStorage > xStor = comphelper::OStorageHelper::GetStorageFromURL( GetName(), + embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE ); + + // set segment size property; package will automatically be divided in pieces fitting + // into this size + ::com::sun::star::uno::Any aAny; + aAny <<= pSegmentSize->GetValue(); + + uno::Reference < beans::XPropertySet > xSet( pImp->xStorage, uno::UNO_QUERY ); + xSet->setPropertyValue( String::CreateFromAscii("SegmentSize"), aAny ); + + // copy the temporary storage into the disk spanned package + GetStorage()->copyToStorage( xStor ); + uno::Reference < embed::XTransactedObject > xTrans( pImp->xStorage, uno::UNO_QUERY ); + if ( xTrans.is() ) + xTrans->commit(); + + } + catch ( uno::Exception& ) + { + //TODO/MBA: error handling + } + return; + } + + INetURLObject aDest( GetURLObject() ); + + // source is the temp file written so far + INetURLObject aSource( aNameURL ); + + // a special case, an interaction handler should be used for + // authentication in case it is available + Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv; + Reference< ::com::sun::star::task::XInteractionHandler > xInteractionHandler = GetInteractionHandler(); + if (xInteractionHandler.is()) + xComEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler, + Reference< ::com::sun::star::ucb::XProgressHandler >() ); + + if ( ::utl::LocalFileHelper::IsLocalFile( aDest.GetMainURL( INetURLObject::NO_DECODE ) ) || !aDest.removeSegment() ) + { + TransactedTransferForFS_Impl( aSource, aDest, xComEnv ); + } + else + { + // create content for the parent folder and call transfer on that content with the source content + // and the destination file name as parameters + ::ucbhelper::Content aSourceContent; + ::ucbhelper::Content aTransferContent; + + String aFileName = GetLongName(); + if ( !aFileName.Len() ) + aFileName = GetURLObject().getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + + try + { + aTransferContent = ::ucbhelper::Content( aDest.GetMainURL( INetURLObject::NO_DECODE ), xComEnv ); + } + catch (const ::com::sun::star::ucb::ContentCreationException& ex) + { + eError = ERRCODE_IO_GENERAL; + if ( + (ex.eError == ::com::sun::star::ucb::ContentCreationError_NO_CONTENT_PROVIDER ) || + (ex.eError == ::com::sun::star::ucb::ContentCreationError_CONTENT_CREATION_FAILED) + ) + { + eError = ERRCODE_IO_NOTEXISTSPATH; + } + } + catch (const ::com::sun::star::uno::Exception&) + { + eError = ERRCODE_IO_GENERAL; + } + + if ( !eError || (eError & ERRCODE_WARNING_MASK) ) + { + // free resources, otherwise the transfer may fail + if ( pImp->xStorage.is() ) + CloseStorage(); + + CloseStreams_Impl(); + + ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xEnv, aSourceContent ); + + // check for external parameters that may customize the handling of NameClash situations + SFX_ITEMSET_ARG( GetItemSet(), pRename, SfxBoolItem, SID_RENAME, sal_False ); + SFX_ITEMSET_ARG( GetItemSet(), pOverWrite, SfxBoolItem, SID_OVERWRITE, sal_False ); + sal_Int32 nNameClash; + if ( pOverWrite && !pOverWrite->GetValue() ) + // argument says: never overwrite + nNameClash = NameClash::ERROR; + else if ( pRename && pRename->GetValue() ) + // argument says: rename file + nNameClash = NameClash::RENAME; + else + // default is overwrite existing files + nNameClash = NameClash::OVERWRITE; + + try + { + if (!aTransferContent.transferContent( aSourceContent, ::ucbhelper::InsertOperation_COPY, aFileName, nNameClash )) + eError = ERRCODE_IO_GENERAL; + } + catch ( ::com::sun::star::ucb::CommandAbortedException& ) + { + eError = ERRCODE_ABORT; + } + catch ( ::com::sun::star::ucb::CommandFailedException& ) + { + eError = ERRCODE_ABORT; + } + catch ( ::com::sun::star::ucb::InteractiveIOException& r ) + { + if ( r.Code == IOErrorCode_ACCESS_DENIED ) + eError = ERRCODE_IO_ACCESSDENIED; + else if ( r.Code == IOErrorCode_NOT_EXISTING ) + eError = ERRCODE_IO_NOTEXISTS; + else if ( r.Code == IOErrorCode_CANT_READ ) + eError = ERRCODE_IO_CANTREAD; + else + eError = ERRCODE_IO_GENERAL; + } + catch ( ::com::sun::star::uno::Exception& ) + { + eError = ERRCODE_IO_GENERAL; + } + + // do not switch from temporary file in case of nonfile protocol + } + } + + if ( ( !eError || (eError & ERRCODE_WARNING_MASK) ) && !pImp->pTempFile ) + { + // without a TempFile the physical and logical name should be the same after successful transfer + ::utl::LocalFileHelper::ConvertURLToPhysicalName( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), + aName ); + pImp->m_bSalvageMode = sal_False; + } + } +} + +//------------------------------------------------------------------ +void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content& aOriginalContent, + const String& aPrefix, + const String& aExtension, + const String& aDestDir ) +{ + RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxMedium::DoInternalBackup_Impl( with destdir )" ); + + if ( pImp->m_aBackupURL.getLength() ) + return; // the backup was done already + + ::utl::TempFile aTransactTemp( aPrefix, &aExtension, &aDestDir ); + aTransactTemp.EnableKillingFile( sal_False ); + + INetURLObject aBackObj( aTransactTemp.GetURL() ); + ::rtl::OUString aBackupName = aBackObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + + Reference < ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv; + ::ucbhelper::Content aBackupCont; + if( ::ucbhelper::Content::create( aDestDir, xDummyEnv, aBackupCont ) ) + { + try + { + if( aBackupCont.transferContent( aOriginalContent, + ::ucbhelper::InsertOperation_COPY, + aBackupName, + NameClash::OVERWRITE ) ) + { + pImp->m_aBackupURL = aBackObj.GetMainURL( INetURLObject::NO_DECODE ); + pImp->m_bRemoveBackup = sal_True; + } + } + catch( Exception& ) + {} + } + + if ( !pImp->m_aBackupURL.getLength() ) + aTransactTemp.EnableKillingFile( sal_True ); +} + +//------------------------------------------------------------------ +void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content& aOriginalContent ) +{ + if ( pImp->m_aBackupURL.getLength() ) + return; // the backup was done already + + ::rtl::OUString aFileName = GetURLObject().getName( INetURLObject::LAST_SEGMENT, + true, + INetURLObject::NO_DECODE ); + + sal_Int32 nPrefixLen = aFileName.lastIndexOf( '.' ); + String aPrefix = ( nPrefixLen == -1 ) ? aFileName : aFileName.copy( 0, nPrefixLen ); + String aExtension = ( nPrefixLen == -1 ) ? String() : String(aFileName.copy( nPrefixLen )); + String aBakDir = SvtPathOptions().GetBackupPath(); + + DoInternalBackup_Impl( aOriginalContent, aPrefix, aExtension, aBakDir ); + + if ( !pImp->m_aBackupURL.getLength() ) + { + // the copiing to the backup catalog failed ( for example because + // of using an encrypted partition as target catalog ) + // since the user did not specify to make backup explicitly + // office should try to make backup in another place, + // target catalog does not look bad for this case ( and looks + // to be the only way for encrypted partitions ) + + INetURLObject aDest = GetURLObject(); + if ( aDest.removeSegment() ) + DoInternalBackup_Impl( aOriginalContent, aPrefix, aExtension, aDest.GetMainURL( INetURLObject::NO_DECODE ) ); + } +} + + +//------------------------------------------------------------------ +void SfxMedium::DoBackup_Impl() +{ + RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxMedium::DoBackup_Impl" ); + + // source file name is the logical name of this medium + INetURLObject aSource( GetURLObject() ); + + // there is nothing to backup in case source file does not exist + if ( !::utl::UCBContentHelper::IsDocument( aSource.GetMainURL( INetURLObject::NO_DECODE ) ) ) + return; + + sal_Bool bSuccess = sal_False; + + // get path for backups + String aBakDir = SvtPathOptions().GetBackupPath(); + if( aBakDir.Len() ) + { + // create content for the parent folder ( = backup folder ) + ::ucbhelper::Content aContent; + Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv; + if( ::ucbhelper::Content::create( aBakDir, xEnv, aContent ) ) + { + // save as ".bak" file + INetURLObject aDest( aBakDir ); + aDest.insertName( aSource.getName() ); + aDest.setExtension( DEFINE_CONST_UNICODE( "bak" ) ); + String aFileName = aDest.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + + // create a content for the source file + ::ucbhelper::Content aSourceContent; + if ( ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::NO_DECODE ), xEnv, aSourceContent ) ) + { + try + { + // do the transfer ( copy source file to backup dir ) + bSuccess = aContent.transferContent( aSourceContent, + ::ucbhelper::InsertOperation_COPY, + aFileName, + NameClash::OVERWRITE ); + if( bSuccess ) + { + pImp->m_aBackupURL = aDest.GetMainURL( INetURLObject::NO_DECODE ); + pImp->m_bRemoveBackup = sal_False; + } + } + catch ( ::com::sun::star::uno::Exception& ) + { + } + } + } + } + + if ( !bSuccess ) + { + eError = ERRCODE_SFX_CANTCREATEBACKUP; + } +} + +//------------------------------------------------------------------ +void SfxMedium::ClearBackup_Impl() +{ + if( pImp->m_bRemoveBackup ) + { + // currently a document is always stored in a new medium, + // thus if a backup can not be removed the backup URL should not be cleaned + if ( pImp->m_aBackupURL.getLength() ) + { + if ( ::utl::UCBContentHelper::Kill( pImp->m_aBackupURL ) ) + // || !::utl::UCBContentHelper::IsDocument( pImp->m_aBackupURL ) ); + { + pImp->m_bRemoveBackup = sal_False; + pImp->m_aBackupURL = ::rtl::OUString(); + } + else + { + + DBG_ERROR("Couldn't remove backup file!"); + } + } + } + else + pImp->m_aBackupURL = ::rtl::OUString(); +} + +//---------------------------------------------------------------- +void SfxMedium::GetLockingStream_Impl() +{ + if ( ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) + && !pImp->m_xLockingStream.is() ) + { + SFX_ITEMSET_ARG( pSet, pWriteStreamItem, SfxUnoAnyItem, SID_STREAM, sal_False); + if ( pWriteStreamItem ) + pWriteStreamItem->GetValue() >>= pImp->m_xLockingStream; + + if ( !pImp->m_xLockingStream.is() ) + { + // open the original document + uno::Sequence< beans::PropertyValue > xProps; + TransformItems( SID_OPENDOC, *GetItemSet(), xProps ); + comphelper::MediaDescriptor aMedium( xProps ); + + aMedium.addInputStreamOwnLock(); + + uno::Reference< io::XInputStream > xInputStream; + aMedium[comphelper::MediaDescriptor::PROP_STREAM()] >>= pImp->m_xLockingStream; + aMedium[comphelper::MediaDescriptor::PROP_INPUTSTREAM()] >>= xInputStream; + + if ( !pImp->pTempFile && !aName.Len() ) + { + // the medium is still based on the original file, it makes sence to initialize the streams + if ( pImp->m_xLockingStream.is() ) + pImp->xStream = pImp->m_xLockingStream; + + if ( xInputStream.is() ) + pImp->xInputStream = xInputStream; + + if ( !pImp->xInputStream.is() && pImp->xStream.is() ) + pImp->xInputStream = pImp->xStream->getInputStream(); + } + } + } +} + +//---------------------------------------------------------------- +void SfxMedium::GetMedium_Impl() +{ + if ( !pInStream ) + { + pImp->bDownloadDone = sal_False; + Reference< ::com::sun::star::task::XInteractionHandler > xInteractionHandler = GetInteractionHandler(); + + //TODO/MBA: need support for SID_STREAM + SFX_ITEMSET_ARG( pSet, pWriteStreamItem, SfxUnoAnyItem, SID_STREAM, sal_False); + SFX_ITEMSET_ARG( pSet, pInStreamItem, SfxUnoAnyItem, SID_INPUTSTREAM, sal_False); + if ( pWriteStreamItem ) + { + pWriteStreamItem->GetValue() >>= pImp->xStream; + + if ( pInStreamItem ) + pInStreamItem->GetValue() >>= pImp->xInputStream; + + if ( !pImp->xInputStream.is() && pImp->xStream.is() ) + pImp->xInputStream = pImp->xStream->getInputStream(); + } + else if ( pInStreamItem ) + { + pInStreamItem->GetValue() >>= pImp->xInputStream; + } + else + { + uno::Sequence < beans::PropertyValue > xProps; + String aFileName; + if ( aName.Len() ) + { + if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aFileName ) ) + { + DBG_ERROR("Physical name not convertable!"); + } + } + else + aFileName = GetName(); + + // in case the temporary file exists the streams should be initialized from it, + // but the original MediaDescriptor should not be changed + sal_Bool bFromTempFile = ( pImp->pTempFile != NULL ); + + if ( !bFromTempFile ) + { + GetItemSet()->Put( SfxStringItem( SID_FILE_NAME, aFileName ) ); + if( !(nStorOpenMode & STREAM_WRITE ) ) + GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, TRUE ) ); + if (xInteractionHandler.is()) + GetItemSet()->Put( SfxUnoAnyItem( SID_INTERACTIONHANDLER, makeAny(xInteractionHandler) ) ); + } + + if ( m_xInputStreamToLoadFrom.is() ) + { + pImp->xInputStream = m_xInputStreamToLoadFrom; + pImp->xInputStream->skipBytes(0); + if(m_bIsReadOnly) + GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, sal_True ) ); + + // m_xInputStreamToLoadFrom = 0; + } + else + { + TransformItems( SID_OPENDOC, *GetItemSet(), xProps ); + comphelper::MediaDescriptor aMedium( xProps ); + + if ( pImp->m_xLockingStream.is() && !bFromTempFile ) + { + // the medium is not based on the temporary file, so the original stream can be used + pImp->xStream = pImp->m_xLockingStream; + } + else + { + if ( bFromTempFile ) + { + aMedium[comphelper::MediaDescriptor::PROP_URL()] <<= ::rtl::OUString( aFileName ); + aMedium.erase( comphelper::MediaDescriptor::PROP_READONLY() ); + aMedium.addInputStream(); + } + else if ( ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) ) + { + // use the special locking approach only for file URLs + aMedium.addInputStreamOwnLock(); + } + else + aMedium.addInputStream(); + + // the ReadOnly property set in aMedium is ignored + // the check is done in LockOrigFileOnDemand() for file and non-file URLs + + //TODO/MBA: what happens if property is not there?! + aMedium[comphelper::MediaDescriptor::PROP_STREAM()] >>= pImp->xStream; + aMedium[comphelper::MediaDescriptor::PROP_INPUTSTREAM()] >>= pImp->xInputStream; + } + + GetContent(); + if ( !pImp->xInputStream.is() && pImp->xStream.is() ) + pImp->xInputStream = pImp->xStream->getInputStream(); + } + + if ( !bFromTempFile ) + { + //TODO/MBA: need support for SID_STREAM + if ( pImp->xStream.is() ) + GetItemSet()->Put( SfxUsrAnyItem( SID_STREAM, makeAny( pImp->xStream ) ) ); + + GetItemSet()->Put( SfxUsrAnyItem( SID_INPUTSTREAM, makeAny( pImp->xInputStream ) ) ); + } + } + + //TODO/MBA: ErrorHandling - how to transport error from MediaDescriptor + if ( !GetError() && !pImp->xStream.is() && !pImp->xInputStream.is() ) + SetError( ERRCODE_IO_ACCESSDENIED, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + + if ( !GetError() ) + { + if ( pImp->xStream.is() ) + pInStream = utl::UcbStreamHelper::CreateStream( pImp->xStream ); + else if ( pImp->xInputStream.is() ) + pInStream = utl::UcbStreamHelper::CreateStream( pImp->xInputStream ); + } + + pImp->bDownloadDone = sal_True; + pImp->aDoneLink.ClearPendingCall(); + pImp->aDoneLink.Call( (void*) GetError() ); + } +} + +//---------------------------------------------------------------- +sal_Bool SfxMedium::IsRemote() +{ + return bRemote; +} + +//------------------------------------------------------------------ + +void SfxMedium::SetUpdatePickList(sal_Bool bVal) +{ + if(!pImp) + pImp = new SfxMedium_Impl( this ); + pImp->bUpdatePickList = bVal; +} +//------------------------------------------------------------------ + +sal_Bool SfxMedium::IsUpdatePickList() const +{ + return pImp? pImp->bUpdatePickList: sal_True; +} +//---------------------------------------------------------------- + +void SfxMedium::SetDoneLink( const Link& rLink ) +{ + pImp->aDoneLink = rLink; +} + +//---------------------------------------------------------------- + +void SfxMedium::SetDataAvailableLink( const Link& rLink ) +{ + pImp->aAvailableLink = rLink; +} + +//---------------------------------------------------------------- +void SfxMedium::StartDownload() +{ + GetInStream(); +} + +void SfxMedium::DownLoad( const Link& aLink ) +{ + SetDoneLink( aLink ); + GetInStream(); + if ( pInStream && !aLink.IsSet() ) + { + while( !pImp->bDownloadDone ) + Application::Yield(); + } +} + +//------------------------------------------------------------------ +void SfxMedium::Init_Impl() +/* [Beschreibung] + Setzt in den Logischen Namen eine gueltige ::com::sun::star::util::URL (Falls zuvor ein Filename + drin war) und setzt den physikalschen Namen auf den Filenamen, falls + vorhanden. + */ + +{ + Reference< XOutputStream > rOutStream; + + // TODO/LATER: handle lifetime of storages + pImp->bDisposeStorage = FALSE; + + SFX_ITEMSET_ARG( pSet, pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False); + if ( pSalvageItem && !pSalvageItem->GetValue().Len() ) + { + pSalvageItem = NULL; + pSet->ClearItem( SID_DOC_SALVAGE ); + } + + if( aLogicName.Len() ) + { + INetURLObject aUrl( aLogicName ); + INetProtocol eProt = aUrl.GetProtocol(); + if ( eProt == INET_PROT_NOT_VALID ) + { + DBG_ERROR ( "Unknown protocol!" ); + } + else + { + if ( aUrl.HasMark() ) + { + aLogicName = aUrl.GetURLNoMark( INetURLObject::NO_DECODE ); + GetItemSet()->Put( SfxStringItem( SID_JUMPMARK, aUrl.GetMark() ) ); + } + + // try to convert the URL into a physical name - but never change a physical name + // physical name may be set if the logical name is changed after construction + if ( !aName.Len() ) + ::utl::LocalFileHelper::ConvertURLToPhysicalName( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), aName ); + else { + DBG_ASSERT( pSalvageItem, "Suspicious change of logical name!" ); + } + } + } + + if ( pSalvageItem && pSalvageItem->GetValue().Len() ) + { + aLogicName = pSalvageItem->GetValue(); + DELETEZ( pURLObj ); + pImp->m_bSalvageMode = sal_True; + } + + // in case output stream is by mistake here + // clear the reference + SFX_ITEMSET_ARG( pSet, pOutStreamItem, SfxUnoAnyItem, SID_OUTPUTSTREAM, sal_False); + if( pOutStreamItem + && ( !( pOutStreamItem->GetValue() >>= rOutStream ) + || !aLogicName.CompareToAscii( "private:stream", 14 ) == COMPARE_EQUAL ) ) + { + pSet->ClearItem( SID_OUTPUTSTREAM ); + DBG_ERROR( "Unexpected Output stream parameter!\n" ); + } + + if ( aLogicName.Len() ) + { + // if the logic name is set it should be set in MediaDescriptor as well + SFX_ITEMSET_ARG( pSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, FALSE ); + if ( !pFileNameItem ) + { + // let the ItemSet be created if necessary + GetItemSet()->Put( SfxStringItem( SID_FILE_NAME, INetURLObject( aLogicName ).GetMainURL( INetURLObject::NO_DECODE ) ) ); + } + } + + SetIsRemote_Impl(); +} + +//------------------------------------------------------------------ +SfxMedium::SfxMedium() +: IMPL_CTOR( sal_False, 0 ), // bRoot, pURLObj + + pFilter(0), + pSet(0), + pImp(new SfxMedium_Impl( this )) +{ + Init_Impl(); +} +//------------------------------------------------------------------ + +SfxMedium::SfxMedium( const SfxMedium& rMedium, sal_Bool bTemporary ) +: SvRefBase(), + IMPL_CTOR( sal_True, // bRoot, pURLObj + rMedium.pURLObj ? new INetURLObject(*rMedium.pURLObj) : 0 ), + pImp(new SfxMedium_Impl( this )) +{ + bDirect = rMedium.IsDirect(); + nStorOpenMode = rMedium.GetOpenMode(); + if ( !bTemporary ) + aName = rMedium.aName; + + pImp->bIsTemp = bTemporary; + DBG_ASSERT( ! rMedium.pImp->bIsTemp, "Temporaeres Medium darf nicht kopiert werden" ); + aLogicName = rMedium.aLogicName; + pSet = rMedium.GetItemSet() ? new SfxItemSet(*rMedium.GetItemSet()) : 0; + pFilter = rMedium.pFilter; + Init_Impl(); + if( bTemporary ) + CreateTempFile( sal_True ); +} + +//------------------------------------------------------------------ + +void SfxMedium::UseInteractionHandler( BOOL bUse ) +{ + pImp->bAllowDefaultIntHdl = bUse; +} + +//------------------------------------------------------------------ + +::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler > +SfxMedium::GetInteractionHandler() +{ + // if interaction isnt allowed explicitly ... return empty reference! + if ( !pImp->bUseInteractionHandler ) + return ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >(); + + // search a possible existing handler inside cached item set + if ( pSet ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler > xHandler; + SFX_ITEMSET_ARG( pSet, pHandler, SfxUnoAnyItem, SID_INTERACTIONHANDLER, sal_False); + if ( pHandler && (pHandler->GetValue() >>= xHandler) && xHandler.is() ) + return xHandler; + } + + // if default interaction isnt allowed explicitly ... return empty reference! + if ( !pImp->bAllowDefaultIntHdl ) + return ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >(); + + // otherwhise return cached default handler ... if it exist. + if ( pImp->xInteraction.is() ) + return pImp->xInteraction; + + // create default handler and cache it! + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); + if ( xFactory.is() ) + { + pImp->xInteraction = ::com::sun::star::uno::Reference< com::sun::star::task::XInteractionHandler >( xFactory->createInstance( DEFINE_CONST_UNICODE("com.sun.star.task.InteractionHandler") ), ::com::sun::star::uno::UNO_QUERY ); + return pImp->xInteraction; + } + + return ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >(); +} + +//---------------------------------------------------------------- + +void SfxMedium::SetFilter( const SfxFilter* pFilterP, sal_Bool /*bResetOrig*/ ) +{ + pFilter = pFilterP; + pImp->nFileVersion = 0; +} + +//---------------------------------------------------------------- + +const SfxFilter* SfxMedium::GetOrigFilter( sal_Bool bNotCurrent ) const +{ + return ( pImp->pOrigFilter || bNotCurrent ) ? pImp->pOrigFilter : pFilter; +} + +//---------------------------------------------------------------- + +void SfxMedium::SetOrigFilter_Impl( const SfxFilter* pOrigFilter ) +{ + pImp->pOrigFilter = pOrigFilter; +} + +//------------------------------------------------------------------ + +sal_uInt32 SfxMedium::CreatePasswordToModifyHash( const ::rtl::OUString& aPasswd, sal_Bool bWriter ) +{ + sal_uInt32 nHash = 0; + + if ( aPasswd.getLength() ) + { + if ( bWriter ) + { + nHash = ::comphelper::DocPasswordHelper::GetWordHashAsUINT32( aPasswd ); + } + else + { + rtl_TextEncoding nEncoding = RTL_TEXTENCODING_UTF8; + + // if the MS-filter should be used + // use the inconsistent algorithm to find the encoding specified by MS + nEncoding = osl_getThreadTextEncoding(); + switch( nEncoding ) + { + case RTL_TEXTENCODING_ISO_8859_15: + case RTL_TEXTENCODING_MS_874: + case RTL_TEXTENCODING_MS_1250: + case RTL_TEXTENCODING_MS_1251: + case RTL_TEXTENCODING_MS_1252: + case RTL_TEXTENCODING_MS_1253: + case RTL_TEXTENCODING_MS_1254: + case RTL_TEXTENCODING_MS_1255: + case RTL_TEXTENCODING_MS_1256: + case RTL_TEXTENCODING_MS_1257: + case RTL_TEXTENCODING_MS_1258: + case RTL_TEXTENCODING_SHIFT_JIS: + case RTL_TEXTENCODING_GB_2312: + case RTL_TEXTENCODING_BIG5: + // in case the system uses an encoding from the list above, it should be used + break; + + default: + // in case other encoding is used, use one of the encodings from the list + nEncoding = RTL_TEXTENCODING_MS_1250; + break; + } + + nHash = ::comphelper::DocPasswordHelper::GetXLHashAsUINT16( aPasswd, nEncoding ); + } + } + + return nHash; +} + +//------------------------------------------------------------------ + +void SfxMedium::Close() +{ + if ( pImp->xStorage.is() ) + { + // don't close the streams if they belong to the + // storage + //TODO/MBA: how to?! Do we need the flag?! + /* + const SvStream *pStream = aStorage->GetSvStream(); + if ( pStream && pStream == pInStream ) + { + CloseZipStorage_Impl(); + pInStream = NULL; + pImp->xInputStream = Reference < XInputStream >(); + pImp->xLockBytes.Clear(); + if ( pSet ) + pSet->ClearItem( SID_INPUTSTREAM ); + aStorage->SetDeleteStream( TRUE ); + } + else if ( pStream && pStream == pOutStream ) + { + pOutStream = NULL; + aStorage->SetDeleteStream( TRUE ); + } */ + + CloseStorage(); + } + + CloseStreams_Impl(); + + UnlockFile( sal_False ); +} + +void SfxMedium::CloseAndRelease() +{ + if ( pImp->xStorage.is() ) + { + // don't close the streams if they belong to the + // storage + //TODO/MBA: how to?! Do we need the flag?! + /* + const SvStream *pStream = aStorage->GetSvStream(); + if ( pStream && pStream == pInStream ) + { + CloseZipStorage_Impl(); + pInStream = NULL; + pImp->xInputStream = Reference < XInputStream >(); + pImp->xLockBytes.Clear(); + if ( pSet ) + pSet->ClearItem( SID_INPUTSTREAM ); + aStorage->SetDeleteStream( TRUE ); + } + else if ( pStream && pStream == pOutStream ) + { + pOutStream = NULL; + aStorage->SetDeleteStream( TRUE ); + } */ + + CloseStorage(); + } + + CloseAndReleaseStreams_Impl(); + + UnlockFile( sal_True ); +} + +void SfxMedium::UnlockFile( sal_Bool bReleaseLockStream ) +{ + if ( pImp->m_xLockingStream.is() ) + { + if ( bReleaseLockStream ) + { + try + { + uno::Reference< io::XInputStream > xInStream = pImp->m_xLockingStream->getInputStream(); + uno::Reference< io::XOutputStream > xOutStream = pImp->m_xLockingStream->getOutputStream(); + if ( xInStream.is() ) + xInStream->closeInput(); + if ( xOutStream.is() ) + xOutStream->closeOutput(); + } + catch( uno::Exception& ) + {} + } + + pImp->m_xLockingStream = uno::Reference< io::XStream >(); + } + + if ( pImp->m_bLocked ) + { + try + { + pImp->m_bLocked = sal_False; + ::svt::DocumentLockFile aLockFile( aLogicName ); + // TODO/LATER: A warning could be shown in case the file is not the own one + aLockFile.RemoveFile(); + } + catch( uno::Exception& ) + {} + } +} + +void SfxMedium::CloseAndReleaseStreams_Impl() +{ + CloseZipStorage_Impl(); + + uno::Reference< io::XInputStream > xInToClose = pImp->xInputStream; + uno::Reference< io::XOutputStream > xOutToClose; + if ( pImp->xStream.is() ) + { + xOutToClose = pImp->xStream->getOutputStream(); + + // if the locking stream is closed here the related member should be cleaned + if ( pImp->xStream == pImp->m_xLockingStream ) + pImp->m_xLockingStream = uno::Reference< io::XStream >(); + } + + // The probably exsisting SvStream wrappers should be closed first + CloseStreams_Impl(); + + // in case of salvage mode the storage is based on the streams + if ( !pImp->m_bSalvageMode ) + { + try + { + if ( xInToClose.is() ) + xInToClose->closeInput(); + if ( xOutToClose.is() ) + xOutToClose->closeOutput(); + } + catch ( uno::Exception& ) + { + } + } +} + +//------------------------------------------------------------------ +void SfxMedium::CloseStreams_Impl() +{ + CloseInStream_Impl(); + CloseOutStream_Impl(); + + if ( pSet ) + pSet->ClearItem( SID_CONTENT ); + + pImp->aContent = ::ucbhelper::Content(); +} + +//------------------------------------------------------------------ + +void SfxMedium::RefreshName_Impl() +{ +#if 0 //(dv) + if ( pImp->aContent.get().is() ) + { + String aNameP = pImp->xAnchor->GetViewURL(); + pImp->aOrigURL = aNameP; + aLogicName = aNameP; + DELETEZ( pURLObj ); + if (aLogicName.Len()) + aLogicName = GetURLObject().GetMainURL( INetURLObject::NO_DECODE ); + SetIsRemote_Impl(); + } +#endif //(dv) +} + +void SfxMedium::SetIsRemote_Impl() +{ + INetURLObject aObj( GetName() ); + switch( aObj.GetProtocol() ) + { + case INET_PROT_FTP: + case INET_PROT_HTTP: + case INET_PROT_HTTPS: + case INET_PROT_POP3: + case INET_PROT_NEWS: + case INET_PROT_IMAP: +// case INET_PROT_OUT: + case INET_PROT_VIM: + bRemote = TRUE; break; + default: + bRemote = ( GetName().CompareToAscii( "private:msgid", 13 ) == COMPARE_EQUAL ); + break; + } + + // Da Dateien, die Remote geschrieben werden zur Uebertragung auch + // gelesen werden koennen muessen + if( bRemote ) + nStorOpenMode |= STREAM_READ; +} + + + +void SfxMedium::SetName( const String& aNameP, sal_Bool bSetOrigURL ) +{ + if( !pImp->aOrigURL.Len() ) + pImp->aOrigURL = aLogicName; + if( bSetOrigURL ) + pImp->aOrigURL = aNameP; + aLogicName = aNameP; + DELETEZ( pURLObj ); + pImp->aContent = ::ucbhelper::Content(); + Init_Impl(); +} + +//---------------------------------------------------------------- +const String& SfxMedium::GetOrigURL() const +{ + return !pImp->aOrigURL.Len() ? (String &)aLogicName : pImp->aOrigURL; +} + +//---------------------------------------------------------------- + +void SfxMedium::SetPhysicalName_Impl( const String& rNameP ) +{ + if ( rNameP != aName ) + { + if( pImp->pTempFile ) + { + delete pImp->pTempFile; + pImp->pTempFile = NULL; + } + + if ( aName.Len() || rNameP.Len() ) + pImp->aContent = ::ucbhelper::Content(); + + aName = rNameP; + bTriedStorage = sal_False; + pImp->bIsStorage = sal_False; + } +} + +//------------------------------------------------------------------ +void SfxMedium::SetTemporary( sal_Bool bTemp ) +{ + pImp->bIsTemp = bTemp; +} + +//------------------------------------------------------------------ +sal_Bool SfxMedium::IsTemporary() const +{ + return pImp->bIsTemp; +} + +//------------------------------------------------------------------ + +sal_Bool SfxMedium::Exists( sal_Bool /*bForceSession*/ ) +{ + DBG_ERROR( "Not implemented!" ); + return sal_True; +} + +//------------------------------------------------------------------ + +void SfxMedium::ReOpen() +{ + BOOL bUseInteractionHandler = pImp->bUseInteractionHandler; + pImp->bUseInteractionHandler = FALSE; + GetMedium_Impl(); + pImp->bUseInteractionHandler = bUseInteractionHandler; +} + +//------------------------------------------------------------------ + +void SfxMedium::CompleteReOpen() +{ + // do not use temporary file for reopen and in case of success throw the temporary file away + BOOL bUseInteractionHandler = pImp->bUseInteractionHandler; + pImp->bUseInteractionHandler = FALSE; + + ::utl::TempFile* pTmpFile = NULL; + if ( pImp->pTempFile ) + { + pTmpFile = pImp->pTempFile; + pImp->pTempFile = NULL; + aName = String(); + } + + GetMedium_Impl(); + + if ( GetError() ) + { + if ( pImp->pTempFile ) + { + pImp->pTempFile->EnableKillingFile( sal_True ); + delete pImp->pTempFile; + } + pImp->pTempFile = pTmpFile; + if ( pImp->pTempFile ) + aName = pImp->pTempFile->GetFileName(); + } + else + { + pTmpFile->EnableKillingFile( sal_True ); + delete pTmpFile; + + } + + pImp->bUseInteractionHandler = bUseInteractionHandler; +} + +//------------------------------------------------------------------ +SfxMedium::SfxMedium +( + const String &rName, StreamMode nOpenMode, sal_Bool bDirectP, + const SfxFilter *pFlt, SfxItemSet *pInSet +) +: IMPL_CTOR( sal_False, 0 ), // bRoot, pURLObj + pFilter(pFlt), + pSet( pInSet ), + pImp(new SfxMedium_Impl( this )) +{ + aLogicName = rName; + nStorOpenMode = nOpenMode; + bDirect = bDirectP; + Init_Impl(); +} + + +SfxMedium::SfxMedium( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs ) + : IMPL_CTOR( sal_False, 0 ), // bRoot, pURLObj + pFilter(0), + pSet(0), + pImp(new SfxMedium_Impl( this )) +{ + SfxAllItemSet *pParams = new SfxAllItemSet( SFX_APP()->GetPool() ); + pSet = pParams; + TransformParameters( SID_OPENDOC, aArgs, *pParams ); + + String aFilterName; + SFX_ITEMSET_ARG( pSet, pFilterNameItem, SfxStringItem, SID_FILTER_NAME, sal_False ); + if( pFilterNameItem ) + aFilterName = pFilterNameItem->GetValue(); + pFilter = SFX_APP()->GetFilterMatcher().GetFilter4FilterName( aFilterName ); + + sal_Bool bSalvage = sal_False; + SFX_ITEMSET_ARG( pSet, pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False ); + if( pSalvageItem ) + { + // QUESTION: there is some treatment of Salvage in Init_Impl; align! + bSalvage = sal_True; + if ( pSalvageItem->GetValue().Len() ) + { + // if an URL is provided in SalvageItem that means that the FileName refers to a temporary file + // that must be copied here + + SFX_ITEMSET_ARG( pSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, FALSE ); + if (!pFileNameItem) throw uno::RuntimeException(); + ::rtl::OUString aNewTempFileURL = SfxMedium::CreateTempCopyWithExt( pFileNameItem->GetValue() ); + if ( aNewTempFileURL.getLength() ) + { + pSet->Put( SfxStringItem( SID_FILE_NAME, aNewTempFileURL ) ); + pSet->ClearItem( SID_INPUTSTREAM ); + pSet->ClearItem( SID_STREAM ); + pSet->ClearItem( SID_CONTENT ); + } + else + { + OSL_ENSURE( sal_False, "Can not create a new temporary file for crash recovery!\n" ); + } + } + } + + BOOL bReadOnly = FALSE; + SFX_ITEMSET_ARG( pSet, pReadOnlyItem, SfxBoolItem, SID_DOC_READONLY, FALSE ); + if ( pReadOnlyItem && pReadOnlyItem->GetValue() ) + bReadOnly = TRUE; + + SFX_ITEMSET_ARG( pSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, FALSE ); + if (!pFileNameItem) throw uno::RuntimeException(); + aLogicName = pFileNameItem->GetValue(); + nStorOpenMode = bReadOnly ? SFX_STREAM_READONLY : SFX_STREAM_READWRITE; + bDirect = FALSE; + Init_Impl(); +} + + +//------------------------------------------------------------------ + +SfxMedium::SfxMedium( const uno::Reference < embed::XStorage >& rStor, const String& rBaseURL, const SfxItemSet* p, sal_Bool bRootP ) +: IMPL_CTOR( bRootP, 0 ), // bRoot, pURLObj + pSet(0), + pImp( new SfxMedium_Impl( this )) +{ + String aType = SfxFilter::GetTypeFromStorage( rStor ); + pFilter = SFX_APP()->GetFilterMatcher().GetFilter4EA( aType ); + DBG_ASSERT( pFilter, "No Filter for storage found!" ); + + Init_Impl(); + pImp->xStorage = rStor; + pImp->bDisposeStorage = FALSE; + + // always take BaseURL first, could be overwritten by ItemSet + GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, rBaseURL ) ); + if ( p ) + GetItemSet()->Put( *p ); +} + +//------------------------------------------------------------------ + +SfxMedium::~SfxMedium() +{ + /* Attention + Don't enable CancelTransfers() till you know that the writer/web has changed his asynchronous load + behaviour. Otherwhise may StyleSheets inside a html file will be loaded at the right time. + => further the help will be empty then ... #100490# + */ + //CancelTransfers(); + + // if there is a requirement to clean the backup this is the last possibility to do it + ClearBackup_Impl(); + + Close(); + + delete pSet; + + if( pImp->bIsTemp && aName.Len() ) + { + String aTemp; + if ( !::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aTemp )) + { + DBG_ERROR("Physical name not convertable!"); + } + + if ( !::utl::UCBContentHelper::Kill( aTemp ) ) + { + DBG_ERROR("Couldn't remove temporary file!"); + } + } + + pFilter = 0; + + delete pURLObj; + delete pImp; +} + +//------------------------------------------------------------------ +void SfxMedium::SetItemSet(SfxItemSet *pNewSet) +{ + delete pSet; + pSet = pNewSet; +} + +//---------------------------------------------------------------- +const INetURLObject& SfxMedium::GetURLObject() const +{ + if( !pURLObj ) + { + SfxMedium* pThis = const_cast < SfxMedium* > (this); + pThis->pURLObj = new INetURLObject( aLogicName ); + if ( pThis->pURLObj->HasMark() ) + (*pThis->pURLObj) = INetURLObject( aLogicName ).GetURLNoMark(); + } + + return *pURLObj; +} + +//---------------------------------------------------------------- + +const String& SfxMedium::GetPreRedirectedURL() const +{ + return pImp->aPreRedirectionURL; +} +//---------------------------------------------------------------- + +sal_uInt32 SfxMedium::GetMIMEAndRedirect( String& /*rName*/ ) +{ +/* dv !!!! not needed any longer ? + INetProtocol eProt = GetURLObject().GetProtocol(); + if( eProt == INET_PROT_FTP && SvBinding::ShouldUseFtpProxy( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) ) + { + Any aAny( UCB_Helper::GetProperty( GetContent(), WID_FLAG_IS_FOLDER ) ); + sal_Bool bIsFolder = FALSE; + if ( ( aAny >>= bIsFolder ) && bIsFolder ) + return ERRCODE_NONE; + } + + GetMedium_Impl(); + if( !eError && pImp->xBinding.Is() ) + { + eError = pImp->xBinding->GetMimeType( rName ); + + // Wir koennen keine Parameter wie CharSets usw. + rName = rName.GetToken( 0, ';' ); + if( !eError ) + { + if( !pImp->aPreRedirectionURL.Len() ) + pImp->aPreRedirectionURL = aLogicName; + SetName( pImp->xBinding->GetRedirectedURL() ); + } + pImp->aExpireTime = pImp->xBinding->GetExpireDateTime(); + } + return eError; +*/ + return 0; +} + +//---------------------------------------------------------------- + +void SfxMedium::SetReferer( const String& rRefer ) +{ + pImp->aReferer = rRefer; +} +//---------------------------------------------------------------- + +const String& SfxMedium::GetReferer( ) const +{ + return pImp->aReferer; +} + +//---------------------------------------------------------------- + +void SfxMedium::SetExpired_Impl( const DateTime& rDateTime ) +{ + pImp->aExpireTime = rDateTime; +} +//---------------------------------------------------------------- + +sal_Bool SfxMedium::IsExpired() const +{ + return pImp->aExpireTime.IsValid() && pImp->aExpireTime < DateTime(); +} +//---------------------------------------------------------------- + +void SfxMedium::ForceSynchronStream_Impl( sal_Bool bForce ) +{ + if( pInStream ) + { + SvLockBytes* pBytes = pInStream->GetLockBytes(); + if( pBytes ) + pBytes->SetSynchronMode( bForce ); + } + pImp->bForceSynchron = bForce; +} + +//---------------------------------------------------------------- +SfxFrame* SfxMedium::GetLoadTargetFrame() const +{ + return pImp->wLoadTargetFrame; +} +//---------------------------------------------------------------- + +void SfxMedium::SetLoadTargetFrame(SfxFrame* pFrame ) +{ + pImp->wLoadTargetFrame = pFrame; +} +//---------------------------------------------------------------- + +void SfxMedium::SetStorage_Impl( const uno::Reference < embed::XStorage >& rStor ) +{ + pImp->xStorage = rStor; +} +//---------------------------------------------------------------- + +SfxItemSet* SfxMedium::GetItemSet() const +{ + // this method *must* return an ItemSet, returning NULL can cause crashes + if( !pSet ) + ((SfxMedium*)this)->pSet = new SfxAllItemSet( SFX_APP()->GetPool() ); + return pSet; +} +//---------------------------------------------------------------- + +SvKeyValueIterator* SfxMedium::GetHeaderAttributes_Impl() +{ + if( !pImp->xAttributes.Is() ) + { + pImp->xAttributes = SvKeyValueIteratorRef( new SvKeyValueIterator ); + + if ( GetContent().is() ) + { + pImp->bIsCharsetInitialized = sal_True; + + try + { + Any aAny = pImp->aContent.getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) ); + ::rtl::OUString aContentType; + aAny >>= aContentType; + + pImp->xAttributes->Append( SvKeyValue( ::rtl::OUString::createFromAscii( "content-type" ), aContentType ) ); + } + catch ( ::com::sun::star::uno::Exception& ) + { + } + } + } + + return pImp->xAttributes; +} +//---------------------------------------------------------------- + +SvCompatWeakHdl* SfxMedium::GetHdl() +{ + return pImp->GetHdl(); +} + +sal_Bool SfxMedium::IsDownloadDone_Impl() +{ + return pImp->bDownloadDone; +} + +::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SfxMedium::GetInputStream() +{ + if ( !pImp->xInputStream.is() ) + GetMedium_Impl(); + return pImp->xInputStream; +} + +const uno::Sequence < util::RevisionTag >& SfxMedium::GetVersionList( bool _bNoReload ) +{ + // if the medium has no name, then this medium should represent a new document and can have no version info + if ( ( !_bNoReload || !pImp->m_bVersionsAlreadyLoaded ) && !pImp->aVersions.getLength() && + ( aName.Len() || aLogicName.Len() ) && GetStorage().is() ) + { + uno::Reference < document::XDocumentRevisionListPersistence > xReader( comphelper::getProcessServiceFactory()->createInstance( + ::rtl::OUString::createFromAscii("com.sun.star.document.DocumentRevisionListPersistence") ), uno::UNO_QUERY ); + if ( xReader.is() ) + { + try + { + pImp->aVersions = xReader->load( GetStorage() ); + } + catch ( uno::Exception& ) + { + } + } + } + + if ( !pImp->m_bVersionsAlreadyLoaded ) + pImp->m_bVersionsAlreadyLoaded = sal_True; + + return pImp->aVersions; +} + +uno::Sequence < util::RevisionTag > SfxMedium::GetVersionList( const uno::Reference < embed::XStorage >& xStorage ) +{ + uno::Reference < document::XDocumentRevisionListPersistence > xReader( comphelper::getProcessServiceFactory()->createInstance( + ::rtl::OUString::createFromAscii("com.sun.star.document.DocumentRevisionListPersistence") ), uno::UNO_QUERY ); + if ( xReader.is() ) + { + try + { + return xReader->load( xStorage ); + } + catch ( uno::Exception& ) + { + } + } + + return uno::Sequence < util::RevisionTag >(); +} + +sal_uInt16 SfxMedium::AddVersion_Impl( util::RevisionTag& rRevision ) +{ + if ( GetStorage().is() ) + { + // Einen eindeutigen Namen f"ur den Stream ermitteln + SvULongs aLongs; + sal_Int32 nLength = pImp->aVersions.getLength(); + for ( sal_Int32 m=0; m<nLength; m++ ) + { + sal_uInt32 nVer = (sal_uInt32) String( pImp->aVersions[m].Identifier ).Copy(7).ToInt32(); + sal_uInt16 n; + for ( n=0; n<aLongs.Count(); n++ ) + if ( nVer<aLongs[n] ) + break; + + aLongs.Insert( nVer, n ); + } + + sal_uInt16 nKey; + for ( nKey=0; nKey<aLongs.Count(); nKey++ ) + if ( aLongs[nKey] > ( ULONG ) nKey+1 ) + break; + + String aRevName = DEFINE_CONST_UNICODE( "Version" ); + aRevName += String::CreateFromInt32( nKey + 1 ); + pImp->aVersions.realloc( nLength+1 ); + rRevision.Identifier = aRevName; + pImp->aVersions[nLength] = rRevision; + return nKey; + } + + return 0; +} + +sal_Bool SfxMedium::RemoveVersion_Impl( const ::rtl::OUString& rName ) +{ + if ( !pImp->aVersions.getLength() ) + return sal_False; + + sal_Int32 nLength = pImp->aVersions.getLength(); + for ( sal_Int32 n=0; n<nLength; n++ ) + { + if ( pImp->aVersions[n].Identifier == rName ) + { + for ( sal_Int32 m=n; m<nLength-1; m++ ) + pImp->aVersions[m] = pImp->aVersions[m+1]; + pImp->aVersions.realloc(nLength-1); + return sal_True; + } + } + + return sal_False; +} + +sal_Bool SfxMedium::TransferVersionList_Impl( SfxMedium& rMedium ) +{ + if ( rMedium.pImp->aVersions.getLength() ) + { + pImp->aVersions = rMedium.pImp->aVersions; + return sal_True; + } + + return sal_False; +} + +sal_Bool SfxMedium::SaveVersionList_Impl( sal_Bool /*bUseXML*/ ) +{ + if ( GetStorage().is() ) + { + if ( !pImp->aVersions.getLength() ) + return sal_True; + + uno::Reference < document::XDocumentRevisionListPersistence > xWriter( comphelper::getProcessServiceFactory()->createInstance( + ::rtl::OUString::createFromAscii("com.sun.star.document.DocumentRevisionListPersistence") ), uno::UNO_QUERY ); + if ( xWriter.is() ) + { + try + { + xWriter->store( GetStorage(), pImp->aVersions ); + return sal_True; + } + catch ( uno::Exception& ) + { + } + } + } + + return sal_False; +} + +//---------------------------------------------------------------- +sal_Bool SfxMedium::IsReadOnly() +{ + sal_Bool bReadOnly = sal_False; + + // a) ReadOnly filter cant produce read/write contents! + bReadOnly = ( + (pFilter ) && + ((pFilter->GetFilterFlags() & SFX_FILTER_OPENREADONLY) == SFX_FILTER_OPENREADONLY) + ); + + // b) if filter allow read/write contents .. check open mode of the storage + if (!bReadOnly) + bReadOnly = !( GetOpenMode() & STREAM_WRITE ); + + // c) the API can force the readonly state! + if (!bReadOnly) + { + SFX_ITEMSET_ARG( GetItemSet(), pItem, SfxBoolItem, SID_DOC_READONLY, sal_False); + if (pItem) + bReadOnly = pItem->GetValue(); + } + + return bReadOnly; +} + +//---------------------------------------------------------------- +sal_Bool SfxMedium::SetWritableForUserOnly( const ::rtl::OUString& aURL ) +{ + // UCB does not allow to allow write access only for the user, + // use osl API + sal_Bool bResult = sal_False; + + ::osl::DirectoryItem aDirItem; + if ( ::osl::DirectoryItem::get( aURL, aDirItem ) == ::osl::FileBase::E_None ) + { + ::osl::FileStatus aFileStatus( FileStatusMask_Attributes ); + if ( aDirItem.getFileStatus( aFileStatus ) == osl::FileBase::E_None + && aFileStatus.isValid( FileStatusMask_Attributes ) ) + { + sal_uInt64 nAttributes = aFileStatus.getAttributes(); + + nAttributes &= ~(Attribute_OwnWrite | + Attribute_GrpWrite | + Attribute_OthWrite | + Attribute_ReadOnly); + nAttributes |= Attribute_OwnWrite; + + bResult = ( osl::File::setAttributes( aURL, nAttributes ) == ::osl::FileBase::E_None ); + } + } + + return bResult; +} + +//---------------------------------------------------------------- +void SfxMedium::CreateTempFile( sal_Bool bReplace ) +{ + if ( pImp->pTempFile ) + { + if ( !bReplace ) + return; + + DELETEZ( pImp->pTempFile ); + aName = String(); + } + + pImp->pTempFile = new ::utl::TempFile(); + pImp->pTempFile->EnableKillingFile( sal_True ); + aName = pImp->pTempFile->GetFileName(); + ::rtl::OUString aTmpURL = pImp->pTempFile->GetURL(); + if ( !aName.Len() || !aTmpURL.getLength() ) + { + SetError( ERRCODE_IO_CANTWRITE, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + return; + } + + if ( !( nStorOpenMode & STREAM_TRUNC ) ) + { + sal_Bool bTransferSuccess = sal_False; + + if ( GetContent().is() + && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) + && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) ) + { + // if there is already such a document, we should copy it + // if it is a file system use OS copy process + try + { + uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv; + INetURLObject aTmpURLObj( aTmpURL ); + ::rtl::OUString aFileName = aTmpURLObj.getName( INetURLObject::LAST_SEGMENT, + true, + INetURLObject::DECODE_WITH_CHARSET ); + if ( aFileName.getLength() && aTmpURLObj.removeSegment() ) + { + ::ucbhelper::Content aTargetContent( aTmpURLObj.GetMainURL( INetURLObject::NO_DECODE ), xComEnv ); + if ( aTargetContent.transferContent( pImp->aContent, ::ucbhelper::InsertOperation_COPY, aFileName, NameClash::OVERWRITE ) ) + { + SetWritableForUserOnly( aTmpURL ); + bTransferSuccess = sal_True; + } + } + } + catch( uno::Exception& ) + {} + + if ( bTransferSuccess ) + { + CloseOutStream(); + CloseInStream(); + } + } + + if ( !bTransferSuccess && pInStream ) + { + // the case when there is no URL-access available or this is a remote protocoll + // but there is an input stream + GetOutStream(); + if ( pOutStream ) + { + char *pBuf = new char [8192]; + sal_uInt32 nErr = ERRCODE_NONE; + + pInStream->Seek(0); + pOutStream->Seek(0); + + while( !pInStream->IsEof() && nErr == ERRCODE_NONE ) + { + sal_uInt32 nRead = pInStream->Read( pBuf, 8192 ); + nErr = pInStream->GetError(); + pOutStream->Write( pBuf, nRead ); + } + + bTransferSuccess = sal_True; + delete[] pBuf; + CloseInStream(); + } + CloseOutStream_Impl(); + } + else + { + // Quite strange design, but currently it is expected that in this case no transfer happens + // TODO/LATER: get rid of this inconsistent part of the call design + bTransferSuccess = sal_True; + CloseInStream(); + } + + if ( !bTransferSuccess ) + { + SetError( ERRCODE_IO_CANTWRITE, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + return; + } + } + + CloseStorage(); +} + +//---------------------------------------------------------------- +void SfxMedium::CreateTempFileNoCopy() +{ + // this call always replaces the existing temporary file + if ( pImp->pTempFile ) + delete pImp->pTempFile; + + pImp->pTempFile = new ::utl::TempFile(); + pImp->pTempFile->EnableKillingFile( sal_True ); + aName = pImp->pTempFile->GetFileName(); + if ( !aName.Len() ) + { + SetError( ERRCODE_IO_CANTWRITE, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + return; + } + + CloseOutStream_Impl(); + CloseStorage(); +} + +::rtl::OUString SfxMedium::GetCharset() +{ + if( !pImp->bIsCharsetInitialized ) + { + // Set an error in case there is no content? + if ( GetContent().is() ) + { + pImp->bIsCharsetInitialized = sal_True; + + try + { + Any aAny = pImp->aContent.getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) ); + ::rtl::OUString aField; + aAny >>= aField; + + ::rtl::OString sContent = ::rtl::OUStringToOString( aField, RTL_TEXTENCODING_ASCII_US ); + ByteString sType, sSubType; + INetContentTypeParameterList aParameters; + + if( INetContentTypes::parse( sContent, sType, sSubType, &aParameters ) ) + { + const INetContentTypeParameter * pCharset = aParameters.find("charset"); + if (pCharset != 0) + pImp->aCharset = pCharset->m_sValue; + } + } + catch ( ::com::sun::star::uno::Exception& ) + { + } + } + } + + return pImp->aCharset; +} + +void SfxMedium::SetCharset( ::rtl::OUString aChs ) +{ + pImp->bIsCharsetInitialized = sal_True; + pImp->aCharset = aChs; +} + +sal_Bool SfxMedium::SignContents_Impl( sal_Bool bScriptingContent, const ::rtl::OUString& aODFVersion, sal_Bool bHasValidDocumentSignature ) +{ + sal_Bool bChanges = FALSE; + + // the medium should be closed to be able to sign, the caller is responsible to close it + if ( !IsOpen() && !GetError() ) + { + // The component should know if there was a valid document signature, since + // it should show a warning in this case + uno::Sequence< uno::Any > aArgs( 2 ); + aArgs[0] <<= aODFVersion; + aArgs[1] <<= bHasValidDocumentSignature; + ::com::sun::star::uno::Reference< ::com::sun::star::security::XDocumentDigitalSignatures > xSigner( + comphelper::getProcessServiceFactory()->createInstanceWithArguments( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.security.DocumentDigitalSignatures" ) ), + aArgs ), + ::com::sun::star::uno::UNO_QUERY ); + + if ( xSigner.is() ) + { + uno::Reference< embed::XStorage > xWriteableZipStor; + if ( !IsReadOnly() ) + { + // we can reuse the temporary file if there is one already + CreateTempFile( sal_False ); + GetMedium_Impl(); + + try + { + if ( !pImp->xStream.is() ) + throw uno::RuntimeException(); + + xWriteableZipStor = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING, pImp->xStream ); + if ( !xWriteableZipStor.is() ) + throw uno::RuntimeException(); + + uno::Reference< embed::XStorage > xMetaInf = xWriteableZipStor->openStorageElement( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "META-INF" ) ), + embed::ElementModes::READWRITE ); + if ( !xMetaInf.is() ) + throw uno::RuntimeException(); + + if ( bScriptingContent ) + { + // If the signature has already the document signature it will be removed + // after the scripting signature is inserted. + uno::Reference< io::XStream > xStream( + xMetaInf->openStreamElement( xSigner->getScriptingContentSignatureDefaultStreamName(), + embed::ElementModes::READWRITE ), + uno::UNO_SET_THROW ); + + if ( xSigner->signScriptingContent( GetZipStorageToSign_Impl(), xStream ) ) + { + // remove the document signature if any + ::rtl::OUString aDocSigName = xSigner->getDocumentContentSignatureDefaultStreamName(); + if ( aDocSigName.getLength() && xMetaInf->hasByName( aDocSigName ) ) + xMetaInf->removeElement( aDocSigName ); + + uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW ); + xTransact->commit(); + xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW ); + xTransact->commit(); + + // the temporary file has been written, commit it to the original file + Commit(); + bChanges = TRUE; + } + } + else + { + uno::Reference< io::XStream > xStream( + xMetaInf->openStreamElement( xSigner->getDocumentContentSignatureDefaultStreamName(), + embed::ElementModes::READWRITE ), + uno::UNO_SET_THROW ); + + if ( xSigner->signDocumentContent( GetZipStorageToSign_Impl(), xStream ) ) + { + uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW ); + xTransact->commit(); + xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW ); + xTransact->commit(); + + // the temporary file has been written, commit it to the original file + Commit(); + bChanges = TRUE; + } + } + } + catch ( uno::Exception& ) + { + OSL_ENSURE( sal_False, "Couldn't use signing functionality!\n" ); + } + + CloseAndRelease(); + } + else + { + try + { + if ( bScriptingContent ) + xSigner->showScriptingContentSignatures( GetZipStorageToSign_Impl(), uno::Reference< io::XInputStream >() ); + else + xSigner->showDocumentContentSignatures( GetZipStorageToSign_Impl(), uno::Reference< io::XInputStream >() ); + } + catch( uno::Exception& ) + { + OSL_ENSURE( sal_False, "Couldn't use signing functionality!\n" ); + } + } + } + + ResetError(); + } + + return bChanges; +} + +//---------------------------------------------------------------- +sal_uInt16 SfxMedium::GetCachedSignatureState_Impl() +{ + return pImp->m_nSignatureState; +} + +//---------------------------------------------------------------- +void SfxMedium::SetCachedSignatureState_Impl( sal_uInt16 nState ) +{ + pImp->m_nSignatureState = nState; +} + +BOOL SfxMedium::HasStorage_Impl() const +{ + return pImp->xStorage.is(); +} + +BOOL SfxMedium::IsOpen() const +{ + return pInStream || pOutStream || pImp->xStorage.is(); +} + +::rtl::OUString SfxMedium::CreateTempCopyWithExt( const ::rtl::OUString& aURL ) +{ + ::rtl::OUString aResult; + + if ( aURL.getLength() ) + { + sal_Int32 nPrefixLen = aURL.lastIndexOf( '.' ); + String aExt = ( nPrefixLen == -1 ) ? String() : String( aURL.copy( nPrefixLen ) ); + + ::rtl::OUString aNewTempFileURL = ::utl::TempFile( String(), &aExt ).GetURL(); + if ( aNewTempFileURL.getLength() ) + { + INetURLObject aSource( aURL ); + INetURLObject aDest( aNewTempFileURL ); + ::rtl::OUString aFileName = aDest.getName( INetURLObject::LAST_SEGMENT, + true, + INetURLObject::DECODE_WITH_CHARSET ); + if ( aFileName.getLength() && aDest.removeSegment() ) + { + try + { + uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv; + ::ucbhelper::Content aTargetContent( aDest.GetMainURL( INetURLObject::NO_DECODE ), xComEnv ); + ::ucbhelper::Content aSourceContent( aSource.GetMainURL( INetURLObject::NO_DECODE ), xComEnv ); + if ( aTargetContent.transferContent( aSourceContent, + ::ucbhelper::InsertOperation_COPY, + aFileName, + NameClash::OVERWRITE ) ) + { + // Success + aResult = aNewTempFileURL; + } + } + catch( uno::Exception& ) + {} + } + } + } + + return aResult; +} + +sal_Bool SfxMedium::CallApproveHandler( const uno::Reference< task::XInteractionHandler >& xHandler, uno::Any aRequest, sal_Bool bAllowAbort ) +{ + sal_Bool bResult = sal_False; + + if ( xHandler.is() ) + { + try + { + uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( bAllowAbort ? 2 : 1 ); + + ::rtl::Reference< ::framework::ContinuationApprove > pApprove( new ::framework::ContinuationApprove() ); + aContinuations[ 0 ] = pApprove.get(); + + if ( bAllowAbort ) + { + ::rtl::Reference< ::framework::ContinuationAbort > pAbort( new ::framework::ContinuationAbort() ); + aContinuations[ 1 ] = pAbort.get(); + } + + uno::Reference< task::XInteractionRequest > xRequest( new ::framework::InteractionRequest( aRequest, aContinuations ) ); + xHandler->handle( xRequest ); + + bResult = pApprove->isSelected(); + } + catch( const Exception& ) + { + } + } + + return bResult; +} + +::rtl::OUString SfxMedium::SwitchDocumentToTempFile() +{ + // the method returns empty string in case of failure + ::rtl::OUString aResult; + ::rtl::OUString aOrigURL = aLogicName; + + if ( aOrigURL.getLength() ) + { + sal_Int32 nPrefixLen = aOrigURL.lastIndexOf( '.' ); + String aExt = ( nPrefixLen == -1 ) ? String() : String( aOrigURL.copy( nPrefixLen ) ); + ::rtl::OUString aNewURL = ::utl::TempFile( String(), &aExt ).GetURL(); + + // TODO/LATER: In future the aLogicName should be set to shared folder URL + // and a temporary file should be created. Transport_Impl should be impossible then. + if ( aNewURL.getLength() ) + { + uno::Reference< embed::XStorage > xStorage = GetStorage(); + uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY ); + + if ( xOptStorage.is() ) + { + // TODO/LATER: reuse the pImp->pTempFile if it already exists + CanDisposeStorage_Impl( sal_False ); + Close(); + SetPhysicalName_Impl( String() ); + SetName( aNewURL ); + + // remove the readonly state + sal_Bool bWasReadonly = sal_False; + nStorOpenMode = SFX_STREAM_READWRITE; + SFX_ITEMSET_ARG( pSet, pReadOnlyItem, SfxBoolItem, SID_DOC_READONLY, FALSE ); + if ( pReadOnlyItem && pReadOnlyItem->GetValue() ) + bWasReadonly = sal_True; + GetItemSet()->ClearItem( SID_DOC_READONLY ); + + GetMedium_Impl(); + LockOrigFileOnDemand( sal_False, sal_False ); + CreateTempFile( sal_True ); + GetMedium_Impl(); + + if ( pImp->xStream.is() ) + { + try + { + xOptStorage->writeAndAttachToStream( pImp->xStream ); + pImp->xStorage = xStorage; + aResult = aNewURL; + } + catch( uno::Exception& ) + {} + } + + if ( !aResult.getLength() ) + { + Close(); + SetPhysicalName_Impl( String() ); + SetName( aOrigURL ); + if ( bWasReadonly ) + { + // set the readonly state back + nStorOpenMode = SFX_STREAM_READONLY; + GetItemSet()->Put( SfxBoolItem(SID_DOC_READONLY, sal_True)); + } + GetMedium_Impl(); + pImp->xStorage = xStorage; + } + } + } + } + + return aResult; +} + +sal_Bool SfxMedium::SwitchDocumentToFile( ::rtl::OUString aURL ) +{ + // the method is only for storage based documents + sal_Bool bResult = sal_False; + ::rtl::OUString aOrigURL = aLogicName; + + if ( aURL.getLength() && aOrigURL.getLength() ) + { + uno::Reference< embed::XStorage > xStorage = GetStorage(); + uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY ); + + if ( xOptStorage.is() ) + { + // TODO/LATER: reuse the pImp->pTempFile if it already exists + CanDisposeStorage_Impl( sal_False ); + Close(); + SetPhysicalName_Impl( String() ); + SetName( aURL ); + + // open the temporary file based document + GetMedium_Impl(); + LockOrigFileOnDemand( sal_False, sal_False ); + CreateTempFile( sal_True ); + GetMedium_Impl(); + + if ( pImp->xStream.is() ) + { + try + { + uno::Reference< io::XTruncate > xTruncate( pImp->xStream, uno::UNO_QUERY_THROW ); + if ( xTruncate.is() ) + xTruncate->truncate(); + + xOptStorage->writeAndAttachToStream( pImp->xStream ); + pImp->xStorage = xStorage; + bResult = sal_True; + } + catch( uno::Exception& ) + {} + } + + if ( !bResult ) + { + Close(); + SetPhysicalName_Impl( String() ); + SetName( aOrigURL ); + GetMedium_Impl(); + pImp->xStorage = xStorage; + } + } + } + + return bResult; +} + diff --git a/sfx2/source/doc/docfilt.cxx b/sfx2/source/doc/docfilt.cxx new file mode 100644 index 000000000000..1219d30d7b27 --- /dev/null +++ b/sfx2/source/doc/docfilt.cxx @@ -0,0 +1,251 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +// INCLUDE --------------------------------------------------------------- + +#ifdef SOLARIS +// HACK: prevent conflict between STLPORT and Workshop headers on Solaris 8 +#include <ctime> +#endif + +#include <string> // HACK: prevent conflict between STLPORT and Workshop headers +#include <sot/exchange.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameAccess.hpp> + +#include <sfx2/docfac.hxx> +#include <sfx2/docfilt.hxx> +#include "fltfnc.hxx" +#include <sfx2/sfxuno.hxx> +#include <sfx2/objsh.hxx> + +using namespace ::com::sun::star; + +// STATIC DATA ----------------------------------------------------------- + +DBG_NAME(SfxFilter) + +SfxFilter::SfxFilter( const String &rName, + const String &rWildCard, + SfxFilterFlags nType, + sal_uInt32 lFmt, + const String &rTypNm, + sal_uInt16 nIcon, + const String &rMimeType, + const String &rUsrDat, + const String &rServiceName ): + aWildCard(rWildCard, ';'), + lFormat(lFmt), + aTypeName(rTypNm), + aUserData(rUsrDat), + nFormatType(nType), + nDocIcon(nIcon), + aServiceName( rServiceName ), + aMimeType( rMimeType ), + aFilterName( rName ) +{ + String aExts = GetWildcard()(); + String aShort, aLong; + String aRet; + sal_uInt16 nMaxLength = USHRT_MAX; + String aTest; + sal_uInt16 nPos = 0; + while( ( aRet = aExts.GetToken( nPos++, ';' ) ).Len() ) + { + aTest = aRet; + aTest.SearchAndReplace( DEFINE_CONST_UNICODE( "*." ), String() ); + if( aTest.Len() <= nMaxLength ) + { + if( aShort.Len() ) aShort += ';'; + aShort += aRet; + } + else + { + if( aLong.Len() ) aLong += ';'; + aLong += aRet; + } + } + if( aShort.Len() && aLong.Len() ) + { + aShort += ';'; + aShort += aLong; + } + aWildCard = aShort; + + nVersion = SOFFICE_FILEFORMAT_50; + aUIName = aFilterName; +} + +SfxFilter::~SfxFilter() +{ +} + +String SfxFilter::GetDefaultExtension() const +{ + return GetWildcard()().GetToken( 0, ';' ); +} + +String SfxFilter::GetSuffixes() const +{ + String aRet = GetWildcard()(); + while( aRet.SearchAndReplaceAscii( "*.", String() ) != STRING_NOTFOUND ) ; + while( aRet.SearchAndReplace( ';', ',' ) != STRING_NOTFOUND ) ; + return aRet; +} + +const SfxFilter* SfxFilter::GetDefaultFilter( const String& rName ) +{ + return SfxFilterContainer::GetDefaultFilter_Impl( rName ); +} + +const SfxFilter* SfxFilter::GetDefaultFilterFromFactory( const String& rFact ) +{ + return GetDefaultFilter( SfxObjectShell::GetServiceNameFromFactory( rFact ) ); +} + +const SfxFilter* SfxFilter::GetFilterByName( const String& rName ) +{ + SfxFilterMatcher aMatch; + return aMatch.GetFilter4FilterName( rName, 0, 0 ); +} + +String SfxFilter::GetTypeFromStorage( const SotStorage& rStg ) +{ + const char* pType=0; + if ( rStg.IsStream( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "WordDocument" ) ) ) ) + { + if ( rStg.IsStream( String::CreateFromAscii("0Table" ) ) || rStg.IsStream( String::CreateFromAscii("1Table" ) ) ) + pType = "writer_MS_Word_97"; + else + pType = "writer_MS_Word_95"; + } + else if ( rStg.IsStream( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "Book" ) ) ) ) + { + pType = "calc_MS_Excel_95"; + } + else if ( rStg.IsStream( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "Workbook" ) ) ) ) + { + pType = "calc_MS_Excel_97"; + } + else if ( rStg.IsStream( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "PowerPoint Document" ) ) ) ) + { + pType = "impress_MS_PowerPoint_97"; + } + else if ( rStg.IsStream( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "Equation Native" ) ) ) ) + { + pType = "math_MathType_3x"; + } + else + { + sal_Int32 nClipId = ((SotStorage&)rStg).GetFormat(); + if ( nClipId ) + { + const SfxFilter* pFilter = SfxFilterMatcher().GetFilter4ClipBoardId( nClipId ); + if ( pFilter ) + return pFilter->GetTypeName(); + } + } + + return pType ? String::CreateFromAscii(pType) : String(); +} + +String SfxFilter::GetTypeFromStorage( const com::sun::star::uno::Reference< com::sun::star::embed::XStorage >& xStorage, BOOL bTemplate, + String* pFilterName ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + SfxFilterMatcher aMatcher; + const char* pType=0; + String aName; + if ( pFilterName ) + { + aName = *pFilterName; + pFilterName->Erase(); + } + + com::sun::star::uno::Reference< com::sun::star::beans::XPropertySet > xProps( xStorage, com::sun::star::uno::UNO_QUERY ); + if ( xProps.is() ) + { + ::rtl::OUString aMediaType; + xProps->getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) ) >>= aMediaType; + if ( aMediaType.getLength() ) + { + ::com::sun::star::datatransfer::DataFlavor aDataFlavor; + aDataFlavor.MimeType = aMediaType; + sal_uInt32 nClipId = SotExchange::GetFormat( aDataFlavor ); + if ( nClipId ) + { + SfxFilterFlags nMust = SFX_FILTER_IMPORT, nDont = SFX_FILTER_NOTINSTALLED; + if ( bTemplate ) + // template filter was preselected, try to verify + nMust |= SFX_FILTER_TEMPLATEPATH; + else + // template filters shouldn't be detected if not explicitly asked for + nDont |= SFX_FILTER_TEMPLATEPATH; + + const SfxFilter* pFilter = 0; + if ( aName.Len() ) + // get preselected Filter if it matches the desired filter flags + pFilter = aMatcher.GetFilter4FilterName( aName, nMust, nDont ); + + if ( !pFilter || pFilter->GetFormat() != nClipId ) + { + // get filter from storage MediaType + pFilter = aMatcher.GetFilter4ClipBoardId( nClipId, nMust, nDont ); + if ( !pFilter ) + // template filter is asked for , but there isn't one; so at least the "normal" format should be detected + // or storage *is* a template, but bTemplate is not set + pFilter = aMatcher.GetFilter4ClipBoardId( nClipId ); + } + + if ( pFilter ) + { + if ( pFilterName ) + *pFilterName = pFilter->GetName(); + return pFilter->GetTypeName(); + } + } + } + } + + //TODO: do it without SfxFilter + //TODO/LATER: don't yield FilterName, should be done in FWK! + String aRet; + if ( pType ) + { + aRet = String::CreateFromAscii(pType); + if ( pFilterName ) + *pFilterName = aMatcher.GetFilter4EA( aRet )->GetName(); + } + + return aRet; +} diff --git a/sfx2/source/doc/docinf.cxx b/sfx2/source/doc/docinf.cxx new file mode 100644 index 000000000000..d0f6678d8641 --- /dev/null +++ b/sfx2/source/doc/docinf.cxx @@ -0,0 +1,309 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include <sfx2/docinf.hxx> + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyContainer.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/uno/Exception.hpp> + +#include <rtl/ustring.hxx> +#include <tools/debug.hxx> +#include <comphelper/string.hxx> +#include <sot/storage.hxx> +#include <vcl/gdimtf.hxx> + +#include "oleprops.hxx" + +// ============================================================================ + +// stream names +#define STREAM_SUMMARYINFO "\005SummaryInformation" +#define STREAM_DOCSUMMARYINFO "\005DocumentSummaryInformation" + +// usings +using namespace ::com::sun::star; + + +namespace sfx2 { + +sal_uInt32 SFX2_DLLPUBLIC LoadOlePropertySet( + uno::Reference< document::XDocumentProperties> i_xDocProps, + SotStorage* i_pStorage ) +{ + // *** global properties from stream "005SummaryInformation" *** + + // load the property set + SfxOlePropertySet aGlobSet; + ErrCode nGlobError = aGlobSet.LoadPropertySet(i_pStorage, + String( RTL_CONSTASCII_USTRINGPARAM( STREAM_SUMMARYINFO ) ) ); + + // global section + SfxOleSectionRef xGlobSect = aGlobSet.GetSection( SECTION_GLOBAL ); + if( xGlobSect.get() ) + { + // set supported properties + String aStrValue; + util::DateTime aDateTime; + + if( xGlobSect->GetStringValue( aStrValue, PROPID_TITLE ) ) + i_xDocProps->setTitle( aStrValue ); + if( xGlobSect->GetStringValue( aStrValue, PROPID_SUBJECT ) ) + i_xDocProps->setSubject( aStrValue ); + if( xGlobSect->GetStringValue( aStrValue, PROPID_KEYWORDS ) ) { + i_xDocProps->setKeywords( + ::comphelper::string::convertCommaSeparated(aStrValue) ); + } + if( xGlobSect->GetStringValue( aStrValue, PROPID_TEMPLATE ) ) + i_xDocProps->setTemplateName( aStrValue ); + if( xGlobSect->GetStringValue( aStrValue, PROPID_COMMENTS ) ) + i_xDocProps->setDescription( aStrValue ); + + util::DateTime aInvalid; + if( xGlobSect->GetStringValue( aStrValue, PROPID_AUTHOR) ) + i_xDocProps->setAuthor( aStrValue ); + else + i_xDocProps->setAuthor( ::rtl::OUString() ); + if( xGlobSect->GetFileTimeValue( aDateTime, PROPID_CREATED ) ) + i_xDocProps->setCreationDate( aDateTime ); + else + i_xDocProps->setCreationDate( aInvalid ); + + if( xGlobSect->GetStringValue( aStrValue, PROPID_LASTAUTHOR) ) + i_xDocProps->setModifiedBy( aStrValue ); + else + i_xDocProps->setModifiedBy( ::rtl::OUString() ); + if( xGlobSect->GetFileTimeValue( aDateTime, PROPID_LASTSAVED ) ) + i_xDocProps->setModificationDate( aDateTime ); + else + i_xDocProps->setModificationDate( aInvalid ); + + i_xDocProps->setPrintedBy( ::rtl::OUString() ); + if( xGlobSect->GetFileTimeValue( aDateTime, PROPID_LASTPRINTED ) ) + i_xDocProps->setPrintDate( aDateTime ); + else + i_xDocProps->setPrintDate( aInvalid ); + + if( xGlobSect->GetStringValue( aStrValue, PROPID_REVNUMBER ) ) + { + sal_Int16 nRevision = static_cast< sal_Int16 >( aStrValue.ToInt32() ); + if ( nRevision > 0 ) + i_xDocProps->setEditingCycles( nRevision ); + } + + if( xGlobSect->GetFileTimeValue( aDateTime, PROPID_EDITTIME ) ) + { + // subtract offset 1601-01-01 + aDateTime.Year -= 1601; + aDateTime.Month -= 1; + aDateTime.Day -= 1; + try + { + i_xDocProps->setEditingDuration( + aDateTime.Day * 60*60*24 + + aDateTime.Hours * 60*60 + + aDateTime.Minutes * 60 + + aDateTime.Seconds ); + } + catch (lang::IllegalArgumentException &) + { + // ignore + } + } + } + + // *** custom properties from stream "005DocumentSummaryInformation" *** + + // load the property set + SfxOlePropertySet aDocSet; + ErrCode nDocError = aDocSet.LoadPropertySet(i_pStorage, + String( RTL_CONSTASCII_USTRINGPARAM( STREAM_DOCSUMMARYINFO ) ) ); + + // custom properties + SfxOleSectionRef xCustomSect = aDocSet.GetSection( SECTION_CUSTOM ); + if( xCustomSect.get() ) + { + uno::Reference < beans::XPropertyContainer > xUserDefined( + i_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); + ::std::vector< sal_Int32 > aPropIds; + xCustomSect->GetPropertyIds( aPropIds ); + for( ::std::vector< sal_Int32 >::const_iterator aIt = aPropIds.begin(), + aEnd = aPropIds.end(); aIt != aEnd; ++aIt ) + { + ::rtl::OUString aPropName = xCustomSect->GetPropertyName( *aIt ); + uno::Any aPropValue = xCustomSect->GetAnyValue( *aIt ); + if( (aPropName.getLength() > 0) && aPropValue.hasValue() ) { + try { + xUserDefined->addProperty( aPropName, + beans::PropertyAttribute::REMOVEABLE, aPropValue ); + } catch ( uno::Exception& ) { + //ignore + } + } + } + } + + // return code + return (nGlobError != ERRCODE_NONE) ? nGlobError : nDocError; +} + +bool SFX2_DLLPUBLIC SaveOlePropertySet( + uno::Reference< document::XDocumentProperties> i_xDocProps, + SotStorage* i_pStorage, + const uno::Sequence<sal_uInt8> * i_pThumb, + const uno::Sequence<sal_uInt8> * i_pGuid, + const uno::Sequence<sal_uInt8> * i_pHyperlinks) +{ + // *** global properties into stream "005SummaryInformation" *** + + SfxOlePropertySet aGlobSet; + + // set supported properties + SfxOleSection& rGlobSect = aGlobSet.AddSection( SECTION_GLOBAL ); + rGlobSect.SetStringValue( PROPID_TITLE, i_xDocProps->getTitle() ); + rGlobSect.SetStringValue( PROPID_SUBJECT, i_xDocProps->getSubject() ); + String aStr = ::comphelper::string::convertCommaSeparated( + i_xDocProps->getKeywords() ); + rGlobSect.SetStringValue( PROPID_KEYWORDS, aStr ); + rGlobSect.SetStringValue( PROPID_TEMPLATE, i_xDocProps->getTemplateName() ); + rGlobSect.SetStringValue( PROPID_COMMENTS, i_xDocProps->getDescription() ); + rGlobSect.SetStringValue( PROPID_AUTHOR, i_xDocProps->getAuthor() ); + rGlobSect.SetFileTimeValue(PROPID_CREATED, i_xDocProps->getCreationDate()); + rGlobSect.SetStringValue( PROPID_LASTAUTHOR, i_xDocProps->getModifiedBy() ); + rGlobSect.SetFileTimeValue(PROPID_LASTSAVED, + i_xDocProps->getModificationDate() ); + // note: apparently PrintedBy is not supported in file format + rGlobSect.SetFileTimeValue(PROPID_LASTPRINTED, i_xDocProps->getPrintDate()); + + sal_Int32 dur = i_xDocProps->getEditingDuration(); + util::DateTime aEditTime; + // add offset 1601-01-01 + aEditTime.Year = 1601; + aEditTime.Month = 1; + aEditTime.Day = 1; + aEditTime.Hours = static_cast<sal_Int16>(dur / 3600); + aEditTime.Minutes = static_cast<sal_Int16>((dur % 3600) / 60); + aEditTime.Seconds = static_cast<sal_Int16>(dur % 60); + rGlobSect.SetFileTimeValue( PROPID_EDITTIME, aEditTime ); + + rGlobSect.SetStringValue( PROPID_REVNUMBER, + String::CreateFromInt32( i_xDocProps->getEditingCycles() ) ); + if ( i_pThumb && i_pThumb->getLength() ) + rGlobSect.SetThumbnailValue( PROPID_THUMBNAIL, *i_pThumb ); + + // save the property set + ErrCode nGlobError = aGlobSet.SavePropertySet(i_pStorage, + String( RTL_CONSTASCII_USTRINGPARAM( STREAM_SUMMARYINFO ) ) ); + + // *** custom properties into stream "005DocumentSummaryInformation" *** + + SfxOlePropertySet aDocSet; + + // set builtin properties + aDocSet.AddSection( SECTION_BUILTIN ); + + // set custom properties + SfxOleSection& rCustomSect = aDocSet.AddSection( SECTION_CUSTOM ); + + // write GUID + if (i_pGuid) { + const sal_Int32 nPropId = rCustomSect.GetFreePropertyId(); + rCustomSect.SetBlobValue( nPropId, *i_pGuid ); + rCustomSect.SetPropertyName( nPropId, + ::rtl::OUString::createFromAscii("_PID_GUID") ); + } + + // write hyperlinks + if (i_pHyperlinks) { + const sal_Int32 nPropId = rCustomSect.GetFreePropertyId(); + rCustomSect.SetBlobValue( nPropId, *i_pHyperlinks ); + rCustomSect.SetPropertyName( nPropId, + ::rtl::OUString::createFromAscii("_PID_HLINKS") ); + } + + uno::Reference<beans::XPropertySet> xUserDefinedProps( + i_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); + DBG_ASSERT(xUserDefinedProps.is(), "UserDefinedProperties is null"); + uno::Reference<beans::XPropertySetInfo> xPropInfo = + xUserDefinedProps->getPropertySetInfo(); + DBG_ASSERT(xPropInfo.is(), "UserDefinedProperties Info is null"); + uno::Sequence<beans::Property> props = xPropInfo->getProperties(); + for (sal_Int32 i = 0; i < props.getLength(); ++i) { + try { + // skip transient properties + if (~props[i].Attributes & beans::PropertyAttribute::TRANSIENT) + { + const ::rtl::OUString name = props[i].Name; + const sal_Int32 nPropId = rCustomSect.GetFreePropertyId(); + if (rCustomSect.SetAnyValue( nPropId, + xUserDefinedProps->getPropertyValue(name))) { + rCustomSect.SetPropertyName( nPropId, name ); + } + } + } catch (uno::Exception &) { + // may happen with concurrent modification... + DBG_WARNING("SavePropertySet: exception"); + } + } + + // save the property set + ErrCode nDocError = aDocSet.SavePropertySet(i_pStorage, + String( RTL_CONSTASCII_USTRINGPARAM( STREAM_DOCSUMMARYINFO ) ) ); + + // return code + return (nGlobError == ERRCODE_NONE) && (nDocError == ERRCODE_NONE); +} + +uno::Sequence<sal_uInt8> SFX2_DLLPUBLIC convertMetaFile(GDIMetaFile* i_pThumb) +{ + if (i_pThumb) { + BitmapEx aBitmap; + SvMemoryStream aStream; +// magic value 160 taken from GraphicHelper::getThumbnailFormatFromGDI_Impl() + if( i_pThumb->CreateThumbnail( 160, aBitmap ) ) { + aBitmap.GetBitmap().Write( aStream, FALSE, FALSE ); +// uno::Sequence<sal_uInt8> aSeq(aStream.GetSize()); // WRONG + aStream.Seek(STREAM_SEEK_TO_END); + uno::Sequence<sal_uInt8> aSeq(aStream.Tell()); + const sal_uInt8* pBlob( + static_cast<const sal_uInt8*>(aStream.GetData())); + for (sal_Int32 j = 0; j < aSeq.getLength(); ++j) { + aSeq[j] = pBlob[j]; + } + return aSeq; + } + } + return uno::Sequence<sal_uInt8>(); +} + +} // namespace sfx2 + diff --git a/sfx2/source/doc/docinsert.cxx b/sfx2/source/doc/docinsert.cxx new file mode 100644 index 000000000000..2dcca2eadf56 --- /dev/null +++ b/sfx2/source/doc/docinsert.cxx @@ -0,0 +1,305 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include <sfx2/app.hxx> +#include "docinsert.hxx" +#include <sfx2/docfile.hxx> +#include <sfx2/fcontnr.hxx> +#include <sfx2/filedlghelper.hxx> +#include "openflag.hxx" +#include <sfx2/passwd.hxx> + +#include <sfx2/sfxsids.hrc> +#include <com/sun/star/ui/dialogs/ControlActions.hpp> +#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> +#include <com/sun/star/ui/dialogs/ListboxControlActions.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <tools/urlobj.hxx> +#include <vcl/msgbox.hxx> +#include <svl/itemset.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <svl/stritem.hxx> + +#define _SVSTDARR_STRINGSDTOR +#include <svl/svstdarr.hxx> + +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::uno; + +// implemented in 'sfx2/source/appl/appopen.cxx' +extern sal_uInt32 CheckPasswd_Impl( SfxObjectShell* pDoc, SfxItemPool &rPool, SfxMedium* pFile ); + +// ======================================================================= + +namespace sfx2 { + +// ======================================================================= + +// ======================================================================= +// DocumentInserter +// ======================================================================= + +DocumentInserter::DocumentInserter( + sal_Int64 _nFlags, const String& _rFactory, bool _bEnableMultiSelection ) : + + m_sDocFactory ( _rFactory ) + , m_bMultiSelectionEnabled ( _bEnableMultiSelection ) + , m_nDlgFlags ( _nFlags | SFXWB_INSERT | WB_3DLOOK ) + , m_nError ( ERRCODE_NONE ) + , m_pFileDlg ( NULL ) + , m_pItemSet ( NULL ) + , m_pURLList ( NULL ) + +{ +} + +DocumentInserter::~DocumentInserter() +{ + delete m_pFileDlg; +} + +void DocumentInserter::StartExecuteModal( const Link& _rDialogClosedLink ) +{ + m_aDialogClosedLink = _rDialogClosedLink; + m_nError = ERRCODE_NONE; + DELETEZ( m_pURLList ); + if ( !m_pFileDlg ) + { + sal_Int64 nFlags = m_bMultiSelectionEnabled ? ( m_nDlgFlags | SFXWB_MULTISELECTION ) + : m_nDlgFlags; + m_pFileDlg = new FileDialogHelper( nFlags, m_sDocFactory ); + } + m_pFileDlg->StartExecuteModal( LINK( this, DocumentInserter, DialogClosedHdl ) ); +} + +SfxMedium* DocumentInserter::CreateMedium() +{ + SfxMedium* pMedium = NULL; + if ( !m_nError && m_pItemSet && m_pURLList && m_pURLList->Count() > 0 ) + { + DBG_ASSERT( m_pURLList->Count() == 1, "DocumentInserter::CreateMedium(): invalid URL list count" ); + String sURL = *( m_pURLList->GetObject(0) ); + pMedium = new SfxMedium( + sURL, SFX_STREAM_READONLY, FALSE, + SFX_APP()->GetFilterMatcher().GetFilter4FilterName( m_sFilter ), m_pItemSet ); + pMedium->UseInteractionHandler( TRUE ); + SfxFilterMatcher* pMatcher = NULL; + if ( m_sDocFactory.Len() ) + pMatcher = new SfxFilterMatcher( m_sDocFactory ); + else + pMatcher = new SfxFilterMatcher(); + + const SfxFilter* pFilter = NULL; + sal_uInt32 nError = pMatcher->DetectFilter( *pMedium, &pFilter, FALSE ); + if ( nError == ERRCODE_NONE && pFilter ) + pMedium->SetFilter( pFilter ); + else + DELETEZ( pMedium ); + + if ( pMedium && CheckPasswd_Impl( 0, SFX_APP()->GetPool(), pMedium ) == ERRCODE_ABORT ) + pMedium = NULL; + + DELETEZ( pMatcher ); + } + + return pMedium; +} + +SfxMediumList* DocumentInserter::CreateMediumList() +{ + SfxMediumList* pMediumList = new SfxMediumList; + if ( !m_nError && m_pItemSet && m_pURLList && m_pURLList->Count() > 0 ) + { + sal_Int32 i = 0; + sal_Int32 nCount = m_pURLList->Count(); + for ( ; i < nCount; ++i ) + { + String sURL = *( m_pURLList->GetObject( static_cast< USHORT >(i) ) ); + SfxMedium* pMedium = new SfxMedium( + sURL, SFX_STREAM_READONLY, FALSE, + SFX_APP()->GetFilterMatcher().GetFilter4FilterName( m_sFilter ), m_pItemSet ); + + pMedium->UseInteractionHandler( TRUE ); + + SfxFilterMatcher aMatcher( m_sDocFactory ); + const SfxFilter* pFilter = NULL; + sal_uInt32 nError = aMatcher.DetectFilter( *pMedium, &pFilter, FALSE ); + if ( nError == ERRCODE_NONE && pFilter ) + pMedium->SetFilter( pFilter ); + else + DELETEZ( pMedium ); + + if( pMedium && CheckPasswd_Impl( 0, SFX_APP()->GetPool(), pMedium ) != ERRCODE_ABORT ) + pMediumList->Insert( pMedium ); + else + delete pMedium; + } + } + + return pMediumList; +} + +void impl_FillURLList( sfx2::FileDialogHelper* _pFileDlg, SvStringsDtor*& _rpURLList ) +{ + DBG_ASSERT( _pFileDlg, "DocumentInserter::fillURLList(): invalid file dialog" ); + DBG_ASSERT( !_rpURLList, "DocumentInserter::fillURLList(): URLList already exists" ); + Sequence < ::rtl::OUString > aPathSeq = _pFileDlg->GetSelectedFiles(); + + if ( aPathSeq.getLength() ) + { + _rpURLList = new SvStringsDtor; + + for ( USHORT i = 0; i < aPathSeq.getLength(); ++i ) + { + INetURLObject aPathObj( aPathSeq[i] ); + String* pURL = new String( aPathObj.GetMainURL( INetURLObject::NO_DECODE ) ); + _rpURLList->Insert( pURL, _rpURLList->Count() ); + } + } +} + +IMPL_LINK( DocumentInserter, DialogClosedHdl, sfx2::FileDialogHelper*, EMPTYARG ) +{ + DBG_ASSERT( m_pFileDlg, "DocumentInserter::DialogClosedHdl(): no file dialog" ); + + m_nError = m_pFileDlg->GetError(); + if ( ERRCODE_NONE == m_nError ) + impl_FillURLList( m_pFileDlg, m_pURLList ); + + Reference < XFilePicker > xFP = m_pFileDlg->GetFilePicker(); + Reference < XFilePickerControlAccess > xCtrlAccess( xFP, UNO_QUERY ); + if ( xCtrlAccess.is() ) + { + // always create a new itemset + m_pItemSet = new SfxAllItemSet( SFX_APP()->GetPool() ); + + short nDlgType = m_pFileDlg->GetDialogType(); + bool bHasPassword = ( + TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD == nDlgType + || TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS == nDlgType ); + + // check, wether or not we have to display a password box + if ( bHasPassword && m_pFileDlg->IsPasswordEnabled() ) + { + try + { + Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD, 0 ); + sal_Bool bPassWord = sal_False; + if ( ( aValue >>= bPassWord ) && bPassWord ) + { + // ask for the password + SfxPasswordDialog aPasswordDlg( NULL ); + aPasswordDlg.ShowExtras( SHOWEXTRAS_CONFIRM ); + short nRet = aPasswordDlg.Execute(); + if ( RET_OK == nRet ) + { + String aPasswd = aPasswordDlg.GetPassword(); + m_pItemSet->Put( SfxStringItem( SID_PASSWORD, aPasswd ) ); + } + else + { + DELETEZ( m_pItemSet ); + return 0; + } + } + } + catch( IllegalArgumentException ){} + } + + if ( SFXWB_EXPORT == ( m_nDlgFlags & SFXWB_EXPORT ) ) + { + try + { + Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_SELECTION, 0 ); + sal_Bool bSelection = sal_False; + if ( aValue >>= bSelection ) + m_pItemSet->Put( SfxBoolItem( SID_SELECTION, bSelection ) ); + } + catch( IllegalArgumentException ) + { + DBG_ERROR( "FileDialogHelper_Impl::execute: caught an IllegalArgumentException!" ); + } + } + + + // set the read-only flag. When inserting a file, this flag is always set + if ( SFXWB_INSERT == ( m_nDlgFlags & SFXWB_INSERT ) ) + m_pItemSet->Put( SfxBoolItem( SID_DOC_READONLY, sal_True ) ); + else + { + if ( ( TemplateDescription::FILEOPEN_READONLY_VERSION == nDlgType ) ) + { + try + { + Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_READONLY, 0 ); + sal_Bool bReadOnly = sal_False; + if ( ( aValue >>= bReadOnly ) && bReadOnly ) + m_pItemSet->Put( SfxBoolItem( SID_DOC_READONLY, bReadOnly ) ); + } + catch( IllegalArgumentException ) + { + DBG_ERROR( "FileDialogHelper_Impl::execute: caught an IllegalArgumentException!" ); + } + } + } + + if ( TemplateDescription::FILEOPEN_READONLY_VERSION == nDlgType ) + { + try + { + Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::LISTBOX_VERSION, + ControlActions::GET_SELECTED_ITEM_INDEX ); + sal_Int32 nVersion = 0; + if ( ( aValue >>= nVersion ) && nVersion > 0 ) + // open a special version; 0 == current version + m_pItemSet->Put( SfxInt16Item( SID_VERSION, (short)nVersion ) ); + } + catch( IllegalArgumentException ){} + } + } + + m_sFilter = m_pFileDlg->GetRealFilter(); + + if ( m_aDialogClosedLink.IsSet() ) + m_aDialogClosedLink.Call( m_pFileDlg ); + + return 0; +} + +// ======================================================================= + +} // namespace sfx2 + +// ======================================================================= + diff --git a/sfx2/source/doc/docmacromode.cxx b/sfx2/source/doc/docmacromode.cxx new file mode 100644 index 000000000000..249ebbaf02ab --- /dev/null +++ b/sfx2/source/doc/docmacromode.cxx @@ -0,0 +1,436 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include "sfx2/docmacromode.hxx" +#include "sfx2/signaturestate.hxx" +#include "sfx2/docfile.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/document/MacroExecMode.hpp> +#include <com/sun/star/task/ErrorCodeRequest.hpp> +#include <com/sun/star/task/DocumentMacroConfirmationRequest.hpp> +#include <com/sun/star/task/InteractionClassification.hpp> +#include <com/sun/star/security/XDocumentDigitalSignatures.hpp> +/** === end UNO includes === **/ + +#include <comphelper/componentcontext.hxx> +#include <comphelper/processfactory.hxx> +#include <framework/interaction.hxx> +#include <osl/file.hxx> +#include <rtl/ref.hxx> +#include <unotools/securityoptions.hxx> +#include <svtools/sfxecode.hxx> +#include <tools/diagnose_ex.h> +#include <tools/urlobj.hxx> + +//........................................................................ +namespace sfx2 +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::task::XInteractionHandler; + using ::com::sun::star::uno::Any; + using ::com::sun::star::task::XInteractionHandler; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::task::XInteractionContinuation; + using ::com::sun::star::task::XInteractionRequest; + using ::com::sun::star::task::DocumentMacroConfirmationRequest; + using ::com::sun::star::task::ErrorCodeRequest; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::security::XDocumentDigitalSignatures; + using ::com::sun::star::security::DocumentSignatureInformation; + using ::com::sun::star::embed::XStorage; + using ::com::sun::star::task::InteractionClassification_QUERY; + using ::com::sun::star::document::XEmbeddedScripts; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::script::XLibraryContainer; + using ::com::sun::star::container::XNameAccess; + using ::com::sun::star::uno::UNO_QUERY_THROW; + /** === end UNO using === **/ + namespace MacroExecMode = ::com::sun::star::document::MacroExecMode; + + //==================================================================== + //= DocumentMacroMode_Data + //==================================================================== + struct DocumentMacroMode_Data + { + IMacroDocumentAccess& m_rDocumentAccess; + sal_Bool m_bMacroDisabledMessageShown; + sal_Bool m_bDocMacroDisabledMessageShown; + + DocumentMacroMode_Data( IMacroDocumentAccess& rDocumentAccess ) + :m_rDocumentAccess( rDocumentAccess ) + ,m_bMacroDisabledMessageShown( sal_False ) + ,m_bDocMacroDisabledMessageShown( sal_False ) + { + } + }; + + //==================================================================== + //= helper + //==================================================================== + namespace + { + //................................................................ + void lcl_showGeneralSfxErrorOnce( const Reference< XInteractionHandler >& rxHandler, const sal_Int32 nSfxErrorCode, sal_Bool& rbAlreadyShown ) + { + if ( rbAlreadyShown ) + return; + + ErrorCodeRequest aErrorCodeRequest; + aErrorCodeRequest.ErrCode = nSfxErrorCode; + + SfxMedium::CallApproveHandler( rxHandler, makeAny( aErrorCodeRequest ), sal_False ); + rbAlreadyShown = sal_True; + } + + //................................................................ + void lcl_showMacrosDisabledError( const Reference< XInteractionHandler >& rxHandler, sal_Bool& rbAlreadyShown ) + { + lcl_showGeneralSfxErrorOnce( rxHandler, ERRCODE_SFX_MACROS_SUPPORT_DISABLED, rbAlreadyShown ); + } + + //................................................................ + void lcl_showDocumentMacrosDisabledError( const Reference< XInteractionHandler >& rxHandler, sal_Bool& rbAlreadyShown ) + { + lcl_showGeneralSfxErrorOnce( rxHandler, ERRCODE_SFX_DOCUMENT_MACRO_DISABLED, rbAlreadyShown ); + } + + //................................................................ + sal_Bool lcl_showMacroWarning( const Reference< XInteractionHandler >& rxHandler, + const ::rtl::OUString& rDocumentLocation ) + { + DocumentMacroConfirmationRequest aRequest; + aRequest.DocumentURL = rDocumentLocation; + return SfxMedium::CallApproveHandler( rxHandler, makeAny( aRequest ), sal_True ); + } + } + + //==================================================================== + //= DocumentMacroMode + //==================================================================== + //-------------------------------------------------------------------- + DocumentMacroMode::DocumentMacroMode( IMacroDocumentAccess& rDocumentAccess ) + :m_pData( new DocumentMacroMode_Data( rDocumentAccess ) ) + { + } + + //-------------------------------------------------------------------- + DocumentMacroMode::~DocumentMacroMode() + { + } + + //-------------------------------------------------------------------- + sal_Bool DocumentMacroMode::allowMacroExecution() + { + m_pData->m_rDocumentAccess.setCurrentMacroExecMode( MacroExecMode::ALWAYS_EXECUTE_NO_WARN ); + return sal_True; + } + + //-------------------------------------------------------------------- + sal_Bool DocumentMacroMode::disallowMacroExecution() + { + m_pData->m_rDocumentAccess.setCurrentMacroExecMode( MacroExecMode::NEVER_EXECUTE ); + return sal_False; + } + + //-------------------------------------------------------------------- + sal_Bool DocumentMacroMode::adjustMacroMode( const Reference< XInteractionHandler >& rxInteraction ) + { + sal_uInt16 nMacroExecutionMode = m_pData->m_rDocumentAccess.getCurrentMacroExecMode(); + + if ( SvtSecurityOptions().IsMacroDisabled() ) + { + // no macro should be executed at all + lcl_showMacrosDisabledError( rxInteraction, m_pData->m_bMacroDisabledMessageShown ); + return disallowMacroExecution(); + } + + // get setting from configuration if required + enum AutoConfirmation + { + eNoAutoConfirm, + eAutoConfirmApprove, + eAutoConfirmReject + }; + AutoConfirmation eAutoConfirm( eNoAutoConfirm ); + + if ( ( nMacroExecutionMode == MacroExecMode::USE_CONFIG ) + || ( nMacroExecutionMode == MacroExecMode::USE_CONFIG_REJECT_CONFIRMATION ) + || ( nMacroExecutionMode == MacroExecMode::USE_CONFIG_APPROVE_CONFIRMATION ) + ) + { + SvtSecurityOptions aOpt; + switch ( aOpt.GetMacroSecurityLevel() ) + { + case 3: + nMacroExecutionMode = MacroExecMode::FROM_LIST_NO_WARN; + break; + case 2: + nMacroExecutionMode = MacroExecMode::FROM_LIST_AND_SIGNED_WARN; + break; + case 1: + nMacroExecutionMode = MacroExecMode::ALWAYS_EXECUTE; + break; + case 0: + nMacroExecutionMode = MacroExecMode::ALWAYS_EXECUTE_NO_WARN; + break; + default: + OSL_ENSURE( sal_False, "DocumentMacroMode::adjustMacroMode: unexpected macro security level!" ); + nMacroExecutionMode = MacroExecMode::NEVER_EXECUTE; + } + + if ( nMacroExecutionMode == MacroExecMode::USE_CONFIG_REJECT_CONFIRMATION ) + eAutoConfirm = eAutoConfirmReject; + else if ( nMacroExecutionMode == MacroExecMode::USE_CONFIG_APPROVE_CONFIRMATION ) + eAutoConfirm = eAutoConfirmApprove; + } + + if ( nMacroExecutionMode == MacroExecMode::NEVER_EXECUTE ) + return sal_False; + + if ( nMacroExecutionMode == MacroExecMode::ALWAYS_EXECUTE_NO_WARN ) + return sal_True; + + try + { + ::rtl::OUString sReferrer( m_pData->m_rDocumentAccess.getDocumentLocation() ); + + // get document location from medium name and check whether it is a trusted one + // the service is created ohne document version, since it is not of interest here + ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); + Reference< XDocumentDigitalSignatures > xSignatures; + if ( aContext.createComponent( "com.sun.star.security.DocumentDigitalSignatures", xSignatures ) ) + { + INetURLObject aURLReferer( sReferrer ); + + ::rtl::OUString aLocation; + if ( aURLReferer.removeSegment() ) + aLocation = aURLReferer.GetMainURL( INetURLObject::NO_DECODE ); + + if ( aLocation.getLength() && xSignatures->isLocationTrusted( aLocation ) ) + { + return allowMacroExecution(); + } + } + + // at this point it is clear that the document is not in the secure location + if ( nMacroExecutionMode == MacroExecMode::FROM_LIST_NO_WARN ) + { + lcl_showDocumentMacrosDisabledError( rxInteraction, m_pData->m_bDocMacroDisabledMessageShown ); + return disallowMacroExecution(); + } + + // check whether the document is signed with trusted certificate + if ( nMacroExecutionMode != MacroExecMode::FROM_LIST ) + { + // the trusted macro check will also retrieve the signature state ( small optimization ) + sal_Bool bHasTrustedMacroSignature = m_pData->m_rDocumentAccess.hasTrustedScriptingSignature( nMacroExecutionMode != MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN ); + + sal_uInt16 nSignatureState = m_pData->m_rDocumentAccess.getScriptingSignatureState(); + if ( nSignatureState == SIGNATURESTATE_SIGNATURES_BROKEN ) + { + // the signature is broken, no macro execution + if ( nMacroExecutionMode != MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN ) + m_pData->m_rDocumentAccess.showBrokenSignatureWarning( rxInteraction ); + + return disallowMacroExecution(); + } + else if ( bHasTrustedMacroSignature ) + { + // there is trusted macro signature, allow macro execution + return allowMacroExecution(); + } + else if ( nSignatureState == SIGNATURESTATE_SIGNATURES_OK + || nSignatureState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED ) + { + // there is valid signature, but it is not from the trusted author + return disallowMacroExecution(); + } + } + + // at this point it is clear that the document is neither in secure location nor signed with trusted certificate + if ( ( nMacroExecutionMode == MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN ) + || ( nMacroExecutionMode == MacroExecMode::FROM_LIST_AND_SIGNED_WARN ) + ) + { + if ( nMacroExecutionMode == MacroExecMode::FROM_LIST_AND_SIGNED_WARN ) + lcl_showDocumentMacrosDisabledError( rxInteraction, m_pData->m_bDocMacroDisabledMessageShown ); + + return disallowMacroExecution(); + } + } + catch ( Exception& ) + { + if ( ( nMacroExecutionMode == MacroExecMode::FROM_LIST_NO_WARN ) + || ( nMacroExecutionMode == MacroExecMode::FROM_LIST_AND_SIGNED_WARN ) + || ( nMacroExecutionMode == MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN ) + ) + { + return disallowMacroExecution(); + } + } + + // conformation is required + sal_Bool bSecure = sal_False; + + if ( eAutoConfirm == eNoAutoConfirm ) + { + ::rtl::OUString sReferrer( m_pData->m_rDocumentAccess.getDocumentLocation() ); + + ::rtl::OUString aSystemFileURL; + if ( osl::FileBase::getSystemPathFromFileURL( sReferrer, aSystemFileURL ) == osl::FileBase::E_None ) + sReferrer = aSystemFileURL; + + bSecure = lcl_showMacroWarning( rxInteraction, sReferrer ); + } + else + bSecure = ( eAutoConfirm == eAutoConfirmApprove ); + + return ( bSecure ? allowMacroExecution() : disallowMacroExecution() ); + } + + //-------------------------------------------------------------------- + sal_Bool DocumentMacroMode::isMacroExecutionDisallowed() const + { + return m_pData->m_rDocumentAccess.getCurrentMacroExecMode() == MacroExecMode::NEVER_EXECUTE; + } + + //-------------------------------------------------------------------- + sal_Bool DocumentMacroMode::hasMacroLibrary() const + { + sal_Bool bHasMacroLib = sal_False; + try + { + Reference< XEmbeddedScripts > xScripts( m_pData->m_rDocumentAccess.getEmbeddedDocumentScripts() ); + Reference< XLibraryContainer > xContainer; + if ( xScripts.is() ) + xContainer.set( xScripts->getBasicLibraries(), UNO_QUERY_THROW ); + + if ( xContainer.is() ) + { + // a library container exists; check if it's empty + + // if there are libraries except the "Standard" library + // we assume that they are not empty (because they have been created by the user) + if ( !xContainer->hasElements() ) + bHasMacroLib = sal_False; + else + { + ::rtl::OUString aStdLibName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) ); + Sequence< ::rtl::OUString > aElements = xContainer->getElementNames(); + if ( aElements.getLength() ) + { + if ( aElements.getLength() > 1 || !aElements[0].equals( aStdLibName ) ) + bHasMacroLib = sal_True; + else + { + // usually a "Standard" library is always present (design) + // for this reason we must check if it's empty + // + // Note: Since #i73229#, this is not true anymore. There's no default + // "Standard" lib anymore. Wouldn't it be time to get completely + // rid of the "Standard" thingie - this shouldn't be necessary + // anymore, should it? + // 2007-01-25 / frank.schoenheit@sun.com + Reference < XNameAccess > xLib; + Any aAny = xContainer->getByName( aStdLibName ); + aAny >>= xLib; + if ( xLib.is() ) + bHasMacroLib = xLib->hasElements(); + } + } + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return bHasMacroLib; + } + + //-------------------------------------------------------------------- + sal_Bool DocumentMacroMode::storageHasMacros( const Reference< XStorage >& rxStorage ) + { + sal_Bool bHasMacros = sal_False; + if ( rxStorage.is() ) + { + try + { + static const ::rtl::OUString s_sBasicStorageName( ::rtl::OUString::intern( RTL_CONSTASCII_USTRINGPARAM( "Basic" ) ) ); + static const ::rtl::OUString s_sScriptsStorageName( ::rtl::OUString::intern( RTL_CONSTASCII_USTRINGPARAM( "Scripts" ) ) ); + + bHasMacros =( ( rxStorage->hasByName( s_sBasicStorageName ) + && rxStorage->isStorageElement( s_sBasicStorageName ) + ) + || ( rxStorage->hasByName( s_sScriptsStorageName ) + && rxStorage->isStorageElement( s_sScriptsStorageName ) + ) + ); + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + return bHasMacros; + } + + //-------------------------------------------------------------------- + sal_Bool DocumentMacroMode::checkMacrosOnLoading( const Reference< XInteractionHandler >& rxInteraction ) + { + sal_Bool bAllow = sal_False; + if ( SvtSecurityOptions().IsMacroDisabled() ) + { + // no macro should be executed at all + bAllow = disallowMacroExecution(); + } + else + { + if ( m_pData->m_rDocumentAccess.documentStorageHasMacros() || hasMacroLibrary() ) + { + bAllow = adjustMacroMode( rxInteraction ); + } + else if ( !isMacroExecutionDisallowed() ) + { + // if macros will be added by the user later, the security check is obsolete + bAllow = allowMacroExecution(); + } + } + return bAllow; + } + +//........................................................................ +} // namespace sfx2 +//........................................................................ diff --git a/sfx2/source/doc/docstoragemodifylistener.cxx b/sfx2/source/doc/docstoragemodifylistener.cxx new file mode 100644 index 000000000000..625aff0031fc --- /dev/null +++ b/sfx2/source/doc/docstoragemodifylistener.cxx @@ -0,0 +1,96 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include "sfx2/docstoragemodifylistener.hxx" +#include <vos/mutex.hxx> + +/** === begin UNO includes === **/ +/** === end UNO includes === **/ + +//........................................................................ +namespace sfx2 +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::lang::EventObject; + /** === end UNO using === **/ + + //==================================================================== + //= + //==================================================================== + //-------------------------------------------------------------------- + DocumentStorageModifyListener::DocumentStorageModifyListener( IModifiableDocument& _rDocument, ::vos::IMutex& _rMutex ) + :m_pDocument( &_rDocument ) + ,m_rMutex( _rMutex ) + { + } + + //-------------------------------------------------------------------- + DocumentStorageModifyListener::~DocumentStorageModifyListener() + { + } + + //-------------------------------------------------------------------- + void DocumentStorageModifyListener::dispose() + { + ::vos::OGuard aGuard( m_rMutex ); + m_pDocument = NULL; + } + + //-------------------------------------------------------------------- + void SAL_CALL DocumentStorageModifyListener::modified( const EventObject& /*aEvent*/ ) throw (RuntimeException) + { + ::vos::OGuard aGuard( m_rMutex ); + // storageIsModified must not contain any locking! + if ( m_pDocument ) + m_pDocument->storageIsModified(); + } + + //-------------------------------------------------------------------- + void SAL_CALL DocumentStorageModifyListener::disposing( const EventObject& /*Source*/ ) throw (RuntimeException) + { + // not interested in. In particular, we do *not* dispose ourself when a storage we're + // listening at is disposed. The reason here is that this listener instance is *reused* + // in case the document is re-based to another storage. + } + +//........................................................................ +} // namespace sfx2 +//........................................................................ diff --git a/sfx2/source/doc/doctdlg.cxx b/sfx2/source/doc/doctdlg.cxx new file mode 100644 index 000000000000..7a5fea18004f --- /dev/null +++ b/sfx2/source/doc/doctdlg.cxx @@ -0,0 +1,238 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#ifndef _MSGBOX_HXX //autogen +#include <vcl/msgbox.hxx> +#endif +#include <svl/stritem.hxx> +#ifndef GCC +#endif + +#include <sfx2/doctdlg.hxx> +#include "docvor.hxx" +#include "sfxresid.hxx" +#include "sfxtypes.hxx" +#include <sfx2/dispatch.hxx> +#include <sfx2/app.hxx> + +#include <sfx2/sfx.hrc> +#include "doc.hrc" +#include "doctdlg.hrc" +#include <sfx2/basedlgs.hxx> + +//========================================================================= + +SfxDocumentTemplateDlg::SfxDocumentTemplateDlg( Window * pParent, SfxDocumentTemplates* pTempl ) : + + ModalDialog( pParent, SfxResId( DLG_DOC_TEMPLATE ) ), + + aEditFL ( this, SfxResId( FL_EDIT ) ), + aNameEd ( this, SfxResId( ED_NAME ) ), + aTemplateFL ( this, SfxResId( FL_STYLESHEETS ) ), + aRegionFt ( this, SfxResId( FT_SECTION ) ), + aRegionLb ( this, SfxResId( LB_SECTION ) ), + aTemplateFt ( this, SfxResId( FT_STYLESHEETS ) ), + aTemplateLb ( this, SfxResId( LB_STYLESHEETS ) ), + + aOkBt ( this, SfxResId( BT_OK ) ), + aCancelBt ( this, SfxResId( BT_CANCEL ) ), + aHelpBt ( this, SfxResId( BT_HELP ) ), + aEditBt ( this, SfxResId( BT_EDIT ) ), + aOrganizeBt ( this, SfxResId( BT_ORGANIZE ) ), + + pTemplates ( pTempl ), + pHelper ( NULL ) + +{ + FreeResource(); + + pHelper = new SfxModalDefParentHelper( this ); + aOrganizeBt.SetClickHdl(LINK(this, SfxDocumentTemplateDlg, OrganizeHdl)); + aNameEd.SetModifyHdl(LINK(this, SfxDocumentTemplateDlg, NameModify)); + aOkBt.SetClickHdl(LINK(this, SfxDocumentTemplateDlg, OkHdl)); + aEditBt.SetClickHdl(LINK(this, SfxDocumentTemplateDlg, EditHdl)); + Init(); +} + +//------------------------------------------------------------------------- + +SfxDocumentTemplateDlg::~SfxDocumentTemplateDlg() +{ + delete pHelper; +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxDocumentTemplateDlg, EditHdl, Button *, pBut ) +{ + (void)pBut; //unused + if ( !aRegionLb.GetSelectEntryCount() || + !aTemplateLb.GetSelectEntryCount()) + return 0; + + const SfxStringItem aRegion( SID_TEMPLATE_REGIONNAME, aRegionLb.GetSelectEntry() ); + const SfxStringItem aName( SID_TEMPLATE_NAME, aTemplateLb.GetSelectEntry() ); + SFX_APP()->GetAppDispatcher_Impl()->Execute( SID_OPENTEMPLATE, SFX_CALLMODE_ASYNCHRON|SFX_CALLMODE_RECORD, &aRegion, &aName, 0L ); + EndDialog(RET_EDIT_STYLE); + + return 0; +} + +//------------------------------------------------------------------------- + +void SfxDocumentTemplateDlg::Init() +{ + if(!pTemplates->IsConstructed()) + pTemplates->Construct(); + + const USHORT nCount = pTemplates->GetRegionCount(); + for(USHORT i = 0; i < nCount; ++i) + aRegionLb.InsertEntry(pTemplates->GetFullRegionName(i)); + if(!nCount) + aRegionLb.InsertEntry(String(SfxResId(STR_STANDARD))); + aRegionLb.SelectEntryPos(0); + if(nCount) + { + aRegionLb.SetSelectHdl(LINK(this, SfxDocumentTemplateDlg, RegionSelect)); + RegionSelect(&aRegionLb); + aTemplateLb.SetSelectHdl(LINK(this, SfxDocumentTemplateDlg, TemplateSelect)); + aTemplateLb.SetDoubleClickHdl(LINK(this, SfxDocumentTemplateDlg, EditHdl)); + } + else { + Link aLink; + aTemplateLb.SetSelectHdl(aLink); + aTemplateLb.SetDoubleClickHdl(aLink); + } +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxDocumentTemplateDlg, OrganizeHdl, Button *, pButton ) +{ + (void)pButton; //unused + SfxTemplateOrganizeDlg *pDlg = + new SfxTemplateOrganizeDlg(this, pTemplates); + const short nRet = pDlg->Execute(); + delete pDlg; + if(RET_OK == nRet) + { + // View aktualisieren + aRegionLb.SetUpdateMode( FALSE ); + aRegionLb.Clear(); + Init(); + aRegionLb.SetUpdateMode( TRUE ); + aRegionLb.Invalidate(); + aRegionLb.Update(); + aCancelBt.SetText(String(SfxResId(STR_CLOSE))); + } + else if(RET_EDIT_STYLE == nRet) + EndDialog(RET_CANCEL); + return 0; +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxDocumentTemplateDlg, OkHdl, Control *, pControl ) +{ + (void)pControl; //unused + // pruefen, ob eine Vorlage diesen Namens existiert + if(LISTBOX_ENTRY_NOTFOUND != aTemplateLb.GetEntryPos( + GetTemplateName())) { + QueryBox aQuery(this, SfxResId(MSG_CONFIRM_OVERWRITE_TEMPLATE)); + if(RET_NO == aQuery.Execute()) + return 0; + } + EndDialog(RET_OK); + return 0; +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxDocumentTemplateDlg, RegionSelect, ListBox *, pBox ) +{ + const USHORT nRegion = pBox->GetSelectEntryPos(); + const USHORT nCount = pTemplates->GetCount(nRegion); + aTemplateLb.SetUpdateMode(FALSE); + aTemplateLb.Clear(); + for(USHORT i = 0; i < nCount; ++i) + aTemplateLb.InsertEntry(pTemplates->GetName(nRegion, i)); + aTemplateLb.SelectEntryPos(0); + aTemplateLb.SetUpdateMode(TRUE); + aTemplateLb.Invalidate(); + aTemplateLb.Update(); + return 0; +} + +//------------------------------------------------------------------------- + +IMPL_LINK_INLINE_START( SfxDocumentTemplateDlg, TemplateSelect, ListBox *, pBox ) +{ + aNameEd.SetText(pBox->GetSelectEntry()); + NameModify(&aNameEd); + return 0; +} +IMPL_LINK_INLINE_END( SfxDocumentTemplateDlg, TemplateSelect, ListBox *, pBox ) + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxDocumentTemplateDlg, NameModify, Edit *, pBox ) +{ + const String &rText=pBox->GetText(); + if(!rText.Len()) + aEditBt.Enable(); + else + { + aTemplateLb.SelectEntry(rText); + aEditBt.Enable( aTemplateLb.GetSelectEntry() == rText ); + } + + aOkBt.Enable( rText.Len() > 0 ); + return 0; +} + +//------------------------------------------------------------------------- + +String SfxDocumentTemplateDlg::GetTemplatePath() +{ + const String& rPath=GetTemplateName(); + if(pTemplates->GetRegionCount()) + return pTemplates->GetTemplatePath( + aRegionLb.GetSelectEntryPos(), rPath); + return pTemplates->GetDefaultTemplatePath(rPath); +} + +//------------------------------------------------------------------------- + +void SfxDocumentTemplateDlg::NewTemplate(const String &rPath) +{ + pTemplates->NewTemplate( + aRegionLb.GetSelectEntryPos(), GetTemplateName(), rPath); +} + diff --git a/sfx2/source/doc/doctdlg.hrc b/sfx2/source/doc/doctdlg.hrc new file mode 100644 index 000000000000..8deed4699f3b --- /dev/null +++ b/sfx2/source/doc/doctdlg.hrc @@ -0,0 +1,42 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#define FT_SECTION 1 +#define LB_SECTION 2 +#define FT_STYLESHEETS 3 +#define LB_STYLESHEETS 4 +#define BT_ORGANIZE 20 +#define BT_HELP 21 +#define FL_EDIT 5 +#define FT_NAME 6 +#define ED_NAME 7 +#define BT_OK 10 +#define BT_SECTION 11 +#define BT_EDIT 12 +#define BT_NEW 13 +#define BT_DELETE 15 +#define BT_CANCEL 16 +#define FL_STYLESHEETS 17 diff --git a/sfx2/source/doc/doctdlg.src b/sfx2/source/doc/doctdlg.src new file mode 100644 index 000000000000..91d966fbd2d5 --- /dev/null +++ b/sfx2/source/doc/doctdlg.src @@ -0,0 +1,146 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <sfx2/sfx.hrc> +#include "doc.hrc" +#include "doctdlg.hrc" + +ModalDialog DLG_DOC_TEMPLATE +{ + HelpId = SID_DOCTEMPLATE ; + OutputSize = TRUE ; + SVLook = TRUE ; + Size = MAP_APPFONT ( 280 , 128 ) ; + Text [ en-US ] = "Templates" ; + Moveable = TRUE ; + FixedLine FL_EDIT + { + Pos = MAP_APPFONT ( 6 , 3 ) ; + Size = MAP_APPFONT ( 212 , 8 ) ; + Text [ en-US ] = "New template" ; + }; + Edit ED_NAME + { + Border = TRUE ; + Pos = MAP_APPFONT ( 12 , 14 ) ; + Size = MAP_APPFONT ( 200 , 12 ) ; + }; + FixedLine FL_STYLESHEETS + { + Pos = MAP_APPFONT ( 6 , 32 ) ; + Size = MAP_APPFONT ( 212 , 8 ) ; + Text [ en-US ] = "Templates" ; + }; + FixedText FT_SECTION + { + Pos = MAP_APPFONT ( 12 , 43 ) ; + Size = MAP_APPFONT ( 97 , 10 ) ; + Text [ en-US ] = "~Categories" ; + }; + ListBox LB_SECTION + { + Border = TRUE ; + Pos = MAP_APPFONT ( 12 , 56 ) ; + Size = MAP_APPFONT ( 97 , 66 ) ; + }; + FixedText FT_STYLESHEETS + { + Pos = MAP_APPFONT ( 115 , 43 ) ; + Size = MAP_APPFONT ( 97 , 10 ) ; + Text [ en-US ] = "~Templates" ; + }; + ListBox LB_STYLESHEETS + { + Border = TRUE ; + Pos = MAP_APPFONT ( 115 , 56 ) ; + Size = MAP_APPFONT ( 97 , 66 ) ; + }; + OKButton BT_OK + { + Pos = MAP_APPFONT ( 224 , 6 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + DefButton = TRUE ; + Disable = TRUE ; + }; + CancelButton BT_CANCEL + { + Pos = MAP_APPFONT ( 224 , 23 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + }; + HelpButton BT_HELP + { + Pos = MAP_APPFONT ( 224 , 43 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + }; + PushButton BT_EDIT + { + Pos = MAP_APPFONT ( 224 , 62 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + Text [ en-US ] = "~Edit" ; + }; + PushButton BT_ORGANIZE + { + Pos = MAP_APPFONT ( 224 , 79 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + Text [ en-US ] = "~Organizer..." ; + }; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sfx2/source/doc/doctempl.cxx b/sfx2/source/doc/doctempl.cxx new file mode 100644 index 000000000000..db6f2a2d133f --- /dev/null +++ b/sfx2/source/doc/doctempl.cxx @@ -0,0 +1,2735 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include <limits.h> +#include <com/sun/star/uno/Any.h> +#include <vos/mutex.hxx> +#include <vos/thread.hxx> + +#ifndef _SV_RESARY_HXX +#include <tools/resary.hxx> +#endif +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <unotools/localedatawrapper.hxx> +#include <unotools/pathoptions.hxx> +#include <tools/string.hxx> +#include <tools/urlobj.hxx> +#include <svtools/ehdl.hxx> +#include <svtools/sfxecode.hxx> +#include <comphelper/processfactory.hxx> +#include <ucbhelper/content.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertyContainer.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/document/XTypeDetection.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/frame/XDocumentTemplates.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XPersist.hpp> +#include <com/sun/star/lang/XLocalizable.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/ucb/ContentInfo.hpp> +#include <com/sun/star/ucb/InsertCommandArgument.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <com/sun/star/ucb/TransferInfo.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/ucb/XAnyCompareFactory.hpp> +#include <com/sun/star/ucb/XAnyCompare.hpp> +#include <com/sun/star/ucb/NumberedSortingInfo.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> + +#include "sfxurlrelocator.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::document; +using namespace ::rtl; +using namespace ::ucbhelper; + + +#include <sfx2/doctempl.hxx> +#include <sfx2/docfac.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/objsh.hxx> +#include "sfxtypes.hxx" +#include <sfx2/app.hxx> +#include "sfxresid.hxx" +#include "doc.hrc" +#include <sfx2/fcontnr.hxx> +#include <svtools/templatefoldercache.hxx> + +#include <comphelper/storagehelper.hxx> +#include <unotools/ucbhelper.hxx> + +//======================================================================== + +// #define DONT_USE_HIERARCHY + +#define TITLE "Title" +#define IS_FOLDER "IsFolder" +#define PROPERTY_TYPE "TypeDescription" +#define TARGET_URL "TargetURL" +#define TYPE_FOLDER "application/vnd.sun.star.hier-folder" +#define TYPE_LINK "application/vnd.sun.star.hier-link" +#define TYPE_FSYS_FOLDER "application/vnd.sun.staroffice.fsys-folder" + +#define TARGET_DIR_URL "TargetDirURL" +#define COMMAND_DELETE "delete" +#define COMMAND_TRANSFER "transfer" + +#define STANDARD_FOLDER "standard" + +#define SERVICENAME_TYPEDETECTION "com.sun.star.document.TypeDetection" +#define TYPEDETECTION_PARAMETER "FileName" +//#define SERVICENAME_OLD_TYPEDETECTION "com.sun.star.frame.FrameLoaderFactory" +//#define PARAMETER_OLD_TYPEDETECTION "DeepDetection" +#define SERVICENAME_DOCINFO "com.sun.star.document.DocumentProperties" +#define SERVICENAME_DOCTEMPLATES "com.sun.star.frame.DocumentTemplates" +#define SERVICENAME_DESKTOP "com.sun.star.frame.Desktop" + +//======================================================================== + +class RegionData_Impl; + +namespace DocTempl { + +class DocTempl_EntryData_Impl +{ + RegionData_Impl* mpParent; + SfxObjectShellLock mxObjShell; + OUString maTitle; + OUString maOwnURL; + OUString maTargetURL; + sal_Bool mbIsOwner : 1; + sal_Bool mbDidConvert: 1; + +private: + RegionData_Impl* GetParent() const { return mpParent; } + +public: + DocTempl_EntryData_Impl( RegionData_Impl* pParent, + const OUString& rTitle ); + + const OUString& GetTitle() const { return maTitle; } + const OUString& GetTargetURL(); + const OUString& GetHierarchyURL(); + + void SetTitle( const OUString& rTitle ) { maTitle = rTitle; } + void SetTargetURL( const OUString& rURL ) { maTargetURL = rURL; } + void SetHierarchyURL( const OUString& rURL) { maOwnURL = rURL; } + + int Compare( const OUString& rTitle ) const; + + SfxObjectShellRef CreateObjectShell(); + sal_Bool DeleteObjectShell(); +}; + +} + +using namespace ::DocTempl; + +// ------------------------------------------------------------------------ + +class RegionData_Impl +{ + DECLARE_LIST( EntryList_Impl, DocTempl_EntryData_Impl* ) + const SfxDocTemplate_Impl* mpParent; + EntryList_Impl maEntries; + OUString maTitle; + OUString maOwnURL; + OUString maTargetURL; + +private: + long GetEntryPos( const OUString& rTitle, + sal_Bool& rFound ) const; + const SfxDocTemplate_Impl* GetParent() const { return mpParent; } + +public: + RegionData_Impl( const SfxDocTemplate_Impl* pParent, + const OUString& rTitle ); + ~RegionData_Impl(); + + void SetTargetURL( const OUString& rURL ) { maTargetURL = rURL; } + void SetHierarchyURL( const OUString& rURL) { maOwnURL = rURL; } + + DocTempl_EntryData_Impl* GetEntry( ULONG nIndex ) const; + DocTempl_EntryData_Impl* GetEntry( const OUString& rName ) const; + DocTempl_EntryData_Impl* GetByTargetURL( const OUString& rName ) const; + + const OUString& GetTitle() const { return maTitle; } + const OUString& GetTargetURL(); + const OUString& GetHierarchyURL(); + + ULONG GetCount() const; + + void SetTitle( const OUString& rTitle ) { maTitle = rTitle; } + + void AddEntry( const OUString& rTitle, + const OUString& rTargetURL, + USHORT *pPos = NULL ); + void DeleteEntry( ULONG nIndex ); + + int Compare( const OUString& rTitle ) const + { return maTitle.compareTo( rTitle ); } + int Compare( RegionData_Impl* pCompareWith ) const; +}; + +DECLARE_LIST( RegionList_Impl, RegionData_Impl* ) + +// ------------------------------------------------------------------------ + +class SfxDocTemplate_Impl : public SvRefBase +{ + uno::Reference< XPersist > mxInfo; + uno::Reference< XDocumentTemplates > mxTemplates; + + ::osl::Mutex maMutex; + OUString maRootURL; + OUString maStandardGroup; + RegionList_Impl maRegions; + sal_Bool mbConstructed; + + uno::Reference< XAnyCompareFactory > m_rCompareFactory; + + // the following member is intended to prevent clearing of the global data when it is in use + // TODO/LATER: it still does not make the implementation complete thread-safe + sal_Int32 mnLockCounter; + +private: + void Clear(); + +public: + SfxDocTemplate_Impl(); + ~SfxDocTemplate_Impl(); + + void IncrementLock(); + void DecrementLock(); + + sal_Bool Construct( ); + void CreateFromHierarchy( Content &rTemplRoot ); + void ReInitFromComponent(); + void AddRegion( const OUString& rTitle, + Content& rContent ); + + void Rescan(); + + void DeleteRegion( ULONG nIndex ); + + ULONG GetRegionCount() const + { return maRegions.Count(); } + RegionData_Impl* GetRegion( const OUString& rName ) const; + RegionData_Impl* GetRegion( ULONG nIndex ) const; + void GetTemplates( Content& rTargetFolder, + Content& rParentFolder, + RegionData_Impl* pRegion ); + + long GetRegionPos( const OUString& rTitle, + sal_Bool& rFound ) const; + + sal_Bool GetTitleFromURL( const OUString& rURL, OUString& aTitle ); + sal_Bool InsertRegion( RegionData_Impl *pData, ULONG nPos = LIST_APPEND ); + OUString GetRootURL() const { return maRootURL; } + + uno::Reference< XDocumentTemplates > getDocTemplates() { return mxTemplates; } +}; + +// ------------------------------------------------------------------------ + +class DocTemplLocker_Impl +{ + SfxDocTemplate_Impl& m_aDocTempl; +public: + DocTemplLocker_Impl( SfxDocTemplate_Impl& aDocTempl ) + : m_aDocTempl( aDocTempl ) + { + m_aDocTempl.IncrementLock(); + } + + ~DocTemplLocker_Impl() + { + m_aDocTempl.DecrementLock(); + } +}; + +// ------------------------------------------------------------------------ + +#ifndef SFX_DECL_DOCTEMPLATES_DEFINED +#define SFX_DECL_DOCTEMPLATES_DEFINED +SV_DECL_REF(SfxDocTemplate_Impl) +#endif + +SV_IMPL_REF(SfxDocTemplate_Impl) + +// ------------------------------------------------------------------------ + +SfxDocTemplate_Impl *gpTemplateData = 0; + +// ----------------------------------------------------------------------- + +static sal_Bool getTextProperty_Impl( Content& rContent, + const OUString& rPropName, + OUString& rPropValue ); + +//======================================================================== +//======================================================================== +//======================================================================== + +String SfxDocumentTemplates::GetFullRegionName +( + USHORT nIdx // Index des Bereiches +) const + +/* [Beschreibung] + + Liefert den logischen Namen eines Bereiches Plus seinem Pfad + + + [R"uckgabewert] Referenz auf diesen Namen + +*/ + +{ + // First: find the RegionData for the index + String aName; + + DocTemplLocker_Impl aLocker( *pImp ); + + if ( pImp->Construct() ) + { + RegionData_Impl *pData1 = pImp->GetRegion( nIdx ); + + if ( pData1 ) + aName = pData1->GetTitle(); + + // --**-- here was some code which appended the path to the + // group if there was more than one with the same name. + // this should not happen anymore + } + + return aName; +} + +//------------------------------------------------------------------------ + +const String& SfxDocumentTemplates::GetRegionName +( + USHORT nIdx // Index des Bereiches +) const + +/* [Beschreibung] + + Liefert den logischen Namen eines Bereiches + + + [R"uckgabewert] + + const String& Referenz auf diesen Namen + +*/ +{ + static String maTmpString; + + DocTemplLocker_Impl aLocker( *pImp ); + + if ( pImp->Construct() ) + { + RegionData_Impl *pData = pImp->GetRegion( nIdx ); + + if ( pData ) + maTmpString = pData->GetTitle(); + else + maTmpString.Erase(); + } + else + maTmpString.Erase(); + + return maTmpString; +} + + +//------------------------------------------------------------------------ + +USHORT SfxDocumentTemplates::GetRegionNo +( + const String &rRegion // Name der Region +) const + +/* [Beschreibung] + + Liefert den Index f"ur einen logischen Namen eines Bereiches. + + + [R"uckgabewert] + + USHORT Index von 'rRegion' oder USHRT_MAX falls unbekannt + +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return USHRT_MAX; + + sal_Bool bFound; + ULONG nIndex = pImp->GetRegionPos( rRegion, bFound ); + + if ( bFound ) + return (USHORT) nIndex; + else + return USHRT_MAX; +} + + +//------------------------------------------------------------------------ + +USHORT SfxDocumentTemplates::GetRegionCount() const + +/* [Beschreibung] + + Liefert die Anzahl der Bereiche + + + [R"uckgabewert] + + USHORT Anzahl der Bereiche + +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return 0; + + ULONG nCount = pImp->GetRegionCount(); + + return (USHORT) nCount; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::IsRegionLoaded( USHORT nIdx ) const +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return sal_False; + + RegionData_Impl *pData = pImp->GetRegion( nIdx ); + + if ( pData ) + return sal_True; + else + return sal_False; +} + +//------------------------------------------------------------------------ + +USHORT SfxDocumentTemplates::GetCount +( + const String& rName /* Name des Bereiches, dessen Eintrags- + anzahl ermittelt werden soll */ + +) const + +/* [Beschreibung] + + Liefert die Anzahl der Eintr"age eines Bereiches + + + [R"uckgabewert] + + USHORT Anzahl der Eintr"age + +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return 0; + + RegionData_Impl *pData = pImp->GetRegion( rName ); + ULONG nCount = 0; + + if ( pData ) + nCount = pData->GetCount(); + + return (USHORT) nCount; +} + +//------------------------------------------------------------------------ + +USHORT SfxDocumentTemplates::GetCount +( + USHORT nRegion /* Index des Bereiches, dessen Eintrags- + anzahl ermittelt werden soll */ + +) const + +/* [Beschreibung] + + Liefert die Anzahl der Eintr"age eines Bereiches + + + [R"uckgabewert] Anzahl der Eintr"age + +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return 0; + + RegionData_Impl *pData = pImp->GetRegion( nRegion ); + ULONG nCount = 0; + + if ( pData ) + nCount = pData->GetCount(); + + return (USHORT) nCount; +} + +//------------------------------------------------------------------------ + +const String& SfxDocumentTemplates::GetName +( + USHORT nRegion, // Index des Bereiches, in dem der Eintrag liegt + USHORT nIdx // Index des Eintrags +) const + +/* [Beschreibung] + + Liefert den logischen Namen eines Eintrags eines Bereiches + + + [R"uckgabewert] + + const String& Name des Eintrags + +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + static String maTmpString; + + if ( pImp->Construct() ) + { + DocTempl_EntryData_Impl *pEntry = NULL; + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + + if ( pRegion ) + pEntry = pRegion->GetEntry( nIdx ); + + if ( pEntry ) + maTmpString = pEntry->GetTitle(); + else + maTmpString.Erase(); + } + else + maTmpString.Erase(); + + return maTmpString; +} + +//------------------------------------------------------------------------ + +String SfxDocumentTemplates::GetFileName +( + USHORT nRegion, // Index des Bereiches, in dem der Eintrag liegt + USHORT nIdx // Index des Eintrags +) const + +/* [Beschreibung] + + Liefert den Dateinamen eines Eintrags eines Bereiches + + [R"uckgabewert] Dateiname des Eintrags + +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return String(); + + DocTempl_EntryData_Impl *pEntry = NULL; + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + + if ( pRegion ) + pEntry = pRegion->GetEntry( nIdx ); + + if ( pEntry ) + { + INetURLObject aURLObj( pEntry->GetTargetURL() ); + return aURLObj.getName( INetURLObject::LAST_SEGMENT, true, + INetURLObject::DECODE_WITH_CHARSET ); + } + else + return String(); +} + +//------------------------------------------------------------------------ + +String SfxDocumentTemplates::GetPath +( + USHORT nRegion, // Index des Bereiches, in dem der Eintrag liegt + USHORT nIdx // Index des Eintrags +) const + +/* [Beschreibung] + + Liefert den Dateinamen mit vollst"andigem Pfad zu der einem + Eintrag zugeordneten Datei + + + [R"uckgabewert] + + String Dateiname mit vollst"andigem Pfad + +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return String(); + + DocTempl_EntryData_Impl *pEntry = NULL; + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + + if ( pRegion ) + pEntry = pRegion->GetEntry( nIdx ); + + if ( pEntry ) + return pEntry->GetTargetURL(); + else + return String(); +} + +//------------------------------------------------------------------------ + +String SfxDocumentTemplates::GetTemplatePath +( + USHORT nRegion, // Index des Bereiches, in dem der Eintrag liegt + const String& rLongName // logischer Name des Eintrags +) const + +/* [Beschreibung] + + Liefert den Dateinamen mit vollst"andigem Pfad zu der einem + Eintrag zugeordneten Datei + + + [R"uckgabewert] + + String Dateiname mit vollst"andigem Pfad + +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return String(); + + DocTempl_EntryData_Impl *pEntry = NULL; + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + + if ( pRegion ) + pEntry = pRegion->GetEntry( rLongName ); + + if ( pEntry ) + return pEntry->GetTargetURL(); + else if ( pRegion ) + { + // a new template is going to be inserted, generate a new URL + // TODO/LATER: if the title is localized, use minimized URL in future + + // --**-- extension handling will become more complicated, because + // every new document type will have it's own extension + // e.g.: .stw or .stc instead of .vor + INetURLObject aURLObj( pRegion->GetTargetURL() ); + aURLObj.insertName( rLongName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + OUString aExtension = aURLObj.getExtension(); + + if ( ! aExtension.getLength() ) + aURLObj.setExtension( OUString( RTL_CONSTASCII_USTRINGPARAM( "vor" ) ) ); + + return aURLObj.GetMainURL( INetURLObject::NO_DECODE ); + } + else + return String(); +} + +//------------------------------------------------------------------------ + +String SfxDocumentTemplates::GetDefaultTemplatePath +( + const String& rLongName +) + +/* [Beschreibung] + + Liefert den Standardpfad zu Dokumentvorlagen + + + [R"uckgabewert] + + String Standardpfad zu Dokumentvorlagen + +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return String(); + + // the first region in the list should always be the standard + // group + // --**-- perhaps we have to create it ??? + RegionData_Impl *pRegion = pImp->GetRegion( 0L ); + DocTempl_EntryData_Impl *pEntry = NULL; + + if ( pRegion ) + pEntry = pRegion->GetEntry( rLongName ); + + if ( pEntry ) + return pEntry->GetTargetURL(); + else if ( pRegion ) + { + // a new template is going to be inserted, generate a new URL + // TODO/LATER: if the title is localized, use minimized URL in future + + INetURLObject aURLObj( pRegion->GetTargetURL() ); + aURLObj.insertName( rLongName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + OUString aExtension = aURLObj.getExtension(); + + if ( ! aExtension.getLength() ) + aURLObj.setExtension( OUString( RTL_CONSTASCII_USTRINGPARAM( "vor" ) ) ); + + return aURLObj.GetMainURL( INetURLObject::NO_DECODE ); + } + else + return String(); + +/* dv! missing: create the directory, if it doesn't exists + + + DBG_ASSERT(aDirs.GetTokenCount(cDelim), "Keine Bereiche"); + DirEntry aPath(aDirs.GetToken(0, cDelim)); + + // Verzeichnis anlegen + if(!aPath.MakeDir()) + return String(); + + MakeFileName_Impl(aPath, rLongName, sal_True); + SfxTemplateDir *pEntry = new SfxTemplateDir; + SfxTemplateDirEntryPtr pDirEntry = + new SfxTemplateDirEntry( String( '.' ), aPath.GetPath() ); + pDirEntry->SetContent(new SfxTemplateDir(aPath.GetPath())); + pEntry->Insert(pDirEntry, pEntry->Count()); + pDirs->Insert(pEntry, pDirs->Count()); + return aPath.GetFull(); +*/ +} + +//------------------------------------------------------------------------ + +::rtl::OUString SfxDocumentTemplates::GetTemplateTargetURLFromComponent( const ::rtl::OUString& aGroupName, + const ::rtl::OUString& aTitle ) +{ + DocTemplLocker_Impl aLocker( *pImp ); + + INetURLObject aTemplateObj( pImp->GetRootURL() ); + + aTemplateObj.insertName( aGroupName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + aTemplateObj.insertName( aTitle, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + + ::rtl::OUString aResult; + Content aTemplate; + uno::Reference< XCommandEnvironment > aCmdEnv; + if ( Content::create( aTemplateObj.GetMainURL( INetURLObject::NO_DECODE ), aCmdEnv, aTemplate ) ) + { + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + getTextProperty_Impl( aTemplate, aPropName, aResult ); + aResult = SvtPathOptions().SubstituteVariable( aResult ); + } + + return aResult; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::SaveDir +( +// SfxTemplateDir& rDir // das zu speichernde Directory +) + +/* [Beschreibung] + + Speichert das Directory rDir + + + [R"uckgabewert] + + sal_Bool sal_False, + Schreibfehler + + sal_True + gespeichert + +*/ + +{ + return sal_True; +} + +//------------------------------------------------------------------------ + +void SfxDocumentTemplates::NewTemplate +( + USHORT nRegion, /* Index des Bereiches, in dem die Vorlage + angelegt werden soll */ + + const String& rLongName, // logischer Name der neuen Vorlage + const String& rFileName // Dateiname der neuen Vorlage +) + +/* [Beschreibung] + + Eintragen einer neuen Dokumentvorlage in die Verwaltungsstrukturen + Das "Uberschreiben einer Vorlage gleichen Namens wird + verhindert (!! Fehlermeldung) + +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return; + + DocTempl_EntryData_Impl *pEntry; + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + + // do nothing if there is no region with that index + if ( !pRegion ) + return; + + pEntry = pRegion->GetEntry( rLongName ); + + // do nothing if there is already an entry with that name + if ( pEntry ) + return; + + uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates(); + + if ( xTemplates->addTemplate( pRegion->GetTitle(), rLongName, rFileName ) ) + pRegion->AddEntry( rLongName, rFileName ); +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::CopyOrMove +( + USHORT nTargetRegion, // Index des Zielbereiches + USHORT nTargetIdx, // Index Zielposition + USHORT nSourceRegion, // Index des Quellbereiches + USHORT nSourceIdx, /* Index der zu kopierenden / zu verschiebenden + Dokumentvorlage */ + sal_Bool bMove // kopieren / verschieben +) + +/* [Beschreibung] + + Kopieren oder Verschieben einer Dokumentvorlage + + [R"uckgabewert] + + sal_Bool sal_True + Aktion konnte ausgef"uhrt werden + + sal_False + Aktion konnte nicht ausgef2uhrt werden + [Querverweise] + + <SfxDocumentTemplates::Move(USHORT,USHORT,USHORT,USHORT)> + <SfxDocumentTemplates::Copy(USHORT,USHORT,USHORT,USHORT)> +*/ + +{ + /* to perform a copy or move, we need to send a transfer command to + the destination folder with the URL of the source as parameter. + ( If the destination content doesn't support the transfer command, + we could try a copy ( and delete ) instead. ) + We need two transfers ( one for the real template and one for its + representation in the hierarchy ) + ... + */ + + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return sal_False; + + // Don't copy or move any folders + if( nSourceIdx == USHRT_MAX ) + return sal_False ; + + if ( nSourceRegion == nTargetRegion ) + { + DBG_ERRORFILE( "Don't know, what to do!" ); + return sal_False; +#if 0 + // Verschieben einer Vorlage innerhalb eines Bereiches + // --> nur Verwaltungsdaten aktualisieren + if ( bMove && nTargetRegion == nSourceRegion ) + { + if(nTargetIdx == USHRT_MAX) + nTargetIdx = 0; + const SfxTemplateDirEntryPtr pEntry = rTargetDir[nSourceIdx]; + rTargetDir.Insert(pEntry, nTargetIdx); + if(nTargetIdx < nSourceIdx) + ++nSourceIdx; + rTargetDir.Remove(nSourceIdx); + return SaveDir(rTargetDir); + } +#endif + } + + RegionData_Impl *pSourceRgn = pImp->GetRegion( nSourceRegion ); + if ( !pSourceRgn ) + return sal_False; + + DocTempl_EntryData_Impl *pSource = pSourceRgn->GetEntry( nSourceIdx ); + if ( !pSource ) + return sal_False; + + RegionData_Impl *pTargetRgn = pImp->GetRegion( nTargetRegion ); + if ( !pTargetRgn ) + return sal_False; + + OUString aTitle = pSource->GetTitle(); + + uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates(); + + if ( xTemplates->addTemplate( pTargetRgn->GetTitle(), + aTitle, + pSource->GetTargetURL() ) ) + { + + INetURLObject aSourceObj( pSource->GetTargetURL() ); + + ::rtl::OUString aNewTargetURL = GetTemplateTargetURLFromComponent( pTargetRgn->GetTitle(), aTitle ); + if ( !aNewTargetURL.getLength() ) + return sal_False; + + if ( bMove ) + { + // --**-- delete the original file + sal_Bool bDeleted = xTemplates->removeTemplate( pSourceRgn->GetTitle(), + pSource->GetTitle() ); + if ( bDeleted ) + pSourceRgn->DeleteEntry( nSourceIdx ); + else + { + if ( xTemplates->removeTemplate( pTargetRgn->GetTitle(), aTitle ) ) + return sal_False; // will trigger tetry with copy instead of move + + // if it is not possible to remove just created template ( must be possible! ) + // it is better to report success here, since at least the copy has succeeded + // TODO/LATER: solve it more gracefully in future + } + } + + pTargetRgn->AddEntry( aTitle, aNewTargetURL, &nTargetIdx ); + + return sal_True; + } + + // --**-- wenn aktuell das File geoeffnet ist, + // muss es hinterher wieder geoeffnet werden + + return sal_False; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::Move +( + USHORT nTargetRegion, // Index des Zielbereiches + USHORT nTargetIdx, // Index Zielposition + USHORT nSourceRegion, // Index des Quellbereiches + USHORT nSourceIdx /* Index der zu kopierenden / zu verschiebenden + Dokumentvorlage */ +) + +/* [Beschreibung] + + Verschieben einer Dokumentvorlage + + + [R"uckgabewert] + + sal_Bool sal_True + Aktion konnte ausgef"uhrt werden + + sal_False + Aktion konnte nicht ausgef2uhrt werden + + [Querverweise] + + <SfxDocumentTemplates::CopyOrMove(USHORT,USHORT,USHORT,USHORT,sal_Bool)> +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + return CopyOrMove( nTargetRegion, nTargetIdx, + nSourceRegion, nSourceIdx, sal_True ); +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::Copy +( + USHORT nTargetRegion, // Index des Zielbereiches + USHORT nTargetIdx, // Index Zielposition + USHORT nSourceRegion, // Index des Quellbereiches + USHORT nSourceIdx /* Index der zu kopierenden / zu verschiebenden + Dokumentvorlage */ +) + +/* [Beschreibung] + + Kopieren einer Dokumentvorlage + + + [R"uckgabewert] + + sal_Bool sal_True + Aktion konnte ausgef"uhrt werden + + sal_False + Aktion konnte nicht ausgef"uhrt werden + + [Querverweise] + + <SfxDocumentTemplates::CopyOrMove(USHORT,USHORT,USHORT,USHORT,sal_Bool)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + return CopyOrMove( nTargetRegion, nTargetIdx, + nSourceRegion, nSourceIdx, sal_False ); +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::CopyTo +( + USHORT nRegion, /* Bereich der Vorlage, die exportiert werden + soll */ + USHORT nIdx, /* Index der Vorlage, die exportiert werden + soll */ + const String& rName /* Dateiname, unter dem die Vorlage angelegt + werden soll */ +) const + +/* [Beschreibung] + + Exportieren einer Dokumentvorlage in das Dateisystem + + + [R"uckgabewert] + + sal_Bool sal_True + Aktion konnte ausgef"uhrt werden + + sal_False + Aktion konnte nicht ausgef"uhrt werden + + + [Querverweise] + + <SfxDocumentTemplates::CopyFrom(USHORT,USHORT,String&)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return sal_False; + + RegionData_Impl *pSourceRgn = pImp->GetRegion( nRegion ); + if ( !pSourceRgn ) + return sal_False; + + DocTempl_EntryData_Impl *pSource = pSourceRgn->GetEntry( nIdx ); + if ( !pSource ) + return sal_False; + + INetURLObject aTargetURL( rName ); + + OUString aTitle( aTargetURL.getName( INetURLObject::LAST_SEGMENT, true, + INetURLObject::DECODE_WITH_CHARSET ) ); + aTargetURL.removeSegment(); + + OUString aParentURL = aTargetURL.GetMainURL( INetURLObject::NO_DECODE ); + + uno::Reference< XCommandEnvironment > aCmdEnv; + Content aTarget; + + try + { + aTarget = Content( aParentURL, aCmdEnv ); + + TransferInfo aTransferInfo; + aTransferInfo.MoveData = sal_False; + aTransferInfo.SourceURL = pSource->GetTargetURL(); + aTransferInfo.NewTitle = aTitle; + aTransferInfo.NameClash = NameClash::OVERWRITE; + + Any aArg = makeAny( aTransferInfo ); + OUString aCmd( RTL_CONSTASCII_USTRINGPARAM( COMMAND_TRANSFER ) ); + + aTarget.executeCommand( aCmd, aArg ); + } + catch ( ContentCreationException& ) + { return sal_False; } + catch ( Exception& ) + { return sal_False; } + + return sal_True; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::CopyFrom +( + USHORT nRegion, /* Bereich, in den die Vorlage importiert + werden soll */ + USHORT nIdx, // Index der neuen Vorlage in diesem Bereich + String& rName /* Dateiname der Vorlage, die importiert + werden soll, als out-Parameter der (auto- + matisch aus dem Dateinamen generierte) + logische Name der Vorlage */ +) + +/* [Beschreibung] + + Importieren einer Dokumentvorlage aus dem Dateisystem + + + [R"uckgabewert] Erfolg (sal_True) oder Mi"serfpTargetDirectory->GetContent()); + + sal_Bool sal_True + Aktion konnte ausgef"uhrt werden + + sal_False + Aktion konnte nicht ausgef"uhrt werden + + [Querverweise] + + <SfxDocumentTemplates::CopyTo(USHORT,USHORT,const String&)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return sal_False; + + RegionData_Impl *pTargetRgn = pImp->GetRegion( nRegion ); + + if ( !pTargetRgn ) + return sal_False; + + uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates(); + if ( !xTemplates.is() ) + return sal_False; + + OUString aTitle; + sal_Bool bTemplateAdded = sal_False; + + if( pImp->GetTitleFromURL( rName, aTitle ) ) + { + bTemplateAdded = xTemplates->addTemplate( pTargetRgn->GetTitle(), aTitle, rName ); + } + else + { + OUString aService( RTL_CONSTASCII_USTRINGPARAM( SERVICENAME_DESKTOP ) ); + uno::Reference< XComponentLoader > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance( aService ), + UNO_QUERY ); + + Sequence< PropertyValue > aArgs( 1 ); + aArgs[0].Name = ::rtl::OUString::createFromAscii("Hidden"); + aArgs[0].Value <<= sal_True; + + INetURLObject aTemplURL( rName ); + uno::Reference< XDocumentPropertiesSupplier > xDocPropsSupplier; + uno::Reference< XStorable > xStorable; + try + { + xStorable = uno::Reference< XStorable >( + xDesktop->loadComponentFromURL( aTemplURL.GetMainURL(INetURLObject::NO_DECODE), + OUString::createFromAscii( "_blank" ), + 0, + aArgs ), + UNO_QUERY ); + + xDocPropsSupplier = uno::Reference< XDocumentPropertiesSupplier >( + xStorable, UNO_QUERY ); + } + catch( Exception& ) + { + } + + if( xStorable.is() ) + { + // get Title from XDocumentPropertiesSupplier + if( xDocPropsSupplier.is() ) + { + uno::Reference< XDocumentProperties > xDocProps + = xDocPropsSupplier->getDocumentProperties(); + if (xDocProps.is() ) { + aTitle = xDocProps->getTitle(); + } + } + + if( ! aTitle.getLength() ) + { + INetURLObject aURL( aTemplURL ); + aURL.CutExtension(); + aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true, + INetURLObject::DECODE_WITH_CHARSET ); + } + + // write a template using XStorable interface + bTemplateAdded = xTemplates->storeTemplate( pTargetRgn->GetTitle(), aTitle, xStorable ); + } + } + + + if( bTemplateAdded ) + { + INetURLObject aTemplObj( pTargetRgn->GetHierarchyURL() ); + aTemplObj.insertName( aTitle, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + OUString aTemplURL = aTemplObj.GetMainURL( INetURLObject::NO_DECODE ); + + uno::Reference< XCommandEnvironment > aCmdEnv; + Content aTemplCont; + + if( Content::create( aTemplURL, aCmdEnv, aTemplCont ) ) + { + OUString aTemplName; + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + + if( getTextProperty_Impl( aTemplCont, aPropName, aTemplName ) ) + { + if ( nIdx == USHRT_MAX ) + nIdx = 0; + else + nIdx += 1; + + pTargetRgn->AddEntry( aTitle, aTemplName, &nIdx ); + rName = aTitle; + return sal_True; + } + else + { + DBG_ASSERT( sal_False, "CopyFrom(): The content should contain target URL!" ); + } + } + else + { + DBG_ASSERT( sal_False, "CopyFrom(): The content just was created!" ); + } + } + + return sal_False; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::Delete +( + USHORT nRegion, // Index des Bereiches + USHORT nIdx /* Index des Eintrags oder USHRT_MAX, + wenn ein Verzeichnis gemeint ist. */ +) + +/* [Beschreibung] + + "oschen eines Eintrags oder eines Verzeichnisses + + + [R"uckgabewert] + + sal_Bool sal_True + Aktion konnte ausgef"uhrt werden + + sal_False + Aktion konnte nicht ausgef"uhrt werden + + + [Querverweise] + + <SfxDocumentTemplates::InsertDir(const String&,USHORT)> + <SfxDocumentTemplates::KillDir(SfxTemplateDir&)> + <SfxDocumentTemplates::SaveDir(SfxTemplateDir&)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + /* delete the template or folder in the hierarchy and in the + template folder by sending a delete command to the content. + Then remove the data from the lists + */ + if ( ! pImp->Construct() ) + return sal_False; + + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + + if ( !pRegion ) + return sal_False; + + sal_Bool bRet; + uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates(); + + if ( nIdx == USHRT_MAX ) + { + bRet = xTemplates->removeGroup( pRegion->GetTitle() ); + if ( bRet ) + pImp->DeleteRegion( nRegion ); + } + else + { + DocTempl_EntryData_Impl *pEntry = pRegion->GetEntry( nIdx ); + + if ( !pEntry ) + return sal_False; + + bRet = xTemplates->removeTemplate( pRegion->GetTitle(), + pEntry->GetTitle() ); + if( bRet ) + pRegion->DeleteEntry( nIdx ); + } + + return bRet; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::InsertDir +( + const String& rText, // der logische Name des neuen Bereiches + USHORT nRegion // Index des Bereiches +) + +/* [Beschreibung] + + Einf"ugen eines Verzeichnisses + + + [R"uckgabewert] + + sal_Bool sal_True + Aktion konnte ausgef"uhrt werden + + sal_False + Aktion konnte nicht ausgef"uhrt werden + + [Querverweise] + + <SfxDocumentTemplates::KillDir(SfxTemplateDir&)> + <SfxDocumentTemplates::SaveDir(SfxTemplateDir&)> +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return sal_False; + + RegionData_Impl *pRegion = pImp->GetRegion( rText ); + + if ( pRegion ) + return sal_False; + + uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates(); + + if ( xTemplates->addGroup( rText ) ) + { + RegionData_Impl* pNewRegion = new RegionData_Impl( pImp, rText ); + + if ( ! pImp->InsertRegion( pNewRegion, nRegion ) ) + { + delete pNewRegion; + return sal_False; + } + return sal_True; + } + + return sal_False; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::SetName +( + const String& rName, // Der zu setzende Name + USHORT nRegion, // Index des Bereiches + USHORT nIdx /* Index des Eintrags oder USHRT_MAX, + wenn ein Verzeichnis gemeint ist. */ +) + +/* [Beschreibung] + + "Andern des Namens eines Eintrags oder eines Verzeichnisses + + + [R"uckgabewert] + + sal_Bool sal_True + Aktion konnte ausgef"uhrt werden + + sal_False + Aktion konnte nicht ausgef"uhrt werden + +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return sal_False; + + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + DocTempl_EntryData_Impl *pEntry = NULL; + + if ( !pRegion ) + return sal_False; + + uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates(); + OUString aEmpty; + + if ( nIdx == USHRT_MAX ) + { + if ( pRegion->GetTitle() == OUString( rName ) ) + return sal_True; + + // we have to rename a region + if ( xTemplates->renameGroup( pRegion->GetTitle(), rName ) ) + { + pRegion->SetTitle( rName ); + pRegion->SetTargetURL( aEmpty ); + pRegion->SetHierarchyURL( aEmpty ); + return sal_True; + } + } + else + { + pEntry = pRegion->GetEntry( nIdx ); + + if ( !pEntry ) + return sal_False; + + if ( pEntry->GetTitle() == OUString( rName ) ) + return sal_True; + + if ( xTemplates->renameTemplate( pRegion->GetTitle(), + pEntry->GetTitle(), + rName ) ) + { + pEntry->SetTitle( rName ); + pEntry->SetTargetURL( aEmpty ); + pEntry->SetHierarchyURL( aEmpty ); + return sal_True; + } + } + + return sal_False; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::Rescan() + +/* [Beschreibung] + + Abgleich des Verwaltungsdaten mit dem aktuellen Zustand auf der Platte. + Die logischen Namen, zu denen keine Datei mit existiert, werden aus + der Verwaltungsstruktur entfernt; Dateien, zu denen kein Eintrag + existiert, werden aufgenommen. + + + [R"uckgabewert] + + sal_Bool sal_True + Aktion konnte ausgef"uhrt werden + + sal_False + Aktion konnte nicht ausgef"uhrt werden + + + [Querverweise] + + <SfxTemplateDir::Scan(sal_Bool bDirectory, sal_Bool bSave)> + <SfxTemplateDir::Freshen(const SfxTemplateDir &rNew)> +*/ +{ + if ( !pImp->Construct() ) + return sal_False; + + pImp->Rescan(); + + return sal_True; +} + +//------------------------------------------------------------------------ + +SfxObjectShellRef SfxDocumentTemplates::CreateObjectShell +( + USHORT nRegion, // Index des Bereiches + USHORT nIdx // Index des Eintrags +) + +/* [Beschreibung] + + Zugriff auf die DokumentShell eines Eintrags + + + [R"uckgabewert] + + SfxObjectShellRef Referenz auf die ObjectShell + + + [Querverweise] + + <SfxTemplateDirEntry::CreateObjectShell()> + <SfxDocumentTemplates::DeleteObjectShell(USHORT, USHORT)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return NULL; + + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + DocTempl_EntryData_Impl *pEntry = NULL; + + if ( pRegion ) + pEntry = pRegion->GetEntry( nIdx ); + + if ( pEntry ) + return pEntry->CreateObjectShell(); + else + return NULL; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::DeleteObjectShell +( + USHORT nRegion, // Index des Bereiches + USHORT nIdx // Index des Eintrags +) + +/* [Beschreibung] + + Freigeben der ObjectShell eines Eintrags + + + [R"uckgabewert] + + sal_Bool sal_True + Aktion konnte ausgef"uhrt werden + + sal_False + Aktion konnte nicht ausgef"uhrt werden + + [Querverweise] + + <SfxTemplateDirEntry::DeleteObjectShell()> + <SfxDocumentTemplates::CreateObjectShell(USHORT, USHORT)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return sal_True; + + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + DocTempl_EntryData_Impl *pEntry = NULL; + + if ( pRegion ) + pEntry = pRegion->GetEntry( nIdx ); + + if ( pEntry ) + return pEntry->DeleteObjectShell(); + else + return sal_True; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::GetFull +( + const String &rRegion, // Der Name des Bereiches + const String &rName, // Der Name der Vorlage + String &rPath // Out: Pfad + Dateiname +) + +/* [Beschreibung] + + Liefert Pfad + Dateiname zu der durch rRegion und rName bezeichneten + Vorlage + + + [R"uckgabewert] + + sal_Bool sal_True + Aktion konnte ausgef"uhrt werden + + sal_False + Aktion konnte nicht ausgef"uhrt werden + + + [Querverweise] + + <SfxDocumentTemplates::GetLogicNames(const String&,String&,String&)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + // We don't search for empty names! + if ( ! rName.Len() ) + return sal_False; + + if ( ! pImp->Construct() ) + return sal_False; + + DocTempl_EntryData_Impl* pEntry = NULL; + const USHORT nCount = GetRegionCount(); + + for ( USHORT i = 0; i < nCount; ++i ) + { + RegionData_Impl *pRegion = pImp->GetRegion( i ); + + if( pRegion && + ( !rRegion.Len() || ( rRegion == String( pRegion->GetTitle() ) ) ) ) + { + pEntry = pRegion->GetEntry( rName ); + + if ( pEntry ) + { + rPath = pEntry->GetTargetURL(); + break; + } + } + } + + return ( pEntry != NULL ); +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::GetLogicNames +( + const String &rPath, // vollst"andiger Pfad zu der Vorlage + String &rRegion, // Out: der Bereichsname + String &rName // Out: der Vorlagenname +) const + +/* [Beschreibung] + + Liefert Pfad und logischen Namen zu der durch rPath bezeichneten + Vorlage + + [R"uckgabewert] + + sal_Bool sal_True + Aktion konnte ausgef"uhrt werden + + sal_False + Aktion konnte nicht ausgef"uhrt werden + + + [Querverweise] + + <SfxDocumentTemplates::GetFull(const String&,const String&,DirEntry&)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return sal_False; + + INetURLObject aFullPath; + + aFullPath.SetSmartProtocol( INET_PROT_FILE ); + aFullPath.SetURL( rPath ); + OUString aPath( aFullPath.GetMainURL( INetURLObject::NO_DECODE ) ); + + RegionData_Impl *pData = NULL; + DocTempl_EntryData_Impl *pEntry = NULL; + sal_Bool bFound = sal_False; + + ULONG nCount = GetRegionCount(); + + for ( ULONG i=0; !bFound && (i<nCount); i++ ) + { + pData = pImp->GetRegion( i ); + if ( pData ) + { + ULONG nChildCount = pData->GetCount(); + + for ( ULONG j=0; !bFound && (j<nChildCount); j++ ) + { + pEntry = pData->GetEntry( j ); + if ( pEntry->GetTargetURL() == aPath ) + { + bFound = sal_True; + } + } + } + } + + if ( bFound ) + { + rRegion = pData->GetTitle(); + rName = pEntry->GetTitle(); + } + + return bFound; +} + +//------------------------------------------------------------------------ + +SfxDocumentTemplates::SfxDocumentTemplates() + +/* [Beschreibung] + + Konstruktor +*/ +{ + if ( !gpTemplateData ) + gpTemplateData = new SfxDocTemplate_Impl; + + pImp = gpTemplateData; +} + +//------------------------------------------------------------------------- + +void SfxDocumentTemplates::Construct() + +// verz"ogerter Aufbau der Verwaltungsdaten + +{ +// pImp->Construct(); +} + +//------------------------------------------------------------------------ + +SfxDocumentTemplates::~SfxDocumentTemplates() + +/* [Beschreibung] + + Destruktor + Freigeben der Verwaltungsdaten +*/ + +{ + pImp = NULL; +} + +void SfxDocumentTemplates::Update( sal_Bool _bSmart ) +{ + if ( !_bSmart // don't be smart + || ::svt::TemplateFolderCache( sal_True ).needsUpdate() // update is really necessary + ) + { + if ( pImp->Construct() ) + pImp->Rescan(); + } +} + +void SfxDocumentTemplates::ReInitFromComponent() +{ + pImp->ReInitFromComponent(); +} + + +sal_Bool SfxDocumentTemplates::HasUserContents( sal_uInt16 nRegion, sal_uInt16 nIdx ) const +{ + DocTemplLocker_Impl aLocker( *pImp ); + + sal_Bool bResult = sal_False; + + RegionData_Impl* pRegion = pImp->GetRegion( nRegion ); + + if ( pRegion ) + { + ::rtl::OUString aRegionTargetURL = pRegion->GetTargetURL(); + if ( aRegionTargetURL.getLength() ) + { + sal_uInt16 nLen = 0; + sal_uInt16 nStartInd = 0; + + if( nIdx == USHRT_MAX ) + { + // this is a folder + // check whether there is at least one editable template + nLen = ( sal_uInt16 )pRegion->GetCount(); + nStartInd = 0; + if ( nLen == 0 ) + bResult = sal_True; // the writing part of empty folder with writing URL can be removed + } + else + { + // this is a template + // check whether the template is inserted by user + nLen = 1; + nStartInd = nIdx; + } + + for ( sal_uInt16 nInd = nStartInd; nInd < nStartInd + nLen; nInd++ ) + { + DocTempl_EntryData_Impl* pEntryData = pRegion->GetEntry( nInd ); + if ( pEntryData ) + { + ::rtl::OUString aEntryTargetURL = pEntryData->GetTargetURL(); + if ( aEntryTargetURL.getLength() + && ::utl::UCBContentHelper::IsSubPath( aRegionTargetURL, aEntryTargetURL ) ) + { + bResult = sal_True; + break; + } + } + } + } + } + + return bResult; +} + +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +DocTempl_EntryData_Impl::DocTempl_EntryData_Impl( RegionData_Impl* pParent, + const OUString& rTitle ) +{ + mpParent = pParent; + maTitle = rTitle; + mbIsOwner = sal_False; + mbDidConvert= sal_False; +} + +// ----------------------------------------------------------------------- +int DocTempl_EntryData_Impl::Compare( const OUString& rTitle ) const +{ + return maTitle.compareTo( rTitle ); +} + +//------------------------------------------------------------------------ +SfxObjectShellRef DocTempl_EntryData_Impl::CreateObjectShell() +{ + if( ! mxObjShell.Is() ) + { + mbIsOwner = sal_False; + sal_Bool bDum = sal_False; + SfxApplication *pSfxApp = SFX_APP(); + String aTargetURL = GetTargetURL(); + + mxObjShell = pSfxApp->DocAlreadyLoaded( aTargetURL, sal_True, bDum ); + + if( ! mxObjShell.Is() ) + { + mbIsOwner = sal_True; + SfxMedium *pMed=new SfxMedium( + aTargetURL,(STREAM_STD_READWRITE | STREAM_SHARE_DENYALL), sal_False, 0 ); + const SfxFilter* pFilter = NULL; + pMed->UseInteractionHandler(TRUE); + if( pSfxApp->GetFilterMatcher().GuessFilter( + *pMed, &pFilter, SFX_FILTER_TEMPLATE, 0 ) || + (pFilter && !pFilter->IsOwnFormat()) || + (pFilter && !pFilter->UsesStorage()) ) + { + SfxErrorContext aEc( ERRCTX_SFX_LOADTEMPLATE, + aTargetURL ); + delete pMed; + mbDidConvert=sal_True; + ULONG lErr; + if ( mxObjShell.Is() ) { + lErr = pSfxApp->LoadTemplate( mxObjShell,aTargetURL); + if( lErr != ERRCODE_NONE ) + ErrorHandler::HandleError(lErr); + } + + } + else if (pFilter) + { + mbDidConvert=sal_False; + mxObjShell = SfxObjectShell::CreateObject( pFilter->GetServiceName(), SFX_CREATE_MODE_ORGANIZER ); + if ( mxObjShell.Is() ) + { + mxObjShell->DoInitNew(0); + // TODO/LATER: make sure that we don't use binary templates! + if( mxObjShell->LoadFrom( *pMed ) ) + { + mxObjShell->DoSaveCompleted( pMed ); + } + else + mxObjShell.Clear(); + } + } + } + } + + return (SfxObjectShellRef)(SfxObjectShell*) mxObjShell; +} + +//------------------------------------------------------------------------ +BOOL DocTempl_EntryData_Impl::DeleteObjectShell() +{ + sal_Bool bRet = sal_True; + + if ( mxObjShell.Is() ) + { + if( mxObjShell->IsModified() ) + { + //Hier speichern wir auch, falls die Vorlage in Bearbeitung ist... + bRet = sal_False; + + if ( mbIsOwner ) + { + if( mbDidConvert ) + { + bRet=mxObjShell->PreDoSaveAs_Impl( + GetTargetURL(), + mxObjShell->GetFactory().GetFilterContainer()->GetAnyFilter( SFX_FILTER_EXPORT | SFX_FILTER_IMPORT, SFX_FILTER_INTERNAL )->GetFilterName(), 0 ); + } + else + { + if( mxObjShell->Save() ) + { + uno::Reference< embed::XTransactedObject > xTransacted( mxObjShell->GetStorage(), uno::UNO_QUERY ); + DBG_ASSERT( xTransacted.is(), "Storage must implement XTransactedObject!\n" ); + if ( xTransacted.is() ) + { + try + { + xTransacted->commit(); + bRet = sal_True; + } + catch( uno::Exception& ) + { + } + } + } + } + } + } + + if( bRet ) + { + mxObjShell.Clear(); + } + } + return bRet; +} + +// ----------------------------------------------------------------------- +const OUString& DocTempl_EntryData_Impl::GetHierarchyURL() +{ + if ( !maOwnURL.getLength() ) + { + INetURLObject aTemplateObj( GetParent()->GetHierarchyURL() ); + + aTemplateObj.insertName( GetTitle(), false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + maOwnURL = aTemplateObj.GetMainURL( INetURLObject::NO_DECODE ); + DBG_ASSERT( maOwnURL.getLength(), "GetHierarchyURL(): Could not create URL!" ); + } + + return maOwnURL; +} + +// ----------------------------------------------------------------------- +const OUString& DocTempl_EntryData_Impl::GetTargetURL() +{ + if ( !maTargetURL.getLength() ) + { + uno::Reference< XCommandEnvironment > aCmdEnv; + Content aRegion; + + if ( Content::create( GetHierarchyURL(), aCmdEnv, aRegion ) ) + { + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + + getTextProperty_Impl( aRegion, aPropName, maTargetURL ); + } + else + { + DBG_ERRORFILE( "GetTargetURL(): Could not create hierarchy content!" ); + } + } + + return maTargetURL; +} + +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +RegionData_Impl::RegionData_Impl( const SfxDocTemplate_Impl* pParent, + const OUString& rTitle ) +{ + maTitle = rTitle; + mpParent = pParent; +} + +// ----------------------------------------------------------------------- +RegionData_Impl::~RegionData_Impl() +{ + DocTempl_EntryData_Impl *pData = maEntries.First(); + + while ( pData ) + { + delete pData; + pData = maEntries.Next(); + } +} + +// ----------------------------------------------------------------------- +long RegionData_Impl::GetEntryPos( const OUString& rTitle, + sal_Bool& rFound ) const +{ +#if 1 // Don't use binary search today + ULONG i; + ULONG nCount = maEntries.Count(); + + for ( i=0; i<nCount; i++ ) + { + DocTempl_EntryData_Impl *pData = maEntries.GetObject( i ); + + if ( pData->Compare( rTitle ) == 0 ) + { + rFound = sal_True; + return i; + } + } + + rFound = sal_False; + return i; + +#else + // use binary search to find the correct position + // in the maEntries list + + int nCompVal = 1; + long nStart = 0; + long nEnd = maEntries.Count() - 1; + long nMid; + + DocTempl_EntryData_Impl* pMid; + + rFound = sal_False; + + while ( nCompVal && ( nStart <= nEnd ) ) + { + nMid = ( nEnd - nStart ) / 2 + nStart; + pMid = maEntries.GetObject( nMid ); + + nCompVal = pMid->Compare( rTitle ); + + if ( nCompVal < 0 ) // pMid < pData + nStart = nMid + 1; + else + nEnd = nMid - 1; + } + + if ( nCompVal == 0 ) + { + rFound = sal_True; + } + else + { + if ( nCompVal < 0 ) // pMid < pData + nMid++; + } + + return nMid; +#endif +} + +// ----------------------------------------------------------------------- +void RegionData_Impl::AddEntry( const OUString& rTitle, + const OUString& rTargetURL, + USHORT *pPos ) +{ + INetURLObject aLinkObj( GetHierarchyURL() ); + aLinkObj.insertName( rTitle, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + OUString aLinkURL = aLinkObj.GetMainURL( INetURLObject::NO_DECODE ); + + DocTempl_EntryData_Impl *pEntry; + sal_Bool bFound = sal_False; + long nPos = GetEntryPos( rTitle, bFound ); + + if ( bFound ) + { + pEntry = maEntries.GetObject( nPos ); + } + else + { + if ( pPos ) + nPos = *pPos; + + pEntry = new DocTempl_EntryData_Impl( this, rTitle ); + pEntry->SetTargetURL( rTargetURL ); + pEntry->SetHierarchyURL( aLinkURL ); + maEntries.Insert( pEntry, nPos ); + } +} + +// ----------------------------------------------------------------------- +ULONG RegionData_Impl::GetCount() const +{ + return maEntries.Count(); +} + +// ----------------------------------------------------------------------- +const OUString& RegionData_Impl::GetHierarchyURL() +{ + if ( !maOwnURL.getLength() ) + { + INetURLObject aRegionObj( GetParent()->GetRootURL() ); + + aRegionObj.insertName( GetTitle(), false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + maOwnURL = aRegionObj.GetMainURL( INetURLObject::NO_DECODE ); + DBG_ASSERT( maOwnURL.getLength(), "GetHierarchyURL(): Could not create URL!" ); + } + + return maOwnURL; +} + +// ----------------------------------------------------------------------- +const OUString& RegionData_Impl::GetTargetURL() +{ + if ( !maTargetURL.getLength() ) + { + uno::Reference< XCommandEnvironment > aCmdEnv; + Content aRegion; + + if ( Content::create( GetHierarchyURL(), aCmdEnv, aRegion ) ) + { + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + + getTextProperty_Impl( aRegion, aPropName, maTargetURL ); + // --> PB 2004-10-27 #i32656# - the targeturl must be substituted: $(baseinsturl) + maTargetURL = SvtPathOptions().SubstituteVariable( maTargetURL ); + // <-- + } + else + { + DBG_ERRORFILE( "GetTargetURL(): Could not create hierarchy content!" ); + } + } + + return maTargetURL; +} + +// ----------------------------------------------------------------------- +DocTempl_EntryData_Impl* RegionData_Impl::GetEntry( const OUString& rName ) const +{ + sal_Bool bFound = sal_False; + long nPos = GetEntryPos( rName, bFound ); + + if ( bFound ) + return maEntries.GetObject( nPos ); + else + return NULL; +} + +// ----------------------------------------------------------------------- +DocTempl_EntryData_Impl* RegionData_Impl::GetByTargetURL( const OUString& rName ) const +{ + DocTempl_EntryData_Impl *pEntry; + + ULONG nCount = maEntries.Count(); + + for ( ULONG i=0; i<nCount; i++ ) + { + pEntry = maEntries.GetObject( i ); + if ( pEntry && ( pEntry->GetTargetURL() == rName ) ) + return pEntry; + } + + return NULL; +} + +// ----------------------------------------------------------------------- +DocTempl_EntryData_Impl* RegionData_Impl::GetEntry( ULONG nIndex ) const +{ + return maEntries.GetObject( nIndex ); +} + +// ----------------------------------------------------------------------- +void RegionData_Impl::DeleteEntry( ULONG nIndex ) +{ + DocTempl_EntryData_Impl *pEntry = maEntries.GetObject( nIndex ); + + if ( pEntry ) + { + delete pEntry; + maEntries.Remove( (ULONG) nIndex ); + } +} + +// ----------------------------------------------------------------------- +int RegionData_Impl::Compare( RegionData_Impl* pCompare ) const +{ + int nCompare = maTitle.compareTo( pCompare->maTitle ); + + return nCompare; +} + +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- + +SfxDocTemplate_Impl::SfxDocTemplate_Impl() +: mbConstructed( sal_False ) +, mnLockCounter( 0 ) +{ +} + +// ----------------------------------------------------------------------- +SfxDocTemplate_Impl::~SfxDocTemplate_Impl() +{ + Clear(); + + gpTemplateData = NULL; +} + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::IncrementLock() +{ + ::osl::MutexGuard aGuard( maMutex ); + mnLockCounter++; +} + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::DecrementLock() +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mnLockCounter ) + mnLockCounter--; +} + +// ----------------------------------------------------------------------- +RegionData_Impl* SfxDocTemplate_Impl::GetRegion( ULONG nIndex ) const +{ + return maRegions.GetObject( nIndex ); +} + +// ----------------------------------------------------------------------- +RegionData_Impl* SfxDocTemplate_Impl::GetRegion( const OUString& rName ) + const +{ + ULONG nCount = maRegions.Count(); + RegionData_Impl *pData; + + for ( ULONG i=0; i<nCount; i++ ) + { + pData = maRegions.GetObject( i ); + + if ( pData->GetTitle() == rName ) + return pData; + } + + return NULL; +} + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::DeleteRegion( ULONG nIndex ) +{ + RegionData_Impl* pRegion = maRegions.GetObject( nIndex ); + + if ( pRegion ) + { + delete pRegion; + maRegions.Remove( (ULONG) nIndex ); + } +} + +// ----------------------------------------------------------------------- +/* AddRegion adds a Region to the RegionList +*/ +void SfxDocTemplate_Impl::AddRegion( const OUString& rTitle, + Content& rContent ) +{ + RegionData_Impl* pRegion; + pRegion = new RegionData_Impl( this, rTitle ); + + if ( ! InsertRegion( pRegion ) ) + { + delete pRegion; + return; + } + + // now get the content of the region + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps(2); + aProps[0] = OUString::createFromAscii( TITLE ); + aProps[1] = OUString::createFromAscii( TARGET_URL ); + + try + { + ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY; + Sequence< NumberedSortingInfo > aSortingInfo(1); + aSortingInfo.getArray()->ColumnIndex = 1; + aSortingInfo.getArray()->Ascending = sal_True; + xResultSet = rContent.createSortedCursor( aProps, aSortingInfo, m_rCompareFactory, eInclude ); + } + catch ( Exception& ) {} + + if ( xResultSet.is() ) + { + uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + uno::Reference< XRow > xRow( xResultSet, UNO_QUERY ); + + try + { + while ( xResultSet->next() ) + { + OUString aTitle( xRow->getString( 1 ) ); + OUString aTargetDir( xRow->getString( 2 ) ); + + pRegion->AddEntry( aTitle, aTargetDir ); + } + } + catch ( Exception& ) {} + } +} + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::CreateFromHierarchy( Content &rTemplRoot ) +{ + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps(1); + aProps[0] = OUString::createFromAscii( TITLE ); + + try + { + ResultSetInclude eInclude = INCLUDE_FOLDERS_ONLY; + Sequence< NumberedSortingInfo > aSortingInfo(1); + aSortingInfo.getArray()->ColumnIndex = 1; + aSortingInfo.getArray()->Ascending = sal_True; + xResultSet = rTemplRoot.createSortedCursor( aProps, aSortingInfo, m_rCompareFactory, eInclude ); + } + catch ( Exception& ) {} + + if ( xResultSet.is() ) + { + uno::Reference< XCommandEnvironment > aCmdEnv; + uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + uno::Reference< XRow > xRow( xResultSet, UNO_QUERY ); + + try + { + while ( xResultSet->next() ) + { + OUString aTitle( xRow->getString( 1 ) ); + + OUString aId = xContentAccess->queryContentIdentifierString(); + Content aContent = Content( aId, aCmdEnv ); + + AddRegion( aTitle, aContent ); + } + } + catch ( Exception& ) {} + } +} + +// ------------------------------------------------------------------------ +sal_Bool SfxDocTemplate_Impl::Construct( ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( mbConstructed ) + return sal_True; + + uno::Reference< XMultiServiceFactory > xFactory; + xFactory = ::comphelper::getProcessServiceFactory(); + + OUString aService( RTL_CONSTASCII_USTRINGPARAM( SERVICENAME_DOCINFO ) ); + uno::Reference< XPersist > xInfo( xFactory->createInstance( aService ), UNO_QUERY ); + mxInfo = xInfo; + + aService = OUString( RTL_CONSTASCII_USTRINGPARAM( SERVICENAME_DOCTEMPLATES ) ); + uno::Reference< XDocumentTemplates > xTemplates( xFactory->createInstance( aService ), UNO_QUERY ); + + if ( xTemplates.is() ) + mxTemplates = xTemplates; + else + return sal_False; + + uno::Reference< XLocalizable > xLocalizable( xTemplates, UNO_QUERY ); + + Sequence< Any > aCompareArg(1); + *(aCompareArg.getArray()) <<= xLocalizable->getLocale();; + m_rCompareFactory = uno::Reference< XAnyCompareFactory >( + xFactory->createInstanceWithArguments( OUString::createFromAscii( "com.sun.star.ucb.AnyCompareFactory" ), + aCompareArg ), + UNO_QUERY ); + + uno::Reference < XContent > aRootContent = xTemplates->getContent(); + uno::Reference < XCommandEnvironment > aCmdEnv; + + if ( ! aRootContent.is() ) + return sal_False; + + mbConstructed = sal_True; + maRootURL = aRootContent->getIdentifier()->getContentIdentifier(); + + ResStringArray aLongNames( SfxResId( TEMPLATE_LONG_NAMES_ARY ) ); + + if ( aLongNames.Count() ) + maStandardGroup = aLongNames.GetString( 0 ); + + Content aTemplRoot( aRootContent, aCmdEnv ); + CreateFromHierarchy( aTemplRoot ); + + return sal_True; +} + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::ReInitFromComponent() +{ + uno::Reference< XDocumentTemplates > xTemplates = getDocTemplates(); + if ( xTemplates.is() ) + { + uno::Reference < XContent > aRootContent = xTemplates->getContent(); + uno::Reference < XCommandEnvironment > aCmdEnv; + Content aTemplRoot( aRootContent, aCmdEnv ); + Clear(); + CreateFromHierarchy( aTemplRoot ); + } +} + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::GetTemplates( Content& rTargetFolder, + Content& /*rParentFolder*/, + RegionData_Impl* pRegion ) +{ + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps(1); + + aProps[0] = OUString::createFromAscii( TITLE ); + + try + { + ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY; + Sequence< NumberedSortingInfo > aSortingInfo(1); + aSortingInfo.getArray()->ColumnIndex = 1; + aSortingInfo.getArray()->Ascending = sal_True; + xResultSet = rTargetFolder.createSortedCursor( aProps, aSortingInfo, m_rCompareFactory, eInclude ); + } + catch ( Exception& ) {} + + if ( xResultSet.is() ) + { + uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + uno::Reference< XRow > xRow( xResultSet, UNO_QUERY ); + + try + { + while ( xResultSet->next() ) + { + OUString aTitle( xRow->getString(1) ); + + if ( aTitle.compareToAscii( "sfx.tlx" ) == 0 ) + continue; + + OUString aId = xContentAccess->queryContentIdentifierString(); + + DocTempl_EntryData_Impl* pEntry = pRegion->GetByTargetURL( aId ); + + if ( ! pEntry ) + { + OUString aFullTitle; + if( !GetTitleFromURL( aId, aFullTitle ) ) + { + DBG_ERRORFILE( "GetTemplates(): template of alien format" ); + continue; + } + + if ( aFullTitle.getLength() ) + aTitle = aFullTitle; + + pRegion->AddEntry( aTitle, aId ); + } + } + } + catch ( Exception& ) {} + } +} + + +// ----------------------------------------------------------------------- +long SfxDocTemplate_Impl::GetRegionPos( const OUString& rTitle, + sal_Bool& rFound ) const +{ + int nCompVal = 1; + long nStart = 0; + long nEnd = maRegions.Count() - 1; + long nMid = 0; + + RegionData_Impl* pMid; + + while ( nCompVal && ( nStart <= nEnd ) ) + { + nMid = ( nEnd - nStart ) / 2 + nStart; + pMid = maRegions.GetObject( nMid ); + + nCompVal = pMid->Compare( rTitle ); + + if ( nCompVal < 0 ) // pMid < pData + nStart = nMid + 1; + else + nEnd = nMid - 1; + } + + if ( nCompVal == 0 ) + rFound = sal_True; + else + { + if ( nCompVal < 0 ) // pMid < pData + nMid++; + + rFound = sal_False; + } + + return nMid; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTemplate_Impl::InsertRegion( RegionData_Impl *pNew, + ULONG nPos ) +{ + ::osl::MutexGuard aGuard( maMutex ); + RegionData_Impl *pData = maRegions.First(); + + while ( pData && ( pData->Compare( pNew ) != 0 ) ) + pData = maRegions.Next(); + + if ( ! pData ) + { + // compare with the name of the standard group here to insert it + // first + + if ( pNew->GetTitle() == maStandardGroup ) + maRegions.Insert( pNew, (ULONG) 0 ); + else + maRegions.Insert( pNew, nPos ); + } + + return ( pData == NULL ); +} + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::Rescan() +{ + Clear(); + + try + { + uno::Reference< XDocumentTemplates > xTemplates = getDocTemplates(); + DBG_ASSERT( xTemplates.is(), "SfxDocTemplate_Impl::Rescan:invalid template instance!" ); + if ( xTemplates.is() ) + { + xTemplates->update(); + + uno::Reference < XContent > aRootContent = xTemplates->getContent(); + uno::Reference < XCommandEnvironment > aCmdEnv; + + Content aTemplRoot( aRootContent, aCmdEnv ); + CreateFromHierarchy( aTemplRoot ); + } + } + catch( const Exception& ) + { + DBG_ERRORFILE( "SfxDocTemplate_Impl::Rescan: caught an exception while doing the update!" ); + } +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTemplate_Impl::GetTitleFromURL( const OUString& rURL, + OUString& aTitle ) +{ + if ( mxInfo.is() ) + { + try + { + mxInfo->read( rURL ); + } + catch ( Exception& ) + { + // the document is not a StarOffice document + return sal_False; + } + + + try + { + uno::Reference< XPropertySet > aPropSet( mxInfo, UNO_QUERY ); + if ( aPropSet.is() ) + { + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + Any aValue = aPropSet->getPropertyValue( aPropName ); + aValue >>= aTitle; + } + } + catch ( IOException& ) {} + catch ( UnknownPropertyException& ) {} + catch ( Exception& ) {} + } + + if ( ! aTitle.getLength() ) + { + INetURLObject aURL( rURL ); + aURL.CutExtension(); + aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true, + INetURLObject::DECODE_WITH_CHARSET ); + } + + return sal_True; +} + + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::Clear() +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mnLockCounter ) + return; + + RegionData_Impl *pRegData = maRegions.First(); + + while ( pRegData ) + { + delete pRegData; + pRegData = maRegions.Next(); + } + + maRegions.Clear(); +} + +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +sal_Bool getTextProperty_Impl( Content& rContent, + const OUString& rPropName, + OUString& rPropValue ) +{ + sal_Bool bGotProperty = sal_False; + + // Get the property + try + { + uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties(); + + // check, wether or not the property exists + if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) ) + { + return sal_False; + } + + // now get the property + Any aAnyValue; + + aAnyValue = rContent.getPropertyValue( rPropName ); + aAnyValue >>= rPropValue; + + if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) ) + { + SfxURLRelocator_Impl aRelocImpl( ::comphelper::getProcessServiceFactory() ); + aRelocImpl.makeAbsoluteURL( rPropValue ); + } + + bGotProperty = sal_True; + } + catch ( RuntimeException& ) {} + catch ( Exception& ) {} + + return bGotProperty; +} + diff --git a/sfx2/source/doc/doctempl.src b/sfx2/source/doc/doctempl.src new file mode 100644 index 000000000000..2c91358f845e --- /dev/null +++ b/sfx2/source/doc/doctempl.src @@ -0,0 +1,106 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <sfx2/sfx.hrc> + +#include "doc.hrc" + +StringArray TEMPLATE_SHORT_NAMES_ARY +{ + ItemList = + { + < "standard" ; > ; + < "officorr" ; > ; + < "offimisc" ; > ; + < "personal" ; > ; + < "forms" ; > ; + < "finance" ; > ; + < "educate" ; > ; + < "layout" ; > ; + < "presnt" ; > ; + < "misc" ; > ; + }; +}; + +StringArray TEMPLATE_LONG_NAMES_ARY +{ + ItemList [ en-US ] = + { + < "My Templates" ; > ; + < "Business Correspondence" ; > ; + < "Other Business Documents" ; > ; + < "Personal Correspondence and Documents" ; > ; + < "Forms and Contracts" ; > ; + < "Finances" ; > ; + < "Education" ; > ; + < "Presentation Backgrounds" ; > ; + < "Presentations" ; > ; + < "Miscellaneous" ; > ; + }; + + }; + +String RID_CNT_STR_WAITING +{ + Text [ en-US ] = "The templates are being initialized for first-time usage." ; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sfx2/source/doc/doctemplates.cxx b/sfx2/source/doc/doctemplates.cxx new file mode 100644 index 000000000000..71f3683c0006 --- /dev/null +++ b/sfx2/source/doc/doctemplates.cxx @@ -0,0 +1,2898 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include "doctemplates.hxx" +#include <vos/mutex.hxx> +#include <tools/debug.hxx> +#include <tools/urlobj.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#ifndef _SV_RESARY_HXX +#include <tools/resary.hxx> +#endif +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <unotools/pathoptions.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/XPropertyContainer.hpp> +#include <com/sun/star/beans/StringPair.hpp> +#include <com/sun/star/container/XContainerQuery.hpp> +#include <com/sun/star/document/XTypeDetection.hpp> +#include <com/sun/star/document/XStandaloneDocumentInfo.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <com/sun/star/ucb/NameClashException.hpp> +#include <com/sun/star/ucb/TransferInfo.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/frame/XModuleManager.hpp> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/util/XOfficeInstallationDirectories.hpp> + +#include <svtools/templatefoldercache.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/ucbhelper.hxx> + +#include "sfxresid.hxx" +#include "sfxurlrelocator.hxx" +#include "doctemplateslocal.hxx" +#include <sfx2/docfac.hxx> +#include <sfx2/docfile.hxx> +#include "doc.hrc" + +//----------------------------------------------------------------------------- + +//============================================================================= + +#define TEMPLATE_SERVICE_NAME "com.sun.star.frame.DocumentTemplates" +#define TEMPLATE_IMPLEMENTATION_NAME "com.sun.star.comp.sfx2.DocumentTemplates" + +#define SERVICENAME_TYPEDETECTION "com.sun.star.document.TypeDetection" +#define SERVICENAME_DOCINFO "com.sun.star.document.StandaloneDocumentInfo" + +#define TEMPLATE_ROOT_URL "vnd.sun.star.hier:/templates" +#define TITLE "Title" +#define IS_FOLDER "IsFolder" +#define IS_DOCUMENT "IsDocument" +#define TARGET_URL "TargetURL" +#define TEMPLATE_VERSION "TemplateComponentVersion" +#define TEMPLATE_VERSION_VALUE "2" +#define TYPE_FOLDER "application/vnd.sun.star.hier-folder" +#define TYPE_LINK "application/vnd.sun.star.hier-link" +#define TYPE_FSYS_FOLDER "application/vnd.sun.staroffice.fsys-folder" +#define TYPE_FSYS_FILE "application/vnd.sun.staroffice.fsys-file" + +#define PROPERTY_DIRLIST "DirectoryList" +#define PROPERTY_NEEDSUPDATE "NeedsUpdate" +#define PROPERTY_TYPE "TypeDescription" + +#define TARGET_DIR_URL "TargetDirURL" +#define COMMAND_DELETE "delete" +#define COMMAND_TRANSFER "transfer" + +#define STANDARD_FOLDER "standard" + +#define C_DELIM ';' + +//============================================================================= + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; + +using namespace ::rtl; +using namespace ::ucbhelper; +using namespace ::comphelper; + +//============================================================================= + +class WaitWindow_Impl : public WorkWindow +{ + Rectangle _aRect; + USHORT _nTextStyle; + String _aText; + + public: + WaitWindow_Impl(); + ~WaitWindow_Impl(); + virtual void Paint( const Rectangle& rRect ); +}; + +#define X_OFFSET 15 +#define Y_OFFSET 15 + +//============================================================================= + +struct NamePair_Impl +{ + OUString maShortName; + OUString maLongName; +}; + +DECLARE_LIST( NameList_Impl, NamePair_Impl* ) + +class Updater_Impl; +class GroupList_Impl; +class DocTemplates_EntryData_Impl; +class GroupData_Impl; + +//============================================================================= +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/ucb/XProgressHandler.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> + +class TplTaskEnvironment : public ::cppu::WeakImplHelper1< ucb::XCommandEnvironment > +{ + uno::Reference< task::XInteractionHandler > m_xInteractionHandler; + uno::Reference< ucb::XProgressHandler > m_xProgressHandler; + +public: + TplTaskEnvironment( const uno::Reference< task::XInteractionHandler>& rxInteractionHandler ) + : m_xInteractionHandler( rxInteractionHandler ) + {} + + virtual uno::Reference<task::XInteractionHandler> SAL_CALL getInteractionHandler() throw (uno::RuntimeException) + { return m_xInteractionHandler; } + + virtual uno::Reference<ucb::XProgressHandler> SAL_CALL getProgressHandler() throw (uno::RuntimeException) + { return m_xProgressHandler; } +}; + +class SfxDocTplService_Impl +{ + uno::Reference< XMultiServiceFactory > mxFactory; + uno::Reference< XCommandEnvironment > maCmdEnv; + uno::Reference< XStandaloneDocumentInfo > mxInfo; + uno::Reference< XTypeDetection > mxType; + + ::osl::Mutex maMutex; + Sequence< OUString > maTemplateDirs; + OUString maRootURL; + NameList_Impl maNames; + Locale maLocale; + Content maRootContent; + Updater_Impl* mpUpdater; + sal_Bool mbIsInitialized : 1; + sal_Bool mbLocaleSet : 1; + + SfxURLRelocator_Impl maRelocator; + + void init_Impl(); + void getDefaultLocale(); + void getDirList(); + void readFolderList(); + sal_Bool needsUpdate(); + OUString getLongName( const OUString& rShortName ); + sal_Bool setTitleForURL( const OUString& rURL, const OUString& aTitle ); + sal_Bool getTitleFromURL( const OUString& rURL, OUString& aTitle, OUString& aType, sal_Bool& bDocHasTitle ); + + sal_Bool addEntry( Content& rParentFolder, + const OUString& rTitle, + const OUString& rTargetURL, + const OUString& rType ); + + sal_Bool createFolder( const OUString& rNewFolderURL, + sal_Bool bCreateParent, + sal_Bool bFsysFolder, + Content &rNewFolder ); + + sal_Bool CreateNewUniqueFolderWithPrefix( const ::rtl::OUString& aPath, + const ::rtl::OUString& aPrefix, + ::rtl::OUString& aNewFolderName, + ::rtl::OUString& aNewFolderURL, + Content& aNewFolder ); + ::rtl::OUString CreateNewUniqueFileWithPrefix( const ::rtl::OUString& aPath, + const ::rtl::OUString& aPrefix, + const ::rtl::OUString& aExt ); + + uno::Sequence< beans::StringPair > ReadUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath ); + sal_Bool UpdateUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const ::rtl::OUString& aGroupName, + const ::rtl::OUString& aNewFolderName ); + sal_Bool ReplaceUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const ::rtl::OUString& aFsysGroupName, + const ::rtl::OUString& aOldGroupName, + const ::rtl::OUString& aNewGroupName ); + sal_Bool RemoveUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const ::rtl::OUString& aGroupName ); + sal_Bool WriteUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const uno::Sequence< beans::StringPair >& aUINames ); + + ::rtl::OUString CreateNewGroupFsys( const ::rtl::OUString& rGroupName, Content& aGroup ); + + sal_Bool removeContent( Content& rContent ); + sal_Bool removeContent( const OUString& rContentURL ); + + sal_Bool setProperty( Content& rContent, + const OUString& rPropName, + const Any& rPropValue ); + sal_Bool getProperty( Content& rContent, + const OUString& rPropName, + Any& rPropValue ); + + void createFromContent( GroupList_Impl& rList, + Content &rContent, + sal_Bool bHierarchy, + sal_Bool bWriteableContent = sal_False ); + void addHierGroup( GroupList_Impl& rList, + const OUString& rTitle, + const OUString& rOwnURL ); + void addFsysGroup( GroupList_Impl& rList, + const OUString& rTitle, + const OUString& rUITitle, + const OUString& rOwnURL, + sal_Bool bWriteableGroup = sal_False ); + void removeFromHierarchy( DocTemplates_EntryData_Impl *pData ); + void addToHierarchy( GroupData_Impl *pGroup, + DocTemplates_EntryData_Impl *pData ); + + void removeFromHierarchy( GroupData_Impl *pGroup ); + void addGroupToHierarchy( GroupData_Impl *pGroup ); + + void updateData( DocTemplates_EntryData_Impl *pData ); + +public: + SfxDocTplService_Impl( uno::Reference< XMultiServiceFactory > xFactory ); + ~SfxDocTplService_Impl(); + + sal_Bool init() { if ( !mbIsInitialized ) init_Impl(); return mbIsInitialized; } + Content getContent() { return maRootContent; } + + void setLocale( const Locale & rLocale ); + Locale getLocale(); + + sal_Bool storeTemplate( const OUString& rGroupName, + const OUString& rTemplateName, + const uno::Reference< XSTORABLE >& rStorable ); + + sal_Bool addTemplate( const OUString& rGroupName, + const OUString& rTemplateName, + const OUString& rSourceURL ); + sal_Bool removeTemplate( const OUString& rGroupName, + const OUString& rTemplateName ); + sal_Bool renameTemplate( const OUString& rGroupName, + const OUString& rOldName, + const OUString& rNewName ); + + sal_Bool addGroup( const OUString& rGroupName ); + sal_Bool removeGroup( const OUString& rGroupName ); + sal_Bool renameGroup( const OUString& rOldName, + const OUString& rNewName ); + + void update( sal_Bool bUpdateNow ); + void doUpdate(); + void finished() { mpUpdater = NULL; } +}; + +//============================================================================= + +class Updater_Impl : public ::vos::OThread +{ +private: + SfxDocTplService_Impl *mpDocTemplates; + +public: + Updater_Impl( SfxDocTplService_Impl* pTemplates ); + ~Updater_Impl(); + + virtual void SAL_CALL run(); + virtual void SAL_CALL onTerminated(); +}; + +//============================================================================= + +class DocTemplates_EntryData_Impl +{ + OUString maTitle; + OUString maType; + OUString maTargetURL; + OUString maHierarchyURL; + + sal_Bool mbInHierarchy : 1; + sal_Bool mbInUse : 1; + sal_Bool mbUpdateType : 1; + sal_Bool mbUpdateLink : 1; + +public: + DocTemplates_EntryData_Impl( const OUString& rTitle ); + + void setInUse() { mbInUse = sal_True; } + void setHierarchy( sal_Bool bInHierarchy ) { mbInHierarchy = bInHierarchy; } + void setUpdateLink( sal_Bool bUpdateLink ) { mbUpdateLink = bUpdateLink; } + void setUpdateType( sal_Bool bUpdateType ) { mbUpdateType = bUpdateType; } + + sal_Bool getInUse() const { return mbInUse; } + sal_Bool getInHierarchy() const { return mbInHierarchy; } + sal_Bool getUpdateLink() const { return mbUpdateLink; } + sal_Bool getUpdateType() const { return mbUpdateType; } + + const OUString& getHierarchyURL() const { return maHierarchyURL; } + const OUString& getTargetURL() const { return maTargetURL; } + const OUString& getTitle() const { return maTitle; } + const OUString& getType() const { return maType; } + + void setHierarchyURL( const OUString& rURL ) { maHierarchyURL = rURL; } + void setTargetURL( const OUString& rURL ) { maTargetURL = rURL; } + void setType( const OUString& rType ) { maType = rType; } +}; + +//============================================================================= + +class GroupData_Impl +{ + DECLARE_LIST( EntryList_Impl, DocTemplates_EntryData_Impl* ) + EntryList_Impl maEntries; + OUString maTitle; + OUString maHierarchyURL; + OUString maTargetURL; + sal_Bool mbInUse : 1; + sal_Bool mbInHierarchy : 1; + +public: + GroupData_Impl( const OUString& rTitle ); + ~GroupData_Impl(); + + void setInUse() { mbInUse = sal_True; } + void setHierarchy( sal_Bool bInHierarchy ) { mbInHierarchy = bInHierarchy; } + void setHierarchyURL( const OUString& rURL ) { maHierarchyURL = rURL; } + void setTargetURL( const OUString& rURL ) { maTargetURL = rURL; } + + sal_Bool getInUse() { return mbInUse; } + sal_Bool getInHierarchy() { return mbInHierarchy; } + const OUString& getHierarchyURL() const { return maHierarchyURL; } + const OUString& getTargetURL() const { return maTargetURL; } + const OUString& getTitle() const { return maTitle; } + + DocTemplates_EntryData_Impl* addEntry( const OUString& rTitle, + const OUString& rTargetURL, + const OUString& rType, + const OUString& rHierURL ); + ULONG count() { return maEntries.Count(); } + DocTemplates_EntryData_Impl* getEntry( ULONG nPos ) { return maEntries.GetObject( nPos ); } +}; + +DECLARE_LIST( GroupList_Impl, GroupData_Impl* ) + +//============================================================================= +//============================================================================= +//============================================================================= + +//----------------------------------------------------------------------------- +// private SfxDocTplService_Impl +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::init_Impl() +{ + uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); + if ( xFactory.is() ) + { + uno::Reference < task::XInteractionHandler > xInteractionHandler( xFactory->createInstance( DEFINE_CONST_UNICODE("com.sun.star.task.InteractionHandler") ), uno::UNO_QUERY ); + maCmdEnv = new TplTaskEnvironment( xInteractionHandler ); + } + + ::osl::ClearableMutexGuard aGuard( maMutex ); + sal_Bool bIsInitialized = sal_False; + sal_Bool bNeedsUpdate = sal_False; + + if ( !mbLocaleSet ) + getDefaultLocale(); + + // convert locale to string + OUString aLang = maLocale.Language; + aLang += String( '-' ); + aLang += maLocale.Country; + + // set maRootContent to the root of the templates hierarchy. Create the + // entry if necessary + + maRootURL = OUString( RTL_CONSTASCII_USTRINGPARAM( TEMPLATE_ROOT_URL ) ); + maRootURL += String( '/' ); + maRootURL += aLang; + + ::rtl::OUString aTemplVersPropName( RTL_CONSTASCII_USTRINGPARAM( TEMPLATE_VERSION ) ); + ::rtl::OUString aTemplVers( RTL_CONSTASCII_USTRINGPARAM( TEMPLATE_VERSION_VALUE ) ); + if ( Content::create( maRootURL, maCmdEnv, maRootContent ) ) + { + uno::Any aValue; + ::rtl::OUString aPropValue; + if ( getProperty( maRootContent, aTemplVersPropName, aValue ) + && ( aValue >>= aPropValue ) + && aPropValue.equals( aTemplVers ) ) + { + bIsInitialized = sal_True; + } + else + removeContent( maRootContent ); + } + + if ( !bIsInitialized ) + { + if ( createFolder( maRootURL, sal_True, sal_False, maRootContent ) + && setProperty( maRootContent, aTemplVersPropName, uno::makeAny( aTemplVers ) ) ) + bIsInitialized = sal_True; + + bNeedsUpdate = sal_True; + } + + if ( bIsInitialized ) + { + OUString aService( RTL_CONSTASCII_USTRINGPARAM( SERVICENAME_DOCINFO ) ); + try { + mxInfo = uno::Reference< XStandaloneDocumentInfo > ( + mxFactory->createInstance( aService ), UNO_QUERY ); + } catch (uno::RuntimeException &) { + OSL_ENSURE(false, "SfxDocTplService_Impl::init_Impl: " + "cannot create DocumentProperties service"); + } + + aService = OUString( RTL_CONSTASCII_USTRINGPARAM( SERVICENAME_TYPEDETECTION ) ); + mxType = uno::Reference< XTypeDetection > ( mxFactory->createInstance( aService ), UNO_QUERY ); + + getDirList(); + readFolderList(); + + if ( bNeedsUpdate ) + { + aGuard.clear(); + ::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() ); + + WaitWindow_Impl* pWin = new WaitWindow_Impl(); + + aSolarGuard.clear(); + ::osl::ClearableMutexGuard anotherGuard( maMutex ); + + update( sal_True ); + + anotherGuard.clear(); + ::vos::OGuard aSecondSolarGuard( Application::GetSolarMutex() ); + + delete pWin; + } + else if ( needsUpdate() ) + // the UI should be shown only on the first update + update( sal_True ); + } + else + { + DBG_ERRORFILE( "init_Impl(): Could not create root" ); + } + + mbIsInitialized = bIsInitialized; +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::getDefaultLocale() +{ + if ( !mbLocaleSet ) + { + ::osl::MutexGuard aGuard( maMutex ); + if ( !mbLocaleSet ) + { + rtl::OUString aLocale; + utl::ConfigManager::GetDirectConfigProperty( utl::ConfigManager::LOCALE ) + >>= aLocale; + + if ( aLocale.getLength() > 0 ) + { + sal_Int32 nPos = aLocale.indexOf( sal_Unicode( '-' ) ); + if ( nPos != -1 ) + { + maLocale.Language = aLocale.copy( 0, nPos ); + nPos = aLocale.indexOf( sal_Unicode( '_' ), nPos + 1 ); + if ( nPos != -1 ) + { + maLocale.Country + = aLocale.copy( maLocale.Language.getLength() + 1, + nPos - maLocale.Language.getLength() - 1 ); + maLocale.Variant + = aLocale.copy( nPos + 1 ); + } + else + { + maLocale.Country + = aLocale.copy( maLocale.Language.getLength() + 1 ); + } + } + + } + + mbLocaleSet = sal_True; + } + } +} + +// ----------------------------------------------------------------------- +void SfxDocTplService_Impl::readFolderList() +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + ResStringArray aShortNames( SfxResId( TEMPLATE_SHORT_NAMES_ARY ) ); + ResStringArray aLongNames( SfxResId( TEMPLATE_LONG_NAMES_ARY ) ); + + NamePair_Impl* pPair; + + USHORT nCount = (USHORT)( Min( aShortNames.Count(), aLongNames.Count() ) ); + + for ( USHORT i=0; i<nCount; i++ ) + { + pPair = new NamePair_Impl; + pPair->maShortName = aShortNames.GetString( i ); + pPair->maLongName = aLongNames.GetString( i ); + + maNames.Insert( pPair, LIST_APPEND ); + } +} + +// ----------------------------------------------------------------------- +OUString SfxDocTplService_Impl::getLongName( const OUString& rShortName ) +{ + OUString aRet; + NamePair_Impl *pPair = maNames.First(); + + while ( pPair ) + { + if ( pPair->maShortName == rShortName ) + { + aRet = pPair->maLongName; + break; + } + else + pPair = maNames.Next(); + } + + if ( !aRet.getLength() ) + aRet = rShortName; + + return aRet; +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::getDirList() +{ + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_DIRLIST ) ); + Any aValue; + + // Get the template dir list + // TODO/LATER: let use service, register listener + INetURLObject aURL; + String aDirs = SvtPathOptions().GetTemplatePath(); + USHORT nCount = aDirs.GetTokenCount( C_DELIM ); + + maTemplateDirs = Sequence< OUString >( nCount ); + + for ( USHORT i=0; i<nCount; i++ ) + { + aURL.SetSmartProtocol( INET_PROT_FILE ); + aURL.SetURL( aDirs.GetToken( i, C_DELIM ) ); + maTemplateDirs[i] = aURL.GetMainURL( INetURLObject::NO_DECODE ); + } + + aValue <<= maTemplateDirs; + + // Store the template dir list + setProperty( maRootContent, aPropName, aValue ); +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::needsUpdate() +{ + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_NEEDSUPDATE ) ); + sal_Bool bHasProperty = sal_False; + sal_Bool bNeedsUpdate = sal_True; + Any aValue; + + // Get the template dir list + bHasProperty = getProperty( maRootContent, aPropName, aValue ); + + if ( bHasProperty ) + aValue >>= bNeedsUpdate; + + // the old template component also checks this state, but it is initialized from this component + // so if this componend was already updated the old component does not need such an update + ::svt::TemplateFolderCache aTempCache; + if ( !bNeedsUpdate ) + bNeedsUpdate = aTempCache.needsUpdate(); + + if ( bNeedsUpdate ) + aTempCache.storeState(); + + return bNeedsUpdate; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::setTitleForURL( const OUString& rURL, const OUString& aTitle ) +{ + sal_Bool bResult = sal_False; + if ( mxInfo.is() ) + { + try + { + mxInfo->loadFromURL( rURL ); + uno::Reference< XPropertySet > xPropSet( mxInfo, UNO_QUERY_THROW ); + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + xPropSet->setPropertyValue( aPropName, uno::makeAny( aTitle ) ); + mxInfo->storeIntoURL( rURL ); + bResult = sal_True; + } + catch ( Exception& ) + { + } + } + + return bResult; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::getTitleFromURL( const OUString& rURL, OUString& aTitle, OUString& aType, sal_Bool& bDocHasTitle ) +{ + bDocHasTitle = sal_False; + + if ( mxInfo.is() ) + { + try + { + mxInfo->loadFromURL( rURL ); + } + catch ( Exception& ) + { + // the document is not a StarOffice document + return sal_False; + } + + try + { + uno::Reference< XPropertySet > aPropSet( mxInfo, UNO_QUERY ); + if ( aPropSet.is() ) + { + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + Any aValue = aPropSet->getPropertyValue( aPropName ); + aValue >>= aTitle; + + aPropName = OUString( RTL_CONSTASCII_USTRINGPARAM( "MIMEType" ) ); + aValue = aPropSet->getPropertyValue( aPropName ); + aValue >>= aType; + } + } + catch ( UnknownPropertyException& ) {} + catch ( Exception& ) {} + } + + if ( ! aType.getLength() && mxType.is() ) + { + ::rtl::OUString aDocType = mxType->queryTypeByURL( rURL ); + if ( aDocType.getLength() ) + try + { + uno::Reference< container::XNameAccess > xTypeDetection( mxType, uno::UNO_QUERY_THROW ); + SequenceAsHashMap aTypeProps( xTypeDetection->getByName( aDocType ) ); + aType = aTypeProps.getUnpackedValueOrDefault( + ::rtl::OUString::createFromAscii( "MediaType" ), + ::rtl::OUString() ); + } + catch( uno::Exception& ) + {} + } + + if ( ! aTitle.getLength() ) + { + INetURLObject aURL( rURL ); + aURL.CutExtension(); + aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true, + INetURLObject::DECODE_WITH_CHARSET ); + } + else + bDocHasTitle = sal_True; + + return sal_True; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::addEntry( Content& rParentFolder, + const OUString& rTitle, + const OUString& rTargetURL, + const OUString& rType ) +{ + sal_Bool bAddedEntry = sal_False; + + INetURLObject aLinkObj( rParentFolder.getURL() ); + aLinkObj.insertName( rTitle, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + OUString aLinkURL = aLinkObj.GetMainURL( INetURLObject::NO_DECODE ); + + Content aLink; + + if ( ! Content::create( aLinkURL, maCmdEnv, aLink ) ) + { + Sequence< OUString > aNames(3); + aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + aNames[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( IS_FOLDER ) ); + aNames[2] = OUString( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + + Sequence< Any > aValues(3); + aValues[0] = makeAny( rTitle ); + aValues[1] = makeAny( sal_Bool( sal_False ) ); + aValues[2] = makeAny( rTargetURL ); + + OUString aType( RTL_CONSTASCII_USTRINGPARAM( TYPE_LINK ) ); + OUString aAdditionalProp( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_TYPE ) ); + + try + { + rParentFolder.insertNewContent( aType, aNames, aValues, aLink ); + setProperty( aLink, aAdditionalProp, makeAny( rType ) ); + bAddedEntry = sal_True; + } + catch( Exception& ) + {} + } + return bAddedEntry; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::createFolder( const OUString& rNewFolderURL, + sal_Bool bCreateParent, + sal_Bool bFsysFolder, + Content &rNewFolder ) +{ + Content aParent; + sal_Bool bCreatedFolder = sal_False; + INetURLObject aParentURL( rNewFolderURL ); + OUString aFolderName = aParentURL.getName( INetURLObject::LAST_SEGMENT, true, + INetURLObject::DECODE_WITH_CHARSET ); + + // compute the parent folder url from the new folder url + // and remove the final slash, because Content::create doesn't + // like it + aParentURL.removeSegment(); + if ( aParentURL.getSegmentCount() >= 1 ) + aParentURL.removeFinalSlash(); + + // if the parent exists, we can continue with the creation of the + // new folder, we have to create the parent otherwise ( as long as + // bCreateParent is set to true ) + if ( Content::create( aParentURL.GetMainURL( INetURLObject::NO_DECODE ), maCmdEnv, aParent ) ) + { + try + { + Sequence< OUString > aNames(2); + aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + aNames[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( IS_FOLDER ) ); + + Sequence< Any > aValues(2); + aValues[0] = makeAny( aFolderName ); + aValues[1] = makeAny( sal_Bool( sal_True ) ); + + OUString aType; + + if ( bFsysFolder ) + aType = OUString( RTL_CONSTASCII_USTRINGPARAM( TYPE_FSYS_FOLDER ) ); + else + aType = OUString( RTL_CONSTASCII_USTRINGPARAM( TYPE_FOLDER ) ); + + aParent.insertNewContent( aType, aNames, aValues, rNewFolder ); + bCreatedFolder = sal_True; + } + catch( RuntimeException& ) + { + DBG_ERRORFILE( "createFolder(): got runtime exception" ); + } + catch( Exception& ) + { + DBG_ERRORFILE( "createFolder(): Could not create new folder" ); + } + } + else if ( bCreateParent ) + { + // if the parent doesn't exists and bCreateParent is set to true, + // we try to create the parent and if this was successful, we + // try to create the new folder again ( but this time, we set + // bCreateParent to false to avoid endless recusions ) + if ( ( aParentURL.getSegmentCount() >= 1 ) && + createFolder( aParentURL.GetMainURL( INetURLObject::NO_DECODE ), bCreateParent, bFsysFolder, aParent ) ) + { + bCreatedFolder = createFolder( rNewFolderURL, sal_False, bFsysFolder, rNewFolder ); + } + } + + return bCreatedFolder; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::CreateNewUniqueFolderWithPrefix( const ::rtl::OUString& aPath, + const ::rtl::OUString& aPrefix, + ::rtl::OUString& aNewFolderName, + ::rtl::OUString& aNewFolderURL, + Content& aNewFolder ) +{ + sal_Bool bCreated = sal_False; + INetURLObject aDirPath( aPath ); + + Content aParent; + if ( Content::create( aDirPath.GetMainURL( INetURLObject::NO_DECODE ), maCmdEnv, aParent ) ) + { + for ( sal_Int32 nInd = 0; nInd < 32000; nInd++ ) + { + ::rtl::OUString aTryName = aPrefix; + if ( nInd ) + aTryName += ::rtl::OUString::valueOf( nInd ); + + try + { + Sequence< OUString > aNames(2); + aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + aNames[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( IS_FOLDER ) ); + + Sequence< Any > aValues(2); + aValues[0] = makeAny( aTryName ); + aValues[1] = makeAny( sal_Bool( sal_True ) ); + + OUString aType( RTL_CONSTASCII_USTRINGPARAM( TYPE_FSYS_FOLDER ) ); + + bCreated = aParent.insertNewContent( aType, aNames, aValues, aNewFolder ); + } + catch( ucb::NameClashException& ) + { + // if there is already an element, retry + } + catch( Exception& ) + { + INetURLObject aObjPath( aDirPath ); + aObjPath.insertName( aTryName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + // if there is already an element, retry + // if there was another error, do not try any more + if ( !::utl::UCBContentHelper::Exists( aObjPath.GetMainURL( INetURLObject::NO_DECODE ) ) ) + break; + } + + if ( bCreated ) + { + aNewFolderName = aTryName; + aNewFolderURL = aNewFolder.get()->getIdentifier()->getContentIdentifier(); + break; + } + } + } + + return bCreated; +} + +// ----------------------------------------------------------------------- +::rtl::OUString SfxDocTplService_Impl::CreateNewUniqueFileWithPrefix( const ::rtl::OUString& aPath, + const ::rtl::OUString& aPrefix, + const ::rtl::OUString& aExt ) +{ + ::rtl::OUString aNewFileURL; + INetURLObject aDirPath( aPath ); + + Content aParent; + + uno::Reference< XCommandEnvironment > aQuietEnv; + if ( Content::create( aDirPath.GetMainURL( INetURLObject::NO_DECODE ), aQuietEnv, aParent ) ) + { + for ( sal_Int32 nInd = 0; nInd < 32000; nInd++ ) + { + Content aNewFile; + sal_Bool bCreated = sal_False; + ::rtl::OUString aTryName = aPrefix; + if ( nInd ) + aTryName += ::rtl::OUString::valueOf( nInd ); + if ( aExt.toChar() != '.' ) + aTryName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "." ) ); + aTryName += aExt; + + try + { + Sequence< OUString > aNames(2); + aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + aNames[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( IS_DOCUMENT ) ); + + Sequence< Any > aValues(2); + aValues[0] = makeAny( aTryName ); + aValues[1] = makeAny( sal_Bool( sal_True ) ); + + OUString aType( RTL_CONSTASCII_USTRINGPARAM( TYPE_FSYS_FILE ) ); + + bCreated = aParent.insertNewContent( aType, aNames, aValues, aNewFile ); + } + catch( ucb::NameClashException& ) + { + // if there is already an element, retry + } + catch( Exception& ) + { + INetURLObject aObjPath( aPath ); + aObjPath.insertName( aTryName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + // if there is already an element, retry + // if there was another error, do not try any more + if ( !::utl::UCBContentHelper::Exists( aObjPath.GetMainURL( INetURLObject::NO_DECODE ) ) ) + break; + } + + if ( bCreated ) + { + aNewFileURL = aNewFile.get()->getIdentifier()->getContentIdentifier(); + break; + } + } + } + + return aNewFileURL; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::removeContent( Content& rContent ) +{ + sal_Bool bRemoved = sal_False; + try + { + OUString aCmd( RTL_CONSTASCII_USTRINGPARAM( COMMAND_DELETE ) ); + Any aArg = makeAny( sal_Bool( sal_True ) ); + + rContent.executeCommand( aCmd, aArg ); + bRemoved = sal_True; + } + catch ( RuntimeException& ) {} + catch ( Exception& ) {} + + return bRemoved; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::removeContent( const OUString& rContentURL ) +{ + Content aContent; + + if ( Content::create( rContentURL, maCmdEnv, aContent ) ) + return removeContent( aContent ); + else + return sal_False; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::setProperty( Content& rContent, + const OUString& rPropName, + const Any& rPropValue ) +{ + sal_Bool bPropertySet = sal_False; + + // Store the property + try + { + Any aPropValue( rPropValue ); + uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties(); + + // check, wether or not the property exists, create it, when not + if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) ) + { + uno::Reference< XPropertyContainer > xProperties( rContent.get(), UNO_QUERY ); + if ( xProperties.is() ) + { + try + { + xProperties->addProperty( rPropName, PropertyAttribute::MAYBEVOID, rPropValue ); + } + catch( PropertyExistException& ) {} + catch( IllegalTypeException& ) { DBG_ERRORFILE( "IllegalTypeException" ); } + catch( IllegalArgumentException& ) { DBG_ERRORFILE( "IllegalArgumentException" ); } + } + } + + // To ensure a reloctable office installation, the path to the + // office installtion directory must never be stored directly. + if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) ) + { + OUString aValue; + if ( rPropValue >>= aValue ) + { + maRelocator.makeRelocatableURL( aValue ); + aPropValue = makeAny( aValue ); + } + else + { + Sequence< OUString > aValues; + if ( rPropValue >>= aValues ) + { + for ( sal_Int32 n = 0; n < aValues.getLength(); n++ ) + { + maRelocator.makeRelocatableURL( aValues[ n ] ); + } + aPropValue = makeAny( aValues ); + } + else + { + OSL_ENSURE( false, "Unsupported property value type" ); + } + } + } + + // now set the property + + rContent.setPropertyValue( rPropName, aPropValue ); + bPropertySet = sal_True; + } + catch ( RuntimeException& ) {} + catch ( Exception& ) {} + + return bPropertySet; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::getProperty( Content& rContent, + const OUString& rPropName, + Any& rPropValue ) +{ + sal_Bool bGotProperty = sal_False; + + // Get the property + try + { + uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties(); + + // check, wether or not the property exists + if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) ) + { + return sal_False; + } + + // now get the property + + rPropValue = rContent.getPropertyValue( rPropName ); + + // To ensure a reloctable office installation, the path to the + // office installtion directory must never be stored directly. + if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) ) + { + OUString aValue; + if ( rPropValue >>= aValue ) + { + maRelocator.makeAbsoluteURL( aValue ); + rPropValue = makeAny( aValue ); + } + else + { + Sequence< OUString > aValues; + if ( rPropValue >>= aValues ) + { + for ( sal_Int32 n = 0; n < aValues.getLength(); n++ ) + { + maRelocator.makeAbsoluteURL( aValues[ n ] ); + } + rPropValue = makeAny( aValues ); + } + else + { + OSL_ENSURE( false, "Unsupported property value type" ); + } + } + } + + bGotProperty = sal_True; + } + catch ( RuntimeException& ) {} + catch ( Exception& ) {} + + return bGotProperty; +} + +// ----------------------------------------------------------------------- +// static +bool SfxURLRelocator_Impl::propertyCanContainOfficeDir( + const rtl::OUString & rPropName ) +{ + // Note: TargetURL is handled by UCB itself (because it is a property + // with a predefined semantic). Additional Core properties introduced + // be a client app must be handled by the client app itself, because + // the UCB does not know the semantics of those properties. + return ( rPropName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( TARGET_DIR_URL ) ) || + rPropName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( PROPERTY_DIRLIST ) ) ); +} + +//----------------------------------------------------------------------------- +// public SfxDocTplService_Impl +//----------------------------------------------------------------------------- + +SfxDocTplService_Impl::SfxDocTplService_Impl( uno::Reference< XMultiServiceFactory > xFactory ) +: maRelocator( xFactory ) +{ + mxFactory = xFactory; + mpUpdater = NULL; + mbIsInitialized = sal_False; + mbLocaleSet = sal_False; +} + +//----------------------------------------------------------------------------- +SfxDocTplService_Impl::~SfxDocTplService_Impl() +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( mpUpdater ) + { + mpUpdater->kill(); + delete mpUpdater; + } +} + +//----------------------------------------------------------------------------- +Locale SfxDocTplService_Impl::getLocale() +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( !mbLocaleSet ) + getDefaultLocale(); + + return maLocale; +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::setLocale( const Locale &rLocale ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( mbLocaleSet && + ( maLocale.Language != rLocale.Language ) && + ( maLocale.Country != rLocale.Country ) ) + mbIsInitialized = sal_False; + + maLocale = rLocale; + mbLocaleSet = sal_True; +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::update( sal_Bool bUpdateNow ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( bUpdateNow ) + doUpdate(); + else + { + mpUpdater = new Updater_Impl( this ); + mpUpdater->create(); + } +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::doUpdate() +{ + ::osl::MutexGuard aGuard( maMutex ); + + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_NEEDSUPDATE ) ); + Any aValue; + + aValue <<= sal_True; + setProperty( maRootContent, aPropName, aValue ); + + GroupList_Impl aGroupList; + + // get the entries from the hierarchy + createFromContent( aGroupList, maRootContent, sal_True ); + + // get the entries from the template directories + sal_Int32 nCountDir = maTemplateDirs.getLength(); + OUString* pDirs = maTemplateDirs.getArray(); + Content aDirContent; + + // the last directory in the list must be writable + sal_Bool bWriteableDirectory = sal_True; + + // the target folder might not exist, for this reason no interaction handler should be used + uno::Reference< XCommandEnvironment > aQuietEnv; + + while ( nCountDir ) + { + nCountDir--; + if ( Content::create( pDirs[ nCountDir ], aQuietEnv, aDirContent ) ) + { + createFromContent( aGroupList, aDirContent, sal_False, bWriteableDirectory ); + } + + bWriteableDirectory = sal_False; + } + + // now check the list + GroupData_Impl *pGroup = aGroupList.First(); + while ( pGroup ) + { + if ( pGroup->getInUse() ) + { + if ( pGroup->getInHierarchy() ) + { + Content aGroup; + if ( Content::create( pGroup->getHierarchyURL(), maCmdEnv, aGroup ) ) + setProperty( aGroup, + OUString( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ), + makeAny( pGroup->getTargetURL() ) ); + + ULONG nCount = pGroup->count(); + for ( ULONG i=0; i<nCount; i++ ) + { + DocTemplates_EntryData_Impl *pData = pGroup->getEntry( i ); + if ( ! pData->getInUse() ) + { + if ( pData->getInHierarchy() ) + removeFromHierarchy( pData ); // delete entry in hierarchy + else + addToHierarchy( pGroup, pData ); // add entry to hierarchy + } + else if ( pData->getUpdateType() || + pData->getUpdateLink() ) + { + updateData( pData ); + } + } + } + else + { + addGroupToHierarchy( pGroup ); // add group to hierarchy + } + } + else + removeFromHierarchy( pGroup ); // delete group from hierarchy + + delete pGroup; + pGroup = aGroupList.Next(); + } + + aValue <<= sal_False; + setProperty( maRootContent, aPropName, aValue ); +} + +//----------------------------------------------------------------------------- +uno::Sequence< beans::StringPair > SfxDocTplService_Impl::ReadUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath ) +{ + INetURLObject aLocObj( aUserPath ); + aLocObj.insertName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "groupuinames.xml" ) ), false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + Content aLocContent; + + // TODO/LATER: Use hashmap in future + uno::Sequence< beans::StringPair > aUINames; + if ( Content::create( aLocObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference < ucb::XCommandEnvironment >(), aLocContent ) ) + { + try + { + uno::Reference< io::XInputStream > xLocStream = aLocContent.openStream(); + if ( xLocStream.is() ) + aUINames = DocTemplLocaleHelper::ReadGroupLocalizationSequence( xLocStream, mxFactory ); + } + catch( uno::Exception& ) + {} + } + + return aUINames; +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::UpdateUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const ::rtl::OUString& aGroupName, + const ::rtl::OUString& aNewFolderName ) +{ + uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath ); + sal_Int32 nLen = aUINames.getLength(); + + // it is possible that the name is used already, but it should be checked before + for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ ) + if ( aUINames[nInd].First.equals( aNewFolderName ) ) + return sal_False; + + aUINames.realloc( ++nLen ); + aUINames[nLen-1].First = aNewFolderName; + aUINames[nLen-1].Second = aGroupName; + + return WriteUINamesForTemplateDir_Impl( aUserPath, aUINames ); +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::ReplaceUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const ::rtl::OUString& aDefaultFsysGroupName, + const ::rtl::OUString& aOldGroupName, + const ::rtl::OUString& aNewGroupName ) +{ + uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath ); + sal_Int32 nLen = aUINames.getLength(); + + sal_Bool bChanged = sal_False; + for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ ) + if ( aUINames[nInd].Second.equals( aOldGroupName ) ) + { + aUINames[nInd].Second = aNewGroupName; + bChanged = sal_True; + } + + if ( !bChanged ) + { + aUINames.realloc( ++nLen ); + aUINames[nLen-1].First = aDefaultFsysGroupName; + aUINames[nLen-1].Second = aNewGroupName; + } + return WriteUINamesForTemplateDir_Impl( aUserPath, aUINames ); +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::RemoveUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const ::rtl::OUString& aGroupName ) +{ + uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath ); + sal_Int32 nLen = aUINames.getLength(); + uno::Sequence< beans::StringPair > aNewUINames( nLen ); + sal_Int32 nNewLen = 0; + + sal_Bool bChanged = sal_False; + for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ ) + if ( aUINames[nInd].Second.equals( aGroupName ) ) + bChanged = sal_True; + else + { + nNewLen++; + aNewUINames[nNewLen-1].First = aUINames[nInd].First; + aNewUINames[nNewLen-1].Second = aUINames[nInd].Second; + } + + aNewUINames.realloc( nNewLen ); + + return bChanged ? WriteUINamesForTemplateDir_Impl( aUserPath, aNewUINames ) : sal_True; +} + + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::WriteUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const uno::Sequence< beans::StringPair >& aUINames ) +{ + sal_Bool bResult = sal_False; + try { + uno::Reference< beans::XPropertySet > xTempFile( + mxFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ), + uno::UNO_QUERY_THROW ); + + ::rtl::OUString aTempURL; + uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) ); + aUrl >>= aTempURL; + + uno::Reference< io::XStream > xStream( xTempFile, uno::UNO_QUERY_THROW ); + uno::Reference< io::XOutputStream > xOutStream = xStream->getOutputStream(); + if ( !xOutStream.is() ) + throw uno::RuntimeException(); + + DocTemplLocaleHelper::WriteGroupLocalizationSequence( xOutStream, aUINames, mxFactory ); + try { + // the SAX writer might close the stream + xOutStream->closeOutput(); + } catch( uno::Exception& ) + {} + + Content aTargetContent( aUserPath, maCmdEnv ); + Content aSourceContent( aTempURL, maCmdEnv ); + aTargetContent.transferContent( aSourceContent, + InsertOperation_COPY, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "groupuinames.xml" ) ), + ucb::NameClash::OVERWRITE ); + bResult = sal_True; + } + catch ( uno::Exception& ) + { + } + + return bResult; +} + +//----------------------------------------------------------------------------- +::rtl::OUString SfxDocTplService_Impl::CreateNewGroupFsys( const ::rtl::OUString& rGroupName, Content& aGroup ) +{ + ::rtl::OUString aResultURL; + + if ( maTemplateDirs.getLength() ) + { + ::rtl::OUString aTargetPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ]; + + // create a new folder with the given name + Content aNewFolder; + ::rtl::OUString aNewFolderName; + + // the Fsys name instead of GroupName should be used, the groupuinames must be added also + if ( !CreateNewUniqueFolderWithPrefix( aTargetPath, + rGroupName, + aNewFolderName, + aResultURL, + aNewFolder ) + && !CreateNewUniqueFolderWithPrefix( aTargetPath, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserGroup" ) ), + aNewFolderName, + aResultURL, + aNewFolder ) ) + + return ::rtl::OUString(); + + if ( !UpdateUINamesForTemplateDir_Impl( aTargetPath, rGroupName, aNewFolderName ) ) + { + // we could not create the groupuinames for the folder, so we delete the group in the + // the folder and return + removeContent( aNewFolder ); + return ::rtl::OUString(); + } + + // Now set the target url for this group and we are done + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + Any aValue = makeAny( aResultURL ); + + if ( ! setProperty( aGroup, aPropName, aValue ) ) + { + removeContent( aNewFolder ); + return ::rtl::OUString(); + } + } + + return aResultURL; +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::addGroup( const OUString& rGroupName ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + // Check, wether or not there is a group with this name + Content aNewGroup; + OUString aNewGroupURL; + INetURLObject aNewGroupObj( maRootURL ); + + aNewGroupObj.insertName( rGroupName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + aNewGroupURL = aNewGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( Content::create( aNewGroupURL, maCmdEnv, aNewGroup ) || + ! createFolder( aNewGroupURL, sal_False, sal_False, aNewGroup ) ) + { + // if there already was a group with this name or the new group + // could not be created, we return here + return sal_False; + } + + // Get the user template path entry ( new group will always + // be added in the user template path ) + sal_Int32 nIndex; + OUString aUserPath; + + nIndex = maTemplateDirs.getLength(); + if ( nIndex ) + nIndex--; + else + return sal_False; // We don't know where to add the group + + aUserPath = maTemplateDirs[ nIndex ]; + + // create a new folder with the given name + Content aNewFolder; + OUString aNewFolderName; + OUString aNewFolderURL; + + // the Fsys name instead of GroupName should be used, the groupuinames must be added also + if ( !CreateNewUniqueFolderWithPrefix( aUserPath, + rGroupName, + aNewFolderName, + aNewFolderURL, + aNewFolder ) + && !CreateNewUniqueFolderWithPrefix( aUserPath, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserGroup" ) ), + aNewFolderName, + aNewFolderURL, + aNewFolder ) ) + { + // we could not create the folder, so we delete the group in the + // hierarchy and return + removeContent( aNewGroup ); + return sal_False; + } + + if ( !UpdateUINamesForTemplateDir_Impl( aUserPath, rGroupName, aNewFolderName ) ) + { + // we could not create the groupuinames for the folder, so we delete the group in the + // hierarchy, the folder and return + removeContent( aNewGroup ); + removeContent( aNewFolder ); + return sal_False; + } + + // Now set the target url for this group and we are done + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + Any aValue = makeAny( aNewFolderURL ); + + if ( ! setProperty( aNewGroup, aPropName, aValue ) ) + { + removeContent( aNewGroup ); + removeContent( aNewFolder ); + return sal_False; + } + + return sal_True; +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::removeGroup( const OUString& rGroupName ) +{ + // remove all the elements that have the prefix aTargetURL + // if the group does not have other elements remove it + + ::osl::MutexGuard aGuard( maMutex ); + + sal_Bool bResult = sal_False; + + // create the group url + INetURLObject aGroupObj( maRootURL ); + aGroupObj.insertName( rGroupName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + // Get the target url + Content aGroup; + OUString aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( Content::create( aGroupURL, maCmdEnv, aGroup ) ) + { + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + Any aValue; + + OUString aGroupTargetURL; + if ( getProperty( aGroup, aPropName, aValue ) ) + aValue >>= aGroupTargetURL; + + if ( !aGroupTargetURL.getLength() ) + return sal_False; // nothing is allowed to be removed + + if ( !maTemplateDirs.getLength() ) + return sal_False; + ::rtl::OUString aGeneralTempPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ]; + + // check that the fs location is in writeble folder and this is not a "My templates" folder + INetURLObject aGroupParentFolder( aGroupTargetURL ); + if ( !aGroupParentFolder.removeSegment() + || !::utl::UCBContentHelper::IsSubPath( aGeneralTempPath, + aGroupParentFolder.GetMainURL( INetURLObject::NO_DECODE ) ) ) + return sal_False; + + // now get the content of the Group + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps( 1 ); + + aProps[0] = OUString::createFromAscii( TARGET_URL ); + + try + { + sal_Bool bHasNonRemovable = sal_False; + sal_Bool bHasShared = sal_False; + + ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY; + xResultSet = aGroup.createCursor( aProps, eInclude ); + + if ( xResultSet.is() ) + { + uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY_THROW ); + uno::Reference< XRow > xRow( xResultSet, UNO_QUERY_THROW ); + + while ( xResultSet->next() ) + { + OUString aTemplTargetURL( xRow->getString( 1 ) ); + OUString aHierURL = xContentAccess->queryContentIdentifierString(); + + if ( ::utl::UCBContentHelper::IsSubPath( aGroupTargetURL, aTemplTargetURL ) ) + { + // this is a user template, and it can be removed + if ( removeContent( aTemplTargetURL ) ) + removeContent( aHierURL ); + else + bHasNonRemovable = sal_True; + } + else + bHasShared = sal_True; + } + + if ( !bHasNonRemovable && !bHasShared ) + { + if ( removeContent( aGroupTargetURL ) + || !::utl::UCBContentHelper::Exists( aGroupTargetURL ) ) + { + removeContent( aGroupURL ); + RemoveUINamesForTemplateDir_Impl( aGeneralTempPath, rGroupName ); + bResult = sal_True; // the operation is successful only if the whole group is removed + } + } + else if ( !bHasNonRemovable ) + { + if ( removeContent( aGroupTargetURL ) + || !::utl::UCBContentHelper::Exists( aGroupTargetURL ) ) + { + RemoveUINamesForTemplateDir_Impl( aGeneralTempPath, rGroupName ); + setProperty( aGroup, aPropName, uno::makeAny( ::rtl::OUString() ) ); + } + } + } + } + catch ( Exception& ) {} + } + + return bResult; +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::renameGroup( const OUString& rOldName, + const OUString& rNewName ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + // create the group url + Content aGroup; + INetURLObject aGroupObj( maRootURL ); + aGroupObj.insertName( rNewName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + OUString aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + // Check, if there is a group with the new name, return false + // if there is one. + if ( Content::create( aGroupURL, maCmdEnv, aGroup ) ) + return sal_False; + + aGroupObj.removeSegment(); + aGroupObj.insertName( rOldName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + // When there is no group with the old name, we can't rename it + if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) ) + return sal_False; + + OUString aGroupTargetURL; + // there is no need to check whether target dir url is in target path, since if the target path is changed + // the target dir url should be already generated new + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + Any aValue; + if ( getProperty( aGroup, aPropName, aValue ) ) + aValue >>= aGroupTargetURL; + + if ( !aGroupTargetURL.getLength() ) + return sal_False; + + if ( !maTemplateDirs.getLength() ) + return sal_False; + ::rtl::OUString aGeneralTempPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ]; + + // check that the fs location is in writeble folder and this is not a "My templates" folder + INetURLObject aGroupParentFolder( aGroupTargetURL ); + if ( !aGroupParentFolder.removeSegment() + || !::utl::UCBContentHelper::IsSubPath( aGeneralTempPath, + aGroupParentFolder.GetMainURL( INetURLObject::NO_DECODE ) ) ) + return sal_False; + + // check that the group can be renamed ( all the contents must be in target location ) + sal_Bool bCanBeRenamed = sal_False; + try + { + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps( 1 ); + + aProps[0] = OUString::createFromAscii( TARGET_URL ); + ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY; + xResultSet = aGroup.createCursor( aProps, eInclude ); + + if ( xResultSet.is() ) + { + uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY_THROW ); + uno::Reference< XRow > xRow( xResultSet, UNO_QUERY_THROW ); + + while ( xResultSet->next() ) + { + OUString aTemplTargetURL( xRow->getString( 1 ) ); + + if ( !::utl::UCBContentHelper::IsSubPath( aGroupTargetURL, aTemplTargetURL ) ) + throw uno::Exception(); + } + + bCanBeRenamed = sal_True; + } + } + catch ( Exception& ) {} + + if ( bCanBeRenamed ) + { + INetURLObject aGroupTargetObj( aGroupTargetURL ); + ::rtl::OUString aFsysName = aGroupTargetObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + + if ( aGroupTargetObj.removeSegment() + && ReplaceUINamesForTemplateDir_Impl( aGroupTargetObj.GetMainURL( INetURLObject::NO_DECODE ), + aFsysName, + rOldName, + rNewName ) ) + { + // rename the group in the hierarchy + OUString aTitleProp( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + Any aTitleValue; + aTitleValue <<= rNewName; + + return setProperty( aGroup, aTitleProp, aTitleValue ); + } + } + + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::storeTemplate( const OUString& rGroupName, + const OUString& rTemplateName, + const uno::Reference< XSTORABLE >& rStorable ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + // Check, wether or not there is a group with this name + // Return false, if there is no group with the given name + Content aGroup, aTemplate, aTargetGroup, aTemplateToRemove; + OUString aGroupURL, aTemplateURL, aTemplateToRemoveTargetURL; + INetURLObject aGroupObj( maRootURL ); + sal_Bool bRemoveOldTemplateContent = sal_False; + ::rtl::OUString sDocServiceName; + + aGroupObj.insertName( rGroupName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) ) + return sal_False; + + ::rtl::OUString aGroupTargetURL; + ::rtl::OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + Any aValue; + if ( getProperty( aGroup, aPropName, aValue ) ) + aValue >>= aGroupTargetURL; + + + // Check, if there's a template with the given name in this group + // the target template should be overwritten if it is imported by user + // in case the template is installed by office installation of by an add-in + // it can not be replaced + aGroupObj.insertName( rTemplateName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( Content::create( aTemplateURL, maCmdEnv, aTemplateToRemove ) ) + { + OUString aTargetTemplPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + + bRemoveOldTemplateContent = sal_True; + if ( getProperty( aTemplateToRemove, aTargetTemplPropName, aValue ) ) + aValue >>= aTemplateToRemoveTargetURL; + + if ( !aGroupTargetURL.getLength() || !maTemplateDirs.getLength() + || (aTemplateToRemoveTargetURL.getLength() && !::utl::UCBContentHelper::IsSubPath( maTemplateDirs[ maTemplateDirs.getLength() - 1 ], aTemplateToRemoveTargetURL )) ) + return sal_False; // it is not allowed to remove the template + } + + try + { + uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); + if ( !xFactory.is() ) + throw uno::RuntimeException(); + + // get document service name + uno::Reference< frame::XModuleManager > xModuleManager( + xFactory->createInstance( + ::rtl::OUString::createFromAscii( "com.sun.star.frame.ModuleManager" ) ), + uno::UNO_QUERY_THROW ); + sDocServiceName = xModuleManager->identify( uno::Reference< uno::XInterface >( rStorable, uno::UNO_QUERY ) ); + if ( !sDocServiceName.getLength() ) + throw uno::RuntimeException(); + + // get the actual filter name + ::rtl::OUString aFilterName; + + uno::Reference< lang::XMultiServiceFactory > xConfigProvider( + xFactory->createInstance( + ::rtl::OUString::createFromAscii( "com.sun.star.configuration.ConfigurationProvider" ) ), + uno::UNO_QUERY_THROW ); + + uno::Sequence< uno::Any > aArgs( 1 ); + beans::PropertyValue aPathProp; + aPathProp.Name = ::rtl::OUString::createFromAscii( "nodepath" ); + aPathProp.Value <<= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Setup/Office/Factories/" ) ); + aArgs[0] <<= aPathProp; + + uno::Reference< container::XNameAccess > xSOFConfig( + xConfigProvider->createInstanceWithArguments( + ::rtl::OUString::createFromAscii( "com.sun.star.configuration.ConfigurationAccess" ), + aArgs ), + uno::UNO_QUERY_THROW ); + + uno::Reference< container::XNameAccess > xApplConfig; + xSOFConfig->getByName( sDocServiceName ) >>= xApplConfig; + if ( !xApplConfig.is() ) + throw uno::RuntimeException(); + + xApplConfig->getByName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ooSetupFactoryActualTemplateFilter" ) ) ) >>= aFilterName; + if ( !aFilterName.getLength() ) + throw uno::RuntimeException(); + + // find the related type name + ::rtl::OUString aTypeName; + uno::Reference< container::XNameAccess > xFilterFactory( + xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ), + uno::UNO_QUERY_THROW ); + + uno::Sequence< beans::PropertyValue > aFilterData; + xFilterFactory->getByName( aFilterName ) >>= aFilterData; + for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ ) + if ( aFilterData[nInd].Name.equalsAscii( "Type" ) ) + aFilterData[nInd].Value >>= aTypeName; + + if ( !aTypeName.getLength() ) + throw uno::RuntimeException(); + + // find the mediatype and extension + uno::Reference< container::XNameAccess > xTypeDetection = + mxType.is() ? + uno::Reference< container::XNameAccess >( mxType, uno::UNO_QUERY_THROW ) : + uno::Reference< container::XNameAccess >( + xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.TypeDetection" ) ), + uno::UNO_QUERY_THROW ); + + SequenceAsHashMap aTypeProps( xTypeDetection->getByName( aTypeName ) ); + uno::Sequence< ::rtl::OUString > aAllExt = + aTypeProps.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "Extensions" ), Sequence< ::rtl::OUString >() ); + if ( !aAllExt.getLength() ) + throw uno::RuntimeException(); + + ::rtl::OUString aMediaType = aTypeProps.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "MediaType" ), ::rtl::OUString() ); + ::rtl::OUString aExt = aAllExt[0]; + + if ( !aMediaType.getLength() || !aExt.getLength() ) + throw uno::RuntimeException(); + + // construct destination url + if ( !aGroupTargetURL.getLength() ) + { + aGroupTargetURL = CreateNewGroupFsys( rGroupName, aGroup ); + + if ( !aGroupTargetURL.getLength() ) + throw uno::RuntimeException(); + } + + ::rtl::OUString aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aGroupTargetURL, rTemplateName, aExt ); + if ( !aNewTemplateTargetURL.getLength() ) + { + aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aGroupTargetURL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserTemplate" ) ), aExt ); + + if ( !aNewTemplateTargetURL.getLength() ) + throw uno::RuntimeException(); + } + + // store template + uno::Sequence< PropertyValue > aStoreArgs( 2 ); + aStoreArgs[0].Name = ::rtl::OUString::createFromAscii( "FilterName" ); + aStoreArgs[0].Value <<= aFilterName; + aStoreArgs[1].Name = ::rtl::OUString::createFromAscii( "DocumentTitle" ); + aStoreArgs[1].Value <<= rTemplateName; + + ::rtl::OUString aCurrentDocumentURL = rStorable->getLocation(); + if( !::utl::UCBContentHelper::EqualURLs( aNewTemplateTargetURL, rStorable->getLocation() )) + rStorable->storeToURL( aNewTemplateTargetURL, aStoreArgs ); + else + rStorable->store(); + + // the storing was successful, now the old template with the same name can be removed if it existed + if ( aTemplateToRemoveTargetURL.getLength() ) + { + removeContent( aTemplateToRemoveTargetURL ); + + /* + * pb: #i79496# + * if the old template was the standard template + * it is necessary to change the standard template with the new file name + */ + String sStdTmplFile = SfxObjectFactory::GetStandardTemplate( sDocServiceName ); + if ( INetURLObject( sStdTmplFile ) == INetURLObject( aTemplateToRemoveTargetURL ) ) + { + SfxObjectFactory::SetStandardTemplate( sDocServiceName, aNewTemplateTargetURL ); + } + } + + if ( bRemoveOldTemplateContent ) + removeContent( aTemplateToRemove ); + + // add the template to hierarchy + return addEntry( aGroup, rTemplateName, aNewTemplateTargetURL, aMediaType ); + } + catch( Exception& ) + { + // the template was not stored + return sal_False; + } +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::addTemplate( const OUString& rGroupName, + const OUString& rTemplateName, + const OUString& rSourceURL ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + // Check, wether or not there is a group with this name + // Return false, if there is no group with the given name + Content aGroup, aTemplate, aTargetGroup; + OUString aGroupURL, aTemplateURL; + INetURLObject aGroupObj( maRootURL ); + + aGroupObj.insertName( rGroupName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) ) + return sal_False; + + // Check, if there's a template with the given name in this group + // Return false, if there already is a template + aGroupObj.insertName( rTemplateName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( Content::create( aTemplateURL, maCmdEnv, aTemplate ) ) + return sal_False; + + // get the target url of the group + OUString aTargetURL; + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + Any aValue; + + if ( getProperty( aGroup, aPropName, aValue ) ) + aValue >>= aTargetURL; + + if ( !aTargetURL.getLength() ) + { + aTargetURL = CreateNewGroupFsys( rGroupName, aGroup ); + + if ( !aTargetURL.getLength() ) + return sal_False; + } + + // Get the content type + OUString aTitle, aType, aTargetURL2, aFullName; + + // only StarOffice documents are acceptable + sal_Bool bDocHasTitle = sal_False; + if( !getTitleFromURL( rSourceURL, aTitle, aType, bDocHasTitle ) ) + return sal_False; + + INetURLObject aSourceObj( rSourceURL ); + if ( rTemplateName.equals( aTitle ) ) + { + ///////////////////////////////////////////////////// + // addTemplate will sometimes be called just to add an entry in the + // hierarchy; the target URL and the source URL will be the same in + // this scenario + // TODO/LATER: get rid of this old hack + + INetURLObject aTargetObj( aTargetURL ); + + aTargetObj.insertName( rTemplateName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aTargetObj.setExtension( aSourceObj.getExtension() ); + + aTargetURL2 = aTargetObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( aTargetURL2 == rSourceURL ) + return addEntry( aGroup, rTemplateName, aTargetURL2, aType ); + } + + ///////////////////////////////////////////////////// + // copy the template into the new group (targeturl) + + INetURLObject aTmpURL( aSourceObj ); + aTmpURL.CutExtension(); + ::rtl::OUString aPattern = aTmpURL.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + + ::rtl::OUString aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aTargetURL, aPattern, aSourceObj.getExtension() ); + INetURLObject aNewTemplateTargetObj( aNewTemplateTargetURL ); + ::rtl::OUString aNewTemplateTargetName = aNewTemplateTargetObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + if ( !aNewTemplateTargetURL.getLength() || !aNewTemplateTargetName.getLength() ) + return sal_False; + + // get access to source file + Content aSourceContent; + uno::Reference < ucb::XCommandEnvironment > xEnv; + INetURLObject aSourceURL( rSourceURL ); + if( ! Content::create( aSourceURL.GetMainURL( INetURLObject::NO_DECODE ), xEnv, aSourceContent ) ) + return sal_False; + + if( ! Content::create( aTargetURL, xEnv, aTargetGroup ) ) + return sal_False; + + // transfer source file + try + { + if( ! aTargetGroup.transferContent( aSourceContent, + InsertOperation_COPY, + aNewTemplateTargetName, + NameClash::OVERWRITE ) ) + return sal_False; + + // allow to edit the added template + Content aResultContent; + if ( Content::create( aNewTemplateTargetURL, xEnv, aResultContent ) ) + { + ::rtl::OUString aPropertyName( RTL_CONSTASCII_USTRINGPARAM( "IsReadOnly" ) ); + uno::Any aProperty; + sal_Bool bReadOnly = sal_False; + if ( getProperty( aResultContent, aPropertyName, aProperty ) && ( aProperty >>= bReadOnly ) && bReadOnly ) + setProperty( aResultContent, aPropertyName, uno::makeAny( (sal_Bool)sal_False ) ); + } + } + catch ( ContentCreationException& ) + { return sal_False; } + catch ( Exception& ) + { return sal_False; } + + + // either the document has title and it is the same as requested, or we have to set it + sal_Bool bCorrectTitle = ( bDocHasTitle && aTitle.equals( rTemplateName ) ); + if ( !bCorrectTitle ) + { + if ( !bDocHasTitle ) + { + INetURLObject aNewTmpObj( aNewTemplateTargetObj ); + aNewTmpObj.CutExtension(); + bCorrectTitle = ( aNewTmpObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ).equals( rTemplateName ) ); + } + + if ( !bCorrectTitle ) + bCorrectTitle = setTitleForURL( aNewTemplateTargetURL, rTemplateName ); + } + + if ( bCorrectTitle ) + { + // create a new entry in the hierarchy + return addEntry( aGroup, rTemplateName, aNewTemplateTargetURL, aType ); + } + + // TODO/LATER: The user could be notified here that the renaming has failed + // create a new entry in the hierarchy + addEntry( aGroup, aTitle, aNewTemplateTargetURL, aType ); + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::removeTemplate( const OUString& rGroupName, + const OUString& rTemplateName ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + // Check, wether or not there is a group with this name + // Return false, if there is no group with the given name + Content aGroup, aTemplate; + OUString aGroupURL, aTemplateURL; + INetURLObject aGroupObj( maRootURL ); + + aGroupObj.insertName( rGroupName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) ) + return sal_False; + + // Check, if there's a template with the given name in this group + // Return false, if there is no template + aGroupObj.insertName( rTemplateName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( !Content::create( aTemplateURL, maCmdEnv, aTemplate ) ) + return sal_False; + + // get the target URL from the template + OUString aTargetURL; + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + Any aValue; + + if ( getProperty( aTemplate, aPropName, aValue ) ) + aValue >>= aTargetURL; + + // delete the target template + if ( aTargetURL.getLength() ) + { + if ( !maTemplateDirs.getLength() + || !::utl::UCBContentHelper::IsSubPath( maTemplateDirs[ maTemplateDirs.getLength() - 1 ], aTargetURL ) ) + return sal_False; + + removeContent( aTargetURL ); + } + + // delete the template entry + return removeContent( aTemplate ); +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::renameTemplate( const OUString& rGroupName, + const OUString& rOldName, + const OUString& rNewName ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + // Check, wether or not there is a group with this name + // Return false, if there is no group with the given name + Content aGroup, aTemplate; + OUString aGroupURL, aTemplateURL; + INetURLObject aGroupObj( maRootURL ); + + aGroupObj.insertName( rGroupName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) ) + return sal_False; + + // Check, if there's a template with the new name in this group + // Return false, if there is one + aGroupObj.insertName( rNewName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( Content::create( aTemplateURL, maCmdEnv, aTemplate ) ) + return sal_False; + + // Check, if there's a template with the old name in this group + // Return false, if there is no template + aGroupObj.removeSegment(); + aGroupObj.insertName( rOldName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( !Content::create( aTemplateURL, maCmdEnv, aTemplate ) ) + return sal_False; + + OUString aTemplateTargetURL; + OUString aTargetProp( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + Any aTargetValue; + + if ( getProperty( aTemplate, aTargetProp, aTargetValue ) ) + aTargetValue >>= aTemplateTargetURL; + + if ( !setTitleForURL( aTemplateTargetURL, rNewName ) ) + return sal_False; + + // rename the template entry in the cache + OUString aTitleProp( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + Any aTitleValue; + aTitleValue <<= rNewName; + + return setProperty( aTemplate, aTitleProp, aTitleValue ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +SFX_IMPL_XSERVICEINFO( SfxDocTplService, TEMPLATE_SERVICE_NAME, TEMPLATE_IMPLEMENTATION_NAME ) +SFX_IMPL_SINGLEFACTORY( SfxDocTplService ) + +//----------------------------------------------------------------------------- +SfxDocTplService::SfxDocTplService( const uno::Reference< XMultiServiceFactory >& xFactory ) +{ + pImp = new SfxDocTplService_Impl( xFactory ); +} + +//----------------------------------------------------------------------------- + +SfxDocTplService::~SfxDocTplService() +{ + delete pImp; +} + +//----------------------------------------------------------------------------- +//--- XLocalizable --- +//----------------------------------------------------------------------------- + +Locale SAL_CALL SfxDocTplService::getLocale() + throw( RUNTIMEEXCEPTION ) +{ + return pImp->getLocale(); +} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxDocTplService::setLocale( const Locale & rLocale ) + throw( RUNTIMEEXCEPTION ) +{ + pImp->setLocale( rLocale ); +} + +//----------------------------------------------------------------------------- +//--- XDocumentTemplates --- +//----------------------------------------------------------------------------- +uno::Reference< XCONTENT > SAL_CALL SfxDocTplService::getContent() + throw( RUNTIMEEXCEPTION ) +{ + if ( pImp->init() ) + return pImp->getContent().get(); + else + return NULL; +} + +//----------------------------------------------------------------------------- +sal_Bool SAL_CALL SfxDocTplService::storeTemplate( const OUString& GroupName, + const OUString& TemplateName, + const uno::Reference< XSTORABLE >& Storable ) + throw( RUNTIMEEXCEPTION ) +{ + if ( pImp->init() ) + return pImp->storeTemplate( GroupName, TemplateName, Storable ); + else + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SAL_CALL SfxDocTplService::addTemplate( const OUString& rGroupName, + const OUString& rTemplateName, + const OUString& rSourceURL ) + throw( RUNTIMEEXCEPTION ) +{ + if ( pImp->init() ) + return pImp->addTemplate( rGroupName, rTemplateName, rSourceURL ); + else + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SAL_CALL SfxDocTplService::removeTemplate( const OUString& rGroupName, + const OUString& rTemplateName ) + throw( RUNTIMEEXCEPTION ) +{ + if ( pImp->init() ) + return pImp->removeTemplate( rGroupName, rTemplateName ); + else + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SAL_CALL SfxDocTplService::renameTemplate( const OUString& rGroupName, + const OUString& rOldName, + const OUString& rNewName ) + throw( RUNTIMEEXCEPTION ) +{ + if ( rOldName == rNewName ) + return sal_True; + + if ( pImp->init() ) + return pImp->renameTemplate( rGroupName, rOldName, rNewName ); + else + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SAL_CALL SfxDocTplService::addGroup( const OUString& rGroupName ) + throw( RUNTIMEEXCEPTION ) +{ + if ( pImp->init() ) + return pImp->addGroup( rGroupName ); + else + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SAL_CALL SfxDocTplService::removeGroup( const OUString& rGroupName ) + throw( RUNTIMEEXCEPTION ) +{ + if ( pImp->init() ) + return pImp->removeGroup( rGroupName ); + else + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SAL_CALL SfxDocTplService::renameGroup( const OUString& rOldName, + const OUString& rNewName ) + throw( RUNTIMEEXCEPTION ) +{ + if ( rOldName == rNewName ) + return sal_True; + + if ( pImp->init() ) + return pImp->renameGroup( rOldName, rNewName ); + else + return sal_False; +} + +//----------------------------------------------------------------------------- +void SAL_CALL SfxDocTplService::update() + throw( RUNTIMEEXCEPTION ) +{ + if ( pImp->init() ) + pImp->update( sal_True ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//------------------------------------------------------------------------ + +Updater_Impl::Updater_Impl( SfxDocTplService_Impl* pTemplates ) +{ + mpDocTemplates = pTemplates; +} + +//------------------------------------------------------------------------ +Updater_Impl::~Updater_Impl() +{ +} + +//------------------------------------------------------------------------ +void SAL_CALL Updater_Impl::run() +{ + mpDocTemplates->doUpdate(); +} + +//------------------------------------------------------------------------ +void SAL_CALL Updater_Impl::onTerminated() +{ + mpDocTemplates->finished(); + delete this; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +WaitWindow_Impl::WaitWindow_Impl() + : WorkWindow( NULL, WB_BORDER | WB_3DLOOK ) +{ + Rectangle aRect = Rectangle( 0, 0, 300, 30000 ); + _nTextStyle = TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE; + _aText = String( SfxResId( RID_CNT_STR_WAITING ) ); + _aRect = GetTextRect( aRect, _aText, _nTextStyle ); + aRect = _aRect; + aRect.Right() += 2*X_OFFSET; + aRect.Bottom() += 2*Y_OFFSET; + _aRect.SetPos( Point( X_OFFSET, Y_OFFSET ) ); + SetOutputSizePixel( aRect.GetSize() ); + Show(); + Update(); + Flush(); +} + +//----------------------------------------------------------------------------- +WaitWindow_Impl::~WaitWindow_Impl() +{ + Hide(); +} + +//----------------------------------------------------------------------------- +void WaitWindow_Impl::Paint( const Rectangle& /*rRect*/ ) +{ + DrawText( _aRect, _aText, _nTextStyle ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::addHierGroup( GroupList_Impl& rList, + const OUString& rTitle, + const OUString& rOwnURL ) +{ + // now get the content of the Group + Content aContent; + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps(3); + + aProps[0] = OUString::createFromAscii( TITLE ); + aProps[1] = OUString::createFromAscii( TARGET_URL ); + aProps[2] = OUString::createFromAscii( PROPERTY_TYPE ); + + try + { + aContent = Content( rOwnURL, maCmdEnv ); + ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY; + xResultSet = aContent.createCursor( aProps, eInclude ); + } + catch ( ContentCreationException& ) + { + DBG_ERRORFILE( "addHierGroup: ContentCreationException" ); + } + catch ( Exception& ) {} + + if ( xResultSet.is() ) + { + GroupData_Impl *pGroup = new GroupData_Impl( rTitle ); + pGroup->setHierarchy( sal_True ); + pGroup->setHierarchyURL( rOwnURL ); + rList.Insert( pGroup ); + + uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + uno::Reference< XRow > xRow( xResultSet, UNO_QUERY ); + + try + { + while ( xResultSet->next() ) + { + BOOL bUpdateType = sal_False; + DocTemplates_EntryData_Impl *pData; + + OUString aTitle( xRow->getString( 1 ) ); + OUString aTargetDir( xRow->getString( 2 ) ); + OUString aType( xRow->getString( 3 ) ); + OUString aHierURL = xContentAccess->queryContentIdentifierString(); + + if ( !aType.getLength() ) + { + OUString aTmpTitle; + + sal_Bool bDocHasTitle = sal_False; + if( !getTitleFromURL( aTargetDir, aTmpTitle, aType, bDocHasTitle ) ) + { + DBG_ERRORFILE( "addHierGroup(): template of alien format" ); + continue; + } + + if ( aType.getLength() ) + bUpdateType = sal_True; + } + + pData = pGroup->addEntry( aTitle, aTargetDir, aType, aHierURL ); + pData->setUpdateType( bUpdateType ); + } + } + catch ( Exception& ) {} + } +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::addFsysGroup( GroupList_Impl& rList, + const OUString& rTitle, + const OUString& rUITitle, + const OUString& rOwnURL, + sal_Bool bWriteableGroup ) +{ + ::rtl::OUString aTitle; + + if ( !rUITitle.getLength() ) + { + // reserved FS names that should not be used + if ( rTitle.compareToAscii( "wizard" ) == 0 ) + return; + else if ( rTitle.compareToAscii( "internal" ) == 0 ) + return; + + aTitle = getLongName( rTitle ); + } + else + aTitle = rUITitle; + + if ( !aTitle.getLength() ) + return; + + GroupData_Impl *pGroup = rList.First(); + + while ( pGroup && pGroup->getTitle() != aTitle ) + pGroup = rList.Next(); + + if ( !pGroup ) + { + pGroup = new GroupData_Impl( aTitle ); + rList.Insert( pGroup ); + } + + if ( bWriteableGroup ) + pGroup->setTargetURL( rOwnURL ); + + pGroup->setInUse(); + + // now get the content of the Group + Content aContent; + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps(1); + aProps[0] = OUString::createFromAscii( TITLE ); + + try + { + // this method is only used during checking of the available template-folders + // that should happen quietly + uno::Reference< XCommandEnvironment > aQuietEnv; + aContent = Content( rOwnURL, aQuietEnv ); + ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY; + xResultSet = aContent.createCursor( aProps, eInclude ); + } + catch ( Exception& ) {} + + if ( xResultSet.is() ) + { + uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + uno::Reference< XRow > xRow( xResultSet, UNO_QUERY ); + + try + { + while ( xResultSet->next() ) + { + OUString aChildTitle( xRow->getString( 1 ) ); + OUString aTargetURL = xContentAccess->queryContentIdentifierString(); + OUString aType; + OUString aHierURL; + + if ( aChildTitle.compareToAscii( "sfx.tlx" ) == 0 + || aChildTitle.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "groupuinames.xml" ) ) ) + continue; + + // only StarOffice templates are accepted + sal_Bool bDocHasTitle = sal_False; + if( !getTitleFromURL( aTargetURL, aChildTitle, aType, bDocHasTitle ) ) + continue; + + pGroup->addEntry( aChildTitle, aTargetURL, aType, aHierURL ); + } + } + catch ( Exception& ) {} + } +} + +// ----------------------------------------------------------------------- +void SfxDocTplService_Impl::createFromContent( GroupList_Impl& rList, + Content &rContent, + sal_Bool bHierarchy, + sal_Bool bWriteableContent ) +{ + OUString aTargetURL = rContent.get()->getIdentifier()->getContentIdentifier(); + + // when scanning the file system, we have to add the 'standard' group, too + if ( ! bHierarchy ) + { + OUString aUIStdTitle = getLongName( OUString( RTL_CONSTASCII_USTRINGPARAM( STANDARD_FOLDER ) ) ); + addFsysGroup( rList, ::rtl::OUString(), aUIStdTitle, aTargetURL, bWriteableContent ); + } + + // search for predefined UI names + INetURLObject aLayerObj( aTargetURL ); + + // TODO/LATER: Use hashmap in future + uno::Sequence< beans::StringPair > aUINames; + if ( !bHierarchy ) + aUINames = ReadUINamesForTemplateDir_Impl( aLayerObj.GetMainURL( INetURLObject::NO_DECODE ) ); + + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps(1); + aProps[0] = OUString::createFromAscii( TITLE ); + + try + { + ResultSetInclude eInclude = INCLUDE_FOLDERS_ONLY; + xResultSet = rContent.createCursor( aProps, eInclude ); + } + catch ( Exception& ) {} + + if ( xResultSet.is() ) + { + uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + uno::Reference< XRow > xRow( xResultSet, UNO_QUERY ); + + try + { + while ( xResultSet->next() ) + { + // TODO/LATER: clarify the encoding of the Title + OUString aTitle( xRow->getString( 1 ) ); + OUString aTargetSubfolderURL( xContentAccess->queryContentIdentifierString() ); + + if ( bHierarchy ) + addHierGroup( rList, aTitle, aTargetSubfolderURL ); + else + { + ::rtl::OUString aUITitle; + for ( sal_Int32 nInd = 0; nInd < aUINames.getLength(); nInd++ ) + if ( aUINames[nInd].First.equals( aTitle ) ) + { + aUITitle = aUINames[nInd].Second; + break; + } + + addFsysGroup( rList, aTitle, aUITitle, aTargetSubfolderURL, bWriteableContent ); + } + } + } + catch ( Exception& ) {} + } +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::removeFromHierarchy( DocTemplates_EntryData_Impl *pData ) +{ + Content aTemplate; + + if ( Content::create( pData->getHierarchyURL(), maCmdEnv, aTemplate ) ) + { + removeContent( aTemplate ); + } +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::addToHierarchy( GroupData_Impl *pGroup, + DocTemplates_EntryData_Impl *pData ) +{ + Content aGroup, aTemplate; + + if ( ! Content::create( pGroup->getHierarchyURL(), maCmdEnv, aGroup ) ) + return; + + // Check, if there's a template with the given name in this group + // Return if there is already a template + INetURLObject aGroupObj( pGroup->getHierarchyURL() ); + + aGroupObj.insertName( pData->getTitle(), false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + OUString aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( Content::create( aTemplateURL, maCmdEnv, aTemplate ) ) + return; + + addEntry( aGroup, pData->getTitle(), + pData->getTargetURL(), + pData->getType() ); +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::updateData( DocTemplates_EntryData_Impl *pData ) +{ + Content aTemplate; + + if ( ! Content::create( pData->getHierarchyURL(), maCmdEnv, aTemplate ) ) + return; + + OUString aPropName; + + if ( pData->getUpdateType() ) + { + aPropName = OUString( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_TYPE ) ); + setProperty( aTemplate, aPropName, makeAny( pData->getType() ) ); + } + + if ( pData->getUpdateLink() ) + { + aPropName = OUString( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + setProperty( aTemplate, aPropName, makeAny( pData->getTargetURL() ) ); + } +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::addGroupToHierarchy( GroupData_Impl *pGroup ) +{ + OUString aAdditionalProp( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + Content aGroup; + + INetURLObject aNewGroupObj( maRootURL ); + aNewGroupObj.insertName( pGroup->getTitle(), false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + OUString aNewGroupURL = aNewGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( createFolder( aNewGroupURL, sal_False, sal_False, aGroup ) ) + { + setProperty( aGroup, aAdditionalProp, makeAny( pGroup->getTargetURL() ) ); + pGroup->setHierarchyURL( aNewGroupURL ); + + ULONG nCount = pGroup->count(); + for ( ULONG i=0; i<nCount; i++ ) + { + DocTemplates_EntryData_Impl *pData = pGroup->getEntry( i ); + addToHierarchy( pGroup, pData ); // add entry to hierarchy + } + } +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::removeFromHierarchy( GroupData_Impl *pGroup ) +{ + Content aGroup; + + if ( Content::create( pGroup->getHierarchyURL(), maCmdEnv, aGroup ) ) + { + removeContent( aGroup ); + } +} + +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +GroupData_Impl::GroupData_Impl( const OUString& rTitle ) +{ + maTitle = rTitle; + mbInUse = sal_False; + mbInHierarchy = sal_False; +} + +// ----------------------------------------------------------------------- +GroupData_Impl::~GroupData_Impl() +{ + DocTemplates_EntryData_Impl *pData = maEntries.First(); + while ( pData ) + { + delete pData; + pData = maEntries.Next(); + } +} + +// ----------------------------------------------------------------------- +DocTemplates_EntryData_Impl* GroupData_Impl::addEntry( const OUString& rTitle, + const OUString& rTargetURL, + const OUString& rType, + const OUString& rHierURL ) +{ + DocTemplates_EntryData_Impl *pData = maEntries.First(); + + while ( pData && pData->getTitle() != rTitle ) + pData = maEntries.Next(); + + if ( !pData ) + { + pData = new DocTemplates_EntryData_Impl( rTitle ); + pData->setTargetURL( rTargetURL ); + pData->setType( rType ); + if ( rHierURL.getLength() ) + { + pData->setHierarchyURL( rHierURL ); + pData->setHierarchy( sal_True ); + } + maEntries.Insert( pData ); + } + else + { + if ( rHierURL.getLength() ) + { + pData->setHierarchyURL( rHierURL ); + pData->setHierarchy( sal_True ); + } + + if ( pData->getInHierarchy() ) + pData->setInUse(); + + if ( rTargetURL != pData->getTargetURL() ) + { + pData->setTargetURL( rTargetURL ); + pData->setUpdateLink( sal_True ); + } + } + + return pData; +} + +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +DocTemplates_EntryData_Impl::DocTemplates_EntryData_Impl( const OUString& rTitle ) +{ + maTitle = rTitle; + mbInUse = sal_False; + mbInHierarchy = sal_False; + mbUpdateType = sal_False; + mbUpdateLink = sal_False; +} + +// ----------------------------------------------------------------------- +SfxURLRelocator_Impl::SfxURLRelocator_Impl( uno::Reference< XMultiServiceFactory > xFactory ) +: mxFactory( xFactory ) +{ +} + +// ----------------------------------------------------------------------- +SfxURLRelocator_Impl::~SfxURLRelocator_Impl() +{ +} + +// ----------------------------------------------------------------------- +void SfxURLRelocator_Impl::initOfficeInstDirs() +{ + if ( !mxOfficeInstDirs.is() ) + { + osl::MutexGuard aGuard( maMutex ); + if ( !mxOfficeInstDirs.is() ) + { + OSL_ENSURE( mxFactory.is(), "No service manager!" ); + + uno::Reference< XComponentContext > xCtx; + uno::Reference< XPropertySet > xPropSet( mxFactory, UNO_QUERY ); + if ( xPropSet.is() ) + { + xPropSet->getPropertyValue( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) ) + >>= xCtx; + } + + OSL_ENSURE( xCtx.is(), + "Unable to obtain component context from " + "service manager!" ); + + if ( xCtx.is() ) + { + xCtx->getValueByName( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "/singletons/" + "com.sun.star.util.theOfficeInstallationDirectories" ) ) ) + >>= mxOfficeInstDirs; + } + + OSL_ENSURE( mxOfficeInstDirs.is(), + "Unable to obtain office installation directory " + "singleton!" ); + } + } +} + +// ----------------------------------------------------------------------- +void SfxURLRelocator_Impl::makeRelocatableURL( rtl::OUString & rURL ) +{ + if ( rURL.getLength() > 0 ) + { + initOfficeInstDirs(); + rURL = mxOfficeInstDirs->makeRelocatableURL( rURL ); + } +} + +// ----------------------------------------------------------------------- +void SfxURLRelocator_Impl::makeAbsoluteURL( rtl::OUString & rURL ) +{ + if ( rURL.getLength() > 0 ) + { + initOfficeInstDirs(); + rURL = mxOfficeInstDirs->makeAbsoluteURL( rURL ); + } +} + + diff --git a/sfx2/source/doc/doctemplateslocal.cxx b/sfx2/source/doc/doctemplateslocal.cxx new file mode 100644 index 000000000000..277199d30051 --- /dev/null +++ b/sfx2/source/doc/doctemplateslocal.cxx @@ -0,0 +1,263 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_ +#include <com/sun/star/beans/StringPair.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#endif +#ifndef _COM_SUN_STAR_IO_XACTIVEDATASOURCE_HPP +#include <com/sun/star/io/XActiveDataSource.hpp> +#endif +#ifndef _COM_SUN_STAR_XML_SAX_XPARSER_HPP +#include <com/sun/star/xml/sax/XParser.hpp> +#endif +#ifndef _COM_SUN_STAR_XML_SAX_XDOCUMENTHANDLER_HPP +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_ILLEGALARGUMENTEXCEPTION_HPP +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#endif + +#include <comphelper/attributelist.hxx> + +#include "doctemplateslocal.hxx" + +using namespace ::com::sun::star; + +// ----------------------------------- +uno::Sequence< beans::StringPair > DocTemplLocaleHelper::ReadGroupLocalizationSequence( const uno::Reference< io::XInputStream >& xInStream, const uno::Reference< lang::XMultiServiceFactory > xFactory ) + throw( uno::Exception ) +{ + ::rtl::OUString aStringID = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "groupuinames.xml" ) ); + return ReadLocalizationSequence_Impl( xInStream, aStringID, xFactory ); +} + +// ----------------------------------- +void SAL_CALL DocTemplLocaleHelper::WriteGroupLocalizationSequence( const uno::Reference< io::XOutputStream >& xOutStream, const uno::Sequence< beans::StringPair >& aSequence, const uno::Reference< lang::XMultiServiceFactory > xFactory ) + throw( uno::Exception ) +{ + if ( !xOutStream.is() ) + throw uno::RuntimeException(); + + uno::Reference< io::XActiveDataSource > xWriterSource( + xFactory->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.sax.Writer" ) ) ), + uno::UNO_QUERY_THROW ); + uno::Reference< xml::sax::XDocumentHandler > xWriterHandler( xWriterSource, uno::UNO_QUERY_THROW ); + + xWriterSource->setOutputStream( xOutStream ); + + ::rtl::OUString aGroupListElement( RTL_CONSTASCII_USTRINGPARAM( "groupuinames:template-group-list" ) ); + ::rtl::OUString aGroupElement( RTL_CONSTASCII_USTRINGPARAM( "groupuinames:template-group" ) ); + ::rtl::OUString aNameAttr( RTL_CONSTASCII_USTRINGPARAM( "groupuinames:name" ) ); + ::rtl::OUString aUINameAttr( RTL_CONSTASCII_USTRINGPARAM( "groupuinames:default-ui-name" ) ); + ::rtl::OUString aCDATAString( RTL_CONSTASCII_USTRINGPARAM ( "CDATA" ) ); + ::rtl::OUString aWhiteSpace( RTL_CONSTASCII_USTRINGPARAM ( " " ) ); + + // write the namespace + ::comphelper::AttributeList* pRootAttrList = new ::comphelper::AttributeList; + uno::Reference< xml::sax::XAttributeList > xRootAttrList( pRootAttrList ); + pRootAttrList->AddAttribute( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "xmlns" ) ), + aCDATAString, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "http://openoffice.org/2006/groupuinames" ) ) ); + + xWriterHandler->startDocument(); + xWriterHandler->startElement( aGroupListElement, xRootAttrList ); + + for ( sal_Int32 nInd = 0; nInd < aSequence.getLength(); nInd++ ) + { + ::comphelper::AttributeList *pAttrList = new ::comphelper::AttributeList; + uno::Reference< xml::sax::XAttributeList > xAttrList( pAttrList ); + pAttrList->AddAttribute( aNameAttr, aCDATAString, aSequence[nInd].First ); + pAttrList->AddAttribute( aUINameAttr, aCDATAString, aSequence[nInd].Second ); + + xWriterHandler->startElement( aGroupElement, xAttrList ); + xWriterHandler->ignorableWhitespace( aWhiteSpace ); + xWriterHandler->endElement( aGroupElement ); + } + + xWriterHandler->ignorableWhitespace( aWhiteSpace ); + xWriterHandler->endElement( aGroupListElement ); + xWriterHandler->endDocument(); +} + +// ================================================================================== + +// ----------------------------------- +uno::Sequence< beans::StringPair > SAL_CALL DocTemplLocaleHelper::ReadLocalizationSequence_Impl( const uno::Reference< io::XInputStream >& xInStream, const ::rtl::OUString& aStringID, const uno::Reference< lang::XMultiServiceFactory > xFactory ) + throw( uno::Exception ) +{ + if ( !xFactory.is() || !xInStream.is() ) + throw uno::RuntimeException(); + + uno::Sequence< beans::StringPair > aResult; + + uno::Reference< xml::sax::XParser > xParser( xFactory->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.sax.Parser" ) ) ), uno::UNO_QUERY_THROW ); + + DocTemplLocaleHelper* pHelper = new DocTemplLocaleHelper(); + uno::Reference< xml::sax::XDocumentHandler > xHelper( static_cast< xml::sax::XDocumentHandler* >( pHelper ) ); + xml::sax::InputSource aParserInput; + aParserInput.aInputStream = xInStream; + aParserInput.sSystemId = aStringID; + xParser->setDocumentHandler( xHelper ); + xParser->parseStream( aParserInput ); + xParser->setDocumentHandler( uno::Reference < xml::sax::XDocumentHandler > () ); + + return pHelper->GetParsingResult(); +} + +// ----------------------------------- +DocTemplLocaleHelper::DocTemplLocaleHelper() +: m_aGroupListElement( RTL_CONSTASCII_USTRINGPARAM( "groupuinames:template-group-list" ) ) +, m_aGroupElement( RTL_CONSTASCII_USTRINGPARAM( "groupuinames:template-group" ) ) +, m_aNameAttr( RTL_CONSTASCII_USTRINGPARAM( "groupuinames:name" ) ) +, m_aUINameAttr( RTL_CONSTASCII_USTRINGPARAM( "groupuinames:default-ui-name" ) ) +{ +} + +// ----------------------------------- +DocTemplLocaleHelper::~DocTemplLocaleHelper() +{ +} + +// ----------------------------------- +uno::Sequence< beans::StringPair > DocTemplLocaleHelper::GetParsingResult() +{ + if ( m_aElementsSeq.getLength() ) + throw uno::RuntimeException(); // the parsing has still not finished! + + return m_aResultSeq; +} + +// ----------------------------------- +void SAL_CALL DocTemplLocaleHelper::startDocument() + throw(xml::sax::SAXException, uno::RuntimeException) +{ +} + +// ----------------------------------- +void SAL_CALL DocTemplLocaleHelper::endDocument() + throw(xml::sax::SAXException, uno::RuntimeException) +{ +} + +// ----------------------------------- +void SAL_CALL DocTemplLocaleHelper::startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) + throw( xml::sax::SAXException, uno::RuntimeException ) +{ + if ( aName == m_aGroupListElement ) + { + sal_Int32 nNewLength = m_aElementsSeq.getLength() + 1; + + if ( nNewLength != 1 ) + throw xml::sax::SAXException(); // TODO: this element must be the first level element + + m_aElementsSeq.realloc( nNewLength ); + m_aElementsSeq[nNewLength-1] = aName; + + return; // nothing to do + } + else if ( aName == m_aGroupElement ) + { + sal_Int32 nNewLength = m_aElementsSeq.getLength() + 1; + if ( nNewLength != 2 ) + throw xml::sax::SAXException(); // TODO: this element must be the second level element + + m_aElementsSeq.realloc( nNewLength ); + m_aElementsSeq[nNewLength-1] = aName; + + sal_Int32 nNewEntryNum = m_aResultSeq.getLength() + 1; + m_aResultSeq.realloc( nNewEntryNum ); + + ::rtl::OUString aNameValue = xAttribs->getValueByName( m_aNameAttr ); + if ( !aNameValue.getLength() ) + throw xml::sax::SAXException(); // TODO: the ID value must present + + ::rtl::OUString aUINameValue = xAttribs->getValueByName( m_aUINameAttr ); + if ( !aUINameValue.getLength() ) + throw xml::sax::SAXException(); // TODO: the ID value must present + + m_aResultSeq[nNewEntryNum-1].First = aNameValue; + m_aResultSeq[nNewEntryNum-1].Second = aUINameValue; + } + else + { + // accept future extensions + sal_Int32 nNewLength = m_aElementsSeq.getLength() + 1; + + if ( !nNewLength ) + throw xml::sax::SAXException(); // TODO: the extension element must not be the first level element + + m_aElementsSeq.realloc( nNewLength ); + m_aElementsSeq[nNewLength-1] = aName; + } +} + +// ----------------------------------- +void SAL_CALL DocTemplLocaleHelper::endElement( const ::rtl::OUString& aName ) + throw( xml::sax::SAXException, uno::RuntimeException ) +{ + sal_Int32 nLength = m_aElementsSeq.getLength(); + if ( nLength <= 0 ) + throw xml::sax::SAXException(); // TODO: no other end elements expected! + + if ( !m_aElementsSeq[nLength-1].equals( aName ) ) + throw xml::sax::SAXException(); // TODO: unexpected element ended + + m_aElementsSeq.realloc( nLength - 1 ); +} + +// ----------------------------------- +void SAL_CALL DocTemplLocaleHelper::characters( const ::rtl::OUString& /*aChars*/ ) + throw(xml::sax::SAXException, uno::RuntimeException) +{ +} + +// ----------------------------------- +void SAL_CALL DocTemplLocaleHelper::ignorableWhitespace( const ::rtl::OUString& /*aWhitespaces*/ ) + throw(xml::sax::SAXException, uno::RuntimeException) +{ +} + +// ----------------------------------- +void SAL_CALL DocTemplLocaleHelper::processingInstruction( const ::rtl::OUString& /*aTarget*/, const ::rtl::OUString& /*aData*/ ) + throw(xml::sax::SAXException, uno::RuntimeException) +{ +} + +// ----------------------------------- +void SAL_CALL DocTemplLocaleHelper::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& /*xLocator*/ ) + throw(xml::sax::SAXException, uno::RuntimeException) +{ +} + diff --git a/sfx2/source/doc/doctemplateslocal.hxx b/sfx2/source/doc/doctemplateslocal.hxx new file mode 100644 index 000000000000..84b1a9cc9611 --- /dev/null +++ b/sfx2/source/doc/doctemplateslocal.hxx @@ -0,0 +1,88 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _SFX_DOCTEMPLATESLOCAL_HXX +#define _SFX_DOCTEMPLATESLOCAL_HXX + +#ifndef _COM_SUN_STAR_XML_SAX_XDUCUMENTHANDLER_HPP_ +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#endif +#include <com/sun/star/beans/StringPair.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <cppuhelper/implbase1.hxx> + + +class DocTemplLocaleHelper : public cppu::WeakImplHelper1 < com::sun::star::xml::sax::XDocumentHandler > +{ + // Relations info related strings + ::rtl::OUString m_aGroupListElement; + ::rtl::OUString m_aGroupElement; + ::rtl::OUString m_aNameAttr; + ::rtl::OUString m_aUINameAttr; + + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > m_aResultSeq; + ::com::sun::star::uno::Sequence< ::rtl::OUString > m_aElementsSeq; // stack of elements being parsed + + DocTemplLocaleHelper(); // must not be created directly + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > GetParsingResult(); + + static ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > SAL_CALL ReadLocalizationSequence_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream, const ::rtl::OUString& aStringID, const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory ) + throw( ::com::sun::star::uno::Exception ); + +public: + ~DocTemplLocaleHelper(); + + // returns sequence of pairs ( GroupName, GroupUIName ) + static + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > + ReadGroupLocalizationSequence( + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream, + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory ) + throw( ::com::sun::star::uno::Exception ); + + // writes sequence of elements ( GroupName, GroupUIName ) + static + void SAL_CALL WriteGroupLocalizationSequence( + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream >& xOutStream, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair >& aSequence, + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory ) + throw( ::com::sun::star::uno::Exception ); + + // XDocumentHandler + virtual void SAL_CALL startDocument() throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL endDocument() throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL startElement( const ::rtl::OUString& aName, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttribs ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL endElement( const ::rtl::OUString& aName ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL characters( const ::rtl::OUString& aChars ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL ignorableWhitespace( const ::rtl::OUString& aWhitespaces ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL processingInstruction( const ::rtl::OUString& aTarget, const ::rtl::OUString& aData ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setDocumentLocator( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XLocator >& xLocator ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); +}; + +#endif + diff --git a/sfx2/source/doc/docvor.cxx b/sfx2/source/doc/docvor.cxx new file mode 100644 index 000000000000..719dc5b8d223 --- /dev/null +++ b/sfx2/source/doc/docvor.cxx @@ -0,0 +1,2466 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include "com/sun/star/ui/dialogs/TemplateDescription.hpp" + +#include <stdio.h> + +#ifndef _SV_PRNSETUP_HXX //autogen +#include <svtools/prnsetup.hxx> +#endif +#include <vcl/cmdevt.hxx> +#include <vcl/menubtn.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/print.hxx> +#include <svl/style.hxx> +#include <svl/stritem.hxx> +#include <svl/eitem.hxx> +#include <svtools/sfxecode.hxx> +#include <svtools/ehdl.hxx> +#include <svtools/imagemgr.hxx> +#include <vcl/waitobj.hxx> +#include <tools/urlobj.hxx> +#include <tools/color.hxx> +#include <unotools/pathoptions.hxx> +#include <unotools/moduleoptions.hxx> +#include <sot/exchange.hxx> +#include <comphelper/storagehelper.hxx> + +#include "helpid.hrc" +#include "docvor.hxx" +#include <sfx2/docfac.hxx> +#include "orgmgr.hxx" +#include <sfx2/doctempl.hxx> +#include <sfx2/templdlg.hxx> +#include "sfxtypes.hxx" +#include <sfx2/app.hxx> +#include <sfx2/dispatch.hxx> +#include "sfxresid.hxx" +#include "doc.hrc" +#include <sfx2/sfx.hrc> +#include "docvor.hrc" +#include <sfx2/docfilt.hxx> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/fcontnr.hxx> +#include <svtools/localresaccess.hxx> +#ifndef _SVT_DOC_ADDRESSTEMPLATE_HXX_ +#include <svtools/addresstemplate.hxx> +#endif +#include <comphelper/processfactory.hxx> +#define _SVSTDARR_STRINGSDTOR +#include <svl/svstdarr.hxx> + +static const char cDelim = ':'; +BOOL SfxOrganizeListBox_Impl::bDropMoveOk = TRUE; + +using namespace ::com::sun::star; + +//========================================================================= + +class SuspendAccel +{ +public: + Accelerator* pAccel; + + SuspendAccel( Accelerator* pA ) + { + pAccel=pA; + GetpApp()->RemoveAccel( pAccel ); + } + ~SuspendAccel() + { + GetpApp()->InsertAccel( pAccel ); + } +}; + +//========================================================================= + + +inline void SfxOrganizeListBox_Impl::SetBitmaps( + const Image &rOFolder, const Image &rCFolder, const Image &rODoc, const Image &rCDoc, + const Image &rOFolderHC, const Image &rCFolderHC, const Image &rODocHC, const Image &rCDocHC ) +{ + aOpenedFolderBmp = rOFolder; + aClosedFolderBmp = rCFolder; + aOpenedDocBmp = rODoc; + aClosedDocBmp = rCDoc; + + aOpenedFolderBmpHC = rOFolderHC; + aClosedFolderBmpHC = rCFolderHC; + aOpenedDocBmpHC = rODocHC; + aClosedDocBmpHC = rCDocHC; + +} + +//========================================================================= + +#define NO_DROP_ACTION ((sal_Int8)-1) + +class SfxOrganizeDlg_Impl +{ +friend class SfxTemplateOrganizeDlg; +friend class SfxOrganizeListBox_Impl; + + SuspendAccel* pSuspend; + SfxTemplateOrganizeDlg* pDialog; + + SfxOrganizeListBox_Impl* pFocusBox; + Printer* pPrt; + + // save pointer for asynchronous D&D + SvLBox* pSourceView; + SvLBoxEntry* pTargetEntry; + SfxOrganizeListBox_Impl* pFinishedBox; + sal_Int8 nDropAction; + bool bExecDropFinished; + + // save some variables for the asynchronous file dialog + USHORT m_nRegion; + USHORT m_nIndex; + String m_sExtension4Save; + + SfxOrganizeListBox_Impl aLeftLb; + ListBox aLeftTypLb; + + SfxOrganizeListBox_Impl aRightLb; + ListBox aRightTypLb; + + OKButton aOkBtn; + MenuButton aEditBtn; + HelpButton aHelpBtn; + PushButton aAddressTemplateBtn; + PushButton aFilesBtn; + + Accelerator aEditAcc; + + String aLastDir; + SfxOrganizeMgr aMgr; + sfx2::FileDialogHelper* pFileDlg; + + SvStringsDtor* GetAllFactoryURLs_Impl() const; + sal_Bool GetServiceName_Impl( String& rFactoryURL, String& rFileURL ) const; + long Dispatch_Impl( USHORT nId, Menu* _pMenu ); + String GetPath_Impl( BOOL bOpen, const String& rFileName ); + ::com::sun::star::uno::Sequence< ::rtl::OUString > + GetPaths_Impl( const String& rFileName ); + void InitBitmaps( void ); + + DECL_LINK( GetFocus_Impl, SfxOrganizeListBox_Impl * ); + DECL_LINK( LeftListBoxSelect_Impl, ListBox * ); + DECL_LINK( RightListBoxSelect_Impl, ListBox * ); + DECL_LINK( AccelSelect_Impl, Accelerator * ); + DECL_LINK( MenuSelect_Impl, Menu * ); + DECL_LINK( MenuActivate_Impl, Menu * ); + DECL_LINK( AddFiles_Impl, Button * ); + DECL_LINK( OnAddressTemplateClicked, Button * ); + + DECL_LINK( ImportHdl, sfx2::FileDialogHelper* ); + DECL_LINK( ExportHdl, sfx2::FileDialogHelper* ); + DECL_LINK( AddFilesHdl, sfx2::FileDialogHelper* ); + + BOOL DontDelete_Impl( SvLBoxEntry* pEntry ); + void OkHdl( Button* ); + +public: + SfxOrganizeDlg_Impl( SfxTemplateOrganizeDlg* pParent, SfxDocumentTemplates* pTempl ); + ~SfxOrganizeDlg_Impl(); +}; + +//------------------------------------------------------------------------- + +SfxOrganizeDlg_Impl::SfxOrganizeDlg_Impl( SfxTemplateOrganizeDlg* pParent, + SfxDocumentTemplates* pTempl ) : + + pSuspend ( NULL ), + pDialog ( pParent ), + pFocusBox ( NULL ), + pPrt ( NULL ), + pSourceView ( NULL ), + pTargetEntry ( NULL ), + pFinishedBox ( NULL ), + nDropAction ( NO_DROP_ACTION ), + bExecDropFinished ( true ), + + aLeftLb ( this, pParent, WB_BORDER | WB_TABSTOP | WB_HSCROLL, SfxOrganizeListBox_Impl::VIEW_TEMPLATES ), + aLeftTypLb ( pParent, SfxResId( LB_LEFT_TYP ) ), + + aRightLb ( this, pParent, WB_BORDER | WB_TABSTOP | WB_HSCROLL, SfxOrganizeListBox_Impl::VIEW_FILES ), + aRightTypLb ( pParent, SfxResId( LB_RIGHT_TYP ) ), + + aOkBtn ( pParent, SfxResId( BTN_OK ) ), + aEditBtn ( pParent, SfxResId( BTN_EDIT ) ), + aHelpBtn ( pParent, SfxResId( BTN_HELP ) ), + aAddressTemplateBtn ( pParent, SfxResId( BTN_ADDRESSTEMPLATE ) ), + aFilesBtn ( pParent, SfxResId( BTN_FILES ) ), + + aEditAcc ( SfxResId( ACC_EDIT ) ), + aMgr ( &aLeftLb, &aRightLb, pTempl ), + pFileDlg ( NULL ) + +{ + // update the SfxDocumentTemplates the manager works with + if ( aMgr.GetTemplates() ) // should never fail, but who knows .... + { + // for this, show a wait cursor (it may take a while) + Window* pWaitObjectRange = pDialog ? pDialog->GetParent() : NULL; + if ( !pWaitObjectRange ) + pWaitObjectRange = pDialog; + + WaitObject aWaitCursor( pWaitObjectRange ); + const_cast< SfxDocumentTemplates* >( aMgr.GetTemplates() )->Update( sal_True /* be smart */ ); + // this const_cast is a hack - but the alternative would be to + // * have a method which returns the templates non-const + // * use a new SfxDocumentTemplates instance for the update (knowing that they all share the same + // implementation class) + // * always work with an own instance, even if we get only NULL in this ctor + } + + aLeftLb.SetHelpId( HID_CTL_ORGANIZER_LEFT ); + aRightLb.SetHelpId( HID_CTL_ORGANIZER_RIGHT ); + + String aWorkPath = SvtPathOptions().GetWorkPath(); + if ( aWorkPath.Len() ) + { + INetURLObject aObj( aWorkPath ); + DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Illegal URL !" ); + aObj.setFinalSlash(); + aLastDir = aObj.GetMainURL( INetURLObject::DECODE_TO_IURI ); + } + else + { + // fallback + String aProgURL = SvtPathOptions().SubstituteVariable( String::CreateFromAscii("$(PROGURL)") ); + INetURLObject aObj( aProgURL ); + DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Illegal URL !" ); + aLastDir = aObj.GetMainURL( INetURLObject::DECODE_TO_IURI ); + } + + InitBitmaps(); + + aEditBtn.GetPopupMenu()->SetSelectHdl( LINK( this, SfxOrganizeDlg_Impl, MenuSelect_Impl ) ); + aEditBtn.GetPopupMenu()->SetActivateHdl( LINK( this, SfxOrganizeDlg_Impl, MenuActivate_Impl ) ); + aEditAcc.SetSelectHdl( LINK( this, SfxOrganizeDlg_Impl, AccelSelect_Impl ) ); + GetpApp()->InsertAccel( &aEditAcc ); + + aFilesBtn.SetClickHdl( + LINK(this,SfxOrganizeDlg_Impl, AddFiles_Impl)); + aAddressTemplateBtn.SetClickHdl( + LINK(this,SfxOrganizeDlg_Impl, OnAddressTemplateClicked)); + aLeftTypLb.SetSelectHdl( + LINK(this, SfxOrganizeDlg_Impl, LeftListBoxSelect_Impl)); + aRightTypLb.SetSelectHdl( + LINK(this, SfxOrganizeDlg_Impl, RightListBoxSelect_Impl)); + aLeftLb.SetGetFocusHdl( + LINK(this, SfxOrganizeDlg_Impl, GetFocus_Impl)); + aRightLb.SetGetFocusHdl( + LINK(this, SfxOrganizeDlg_Impl, GetFocus_Impl)); + aLeftLb.SetPosSizePixel(pParent->LogicToPixel(Point(3, 6), MAP_APPFONT), + pParent->LogicToPixel(Size(94, 132), MAP_APPFONT)); + aRightLb.SetPosSizePixel(pParent->LogicToPixel(Point(103, 6), MAP_APPFONT), + pParent->LogicToPixel(Size(94, 132), MAP_APPFONT)); + + if ( !SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::E_SDATABASE) ) + aAddressTemplateBtn.Hide(); + Font aFont(aLeftLb.GetFont()); + aFont.SetWeight(WEIGHT_NORMAL); + aLeftLb.SetFont(aFont); + aRightLb.SetFont(aFont); + const long nIndent = aLeftLb.GetIndent() / 2; + aLeftLb.SetIndent( (short)nIndent ); + aRightLb.SetIndent( (short)nIndent ); + + aLeftLb.SetMgr(&aMgr); + aRightLb.SetMgr(&aMgr); + aLeftLb.Reset(); + aRightLb.Reset();//SetModel(aLeftLb.GetModel()); + + aLeftLb.Show(); + aRightLb.Show(); + + aLeftLb.SelectAll( FALSE ); + aRightLb.SelectAll( FALSE ); + aRightLb.GrabFocus(); +} + +//------------------------------------------------------------------------- + +SfxOrganizeDlg_Impl::~SfxOrganizeDlg_Impl() +{ + delete pFileDlg; +} + +//------------------------------------------------------------------------- + +void SfxOrganizeDlg_Impl::InitBitmaps( void ) +{ + Image aOpenedFolderBmp( SfxResId( IMG_OPENED_FOLDER ) ); + Image aClosedFolderBmp( SfxResId( IMG_CLOSED_FOLDER ) ); + Image aOpenedDocBmp( SfxResId( IMG_OPENED_DOC ) ); + Image aClosedDocBmp( SfxResId( IMG_CLOSED_DOC ) ); + + Image aOpenedFolderBmpHC( SfxResId( IMG_OPENED_FOLDER_HC ) ); + Image aClosedFolderBmpHC( SfxResId( IMG_CLOSED_FOLDER_HC ) ); + Image aOpenedDocBmpHC( SfxResId( IMG_OPENED_DOC_HC ) ); + Image aClosedDocBmpHC( SfxResId( IMG_CLOSED_DOC_HC ) ); + + aLeftLb.SetBitmaps( aOpenedFolderBmp, aClosedFolderBmp, aOpenedDocBmp, aClosedDocBmp, + aOpenedFolderBmpHC, aClosedFolderBmpHC, aOpenedDocBmpHC, aClosedDocBmpHC ); + aRightLb.SetBitmaps( aOpenedFolderBmp, aClosedFolderBmp, aOpenedDocBmp, aClosedDocBmp, + aOpenedFolderBmpHC, aClosedFolderBmpHC, aOpenedDocBmpHC, aClosedDocBmpHC ); +} + +//========================================================================= + +BOOL QueryDelete_Impl(Window *pParent, // Parent der QueryBox + USHORT nId, // Resource Id + const String &rTemplateName) // Name der zu l"oschenden Vorlage +/* [Beschreibung] + + "oschabfrage + +*/ +{ + SfxResId aResId( nId ); + String aEntryText( aResId ); + aEntryText.SearchAndReplaceAscii( "$1", rTemplateName ); + QueryBox aBox( pParent, WB_YES_NO | WB_DEF_NO, aEntryText ); + return RET_NO != aBox.Execute(); +} + +//------------------------------------------------------------------------- + +void ErrorDelete_Impl(Window *pParent, const String &rName, sal_Bool bFolder = sal_False ) + +/* [Beschreibung] + + Benutzerinformation, da"s die Vorlage rName nicht gel"oscht werden konnte + +*/ +{ + if ( bFolder ) + { + String aText( SfxResId( STR_ERROR_DELETE_TEMPLATE_DIR ) ); + ErrorBox( pParent, WB_OK, aText ).Execute(); + } + else + { + String aText( SfxResId( STR_ERROR_DELETE_TEMPLATE ) ); + aText.SearchAndReplaceAscii( "$1", rName ); + ErrorBox( pParent, WB_OK, aText ).Execute(); + } +} + + +//========================================================================= + +/* [Beschreibung] + + Implementierungsklasse; Referenzklasse f"ur USHORT-Array + +*/ + +struct ImpPath_Impl +{ + SvUShorts aUS; + USHORT nRef; + + ImpPath_Impl(); + ImpPath_Impl( const ImpPath_Impl& rCopy ); +}; + +//------------------------------------------------------------------------- + +ImpPath_Impl::ImpPath_Impl() : aUS(5), nRef(1) +{ +} + +//------------------------------------------------------------------------- + +ImpPath_Impl::ImpPath_Impl( const ImpPath_Impl& rCopy ) : + + aUS ( (BYTE)rCopy.aUS.Count() ), + nRef( 1 ) + +{ + const USHORT nCount = rCopy.aUS.Count(); + + for ( USHORT i = 0; i < nCount; ++i ) + aUS.Insert( rCopy.aUS[i], i ); +} + +//========================================================================== + +/* [Beschreibung] + + Implementierungsklasse; Darstellung einer Position in der Outline- + Listbox als USHORT-Array; dieses beschreibt die Position jeweil + als relative Postion zum "ubergeordneten Eintrag + +*/ +class Path +{ + ImpPath_Impl *pData; + void NewImp(); +public: + Path(SvLBox *pBox, SvLBoxEntry *pEntry); + Path(const Path &rPath): + pData(rPath.pData) + { + ++pData->nRef; + } + const Path &operator=(const Path &rPath) + { + if(&rPath != this) + { + if(!--pData->nRef) + delete pData; + pData = rPath.pData; + pData->nRef++; + } + return *this; + } + ~Path() + { + if(!--pData->nRef) + delete pData; + } + USHORT Count() const { return pData->aUS.Count(); } + USHORT operator[]( USHORT i ) const + { + return i < Count()? pData->aUS[i]: INDEX_IGNORE; + } +}; + +//------------------------------------------------------------------------- + +Path::Path(SvLBox *pBox, SvLBoxEntry *pEntry) : + pData(new ImpPath_Impl) +{ + DBG_ASSERT(pEntry != 0, "EntryPtr ist NULL"); + if(!pEntry) + return; + SvLBoxEntry *pParent = pBox->GetParent(pEntry); + do { + pData->aUS.Insert((USHORT)pBox->GetModel()->GetRelPos(pEntry), 0); + if(0 == pParent) + break; + pEntry = pParent; + pParent = pBox->GetParent(pEntry); + } while(1); +} + +//------------------------------------------------------------------------- + +void Path::NewImp() +{ + if(pData->nRef != 1) + { + pData->nRef--; + pData = new ImpPath_Impl(*pData); + } +} + +//------------------------------------------------------------------------- + +SvLBoxEntry *GetIndices_Impl(SvLBox *pBox, + SvLBoxEntry *pEntry, + USHORT &rRegion, + USHORT &rOffset) +/* [Beschreibung] + + Bereich und Position innerhalb eines Bereiches f"ur eine + Dokumentvorlage wird ermittelt. + + [Parameter] + + SvLBox *pBox Listbox, an der das Ereignis auftrat + SvLBoxEntry *pEntry Eintrag, dessen Position ermittelt werden soll + USHORT &rRegion der Bereich innerhalb der Bereiche der + Dokumentvorlagen (Out-Parameter) + USHORT &rOffset die Position innerhalb des Bereiches + Dokumentvorlagen (Out-Parameter) + + [Querverweise] + + <class Path> (unter Umst"anden kann auf diese Funktion zugunsten + von Path verzichtet werden.) + +*/ + +{ + if(!pEntry) + { + rRegion = rOffset = 0; + return pEntry; + } + if(0 == pBox->GetModel()->GetDepth(pEntry)) + { + rRegion = (USHORT)pBox->GetModel()->GetRelPos(pEntry); + rOffset = USHRT_MAX; + return pEntry; + } + SvLBoxEntry *pParent = pBox->GetParent(pEntry); + rRegion = (USHORT)pBox->GetModel()->GetRelPos(pParent); + rOffset = (USHORT)pBox->GetModel()->GetRelPos(pEntry); + return pEntry; +} + +//------------------------------------------------------------------------- + +BOOL SfxOrganizeListBox_Impl::Select( SvLBoxEntry* pEntry, BOOL bSelect ) +{ + if(!bSelect) + return SvTreeListBox::Select(pEntry,bSelect); + USHORT nLevel = GetDocLevel(); + if(GetModel()->GetDepth(pEntry)+nLevel<3) + return SvTreeListBox::Select(pEntry,bSelect); + + Path aPath(this, pEntry); + GetObjectShell(aPath)->TriggerHelpPI( + aPath[nLevel+1], aPath[nLevel+2], aPath[nLevel+3]); + return SvTreeListBox::Select(pEntry,bSelect); +} + +//------------------------------------------------------------------------- + +BOOL SfxOrganizeListBox_Impl::MoveOrCopyTemplates(SvLBox *pSourceBox, + SvLBoxEntry *pSource, + SvLBoxEntry* pTarget, + SvLBoxEntry *&pNewParent, + ULONG &rIdx, + BOOL bCopy) +/* [Beschreibung] + + Verschieben oder Kopieren von Dokumentvorlagen + + [Parameter] + + SvLBox *pSourceBox Quell-Listbox, an der das Ereignis auftrat + SvLBoxEntry *pSource Quell-Eintrag, der kopiert / verschoben werden soll + SvLBoxEntry* pTarget Ziel-Eintrag, auf den verschoben werden soll + SvLBoxEntry *&pNewParent der Parent der an der Zielposition erzeugten + Eintrags (Out-Parameter) + ULONG &rIdx Index des Zieleintrags + BOOL bCopy Flag f"ur Kopieren / Verschieben + + + [Returnwert] BOOL: Erfolg oder Mi"serfolg + + [Querverweise] + + <SfxOrganizeListBox_Impl::MoveOrCopyContents(SvLBox *pSourceBox, + SvLBoxEntry *pSource, + SvLBoxEntry* pTarget, + SvLBoxEntry *&pNewParent, + ULONG &rIdx, + BOOL bCopy)> + <BOOL SfxOrganizeListBox_Impl::NotifyMoving(SvLBoxEntry *pTarget, + SvLBoxEntry* pSource, + SvLBoxEntry *&pNewParent, + ULONG &rIdx)> + <BOOL SfxOrganizeListBox_Impl::NotifyCopying(SvLBoxEntry *pTarget, + SvLBoxEntry* pSource, + SvLBoxEntry *&pNewParent, + ULONG &rIdx)> +*/ + +{ + BOOL bOk = FALSE; + + if(pSource) + { + USHORT nTargetRegion = 0, nTargetIndex = 0; + GetIndices_Impl(this, pTarget, nTargetRegion, nTargetIndex); + + USHORT nSourceRegion = 0, nSourceIndex = 0; + GetIndices_Impl(pSourceBox, pSource, nSourceRegion, nSourceIndex); + + bOk = bCopy ? + pMgr->Copy(nTargetRegion, nTargetIndex+1, + nSourceRegion, nSourceIndex): + pMgr->Move(nTargetRegion, nTargetIndex+1, + nSourceRegion, nSourceIndex); + + if(bOk) + { + if(pSourceBox->GetModel()->GetDepth(pSource) == GetModel()->GetDepth(pTarget)) + { + pNewParent = GetParent(pTarget); + rIdx = GetModel()->GetRelPos(pTarget)+1; + } + else + { + if(nTargetIndex == USHRT_MAX) + { + pNewParent = pTarget; + rIdx = 0; + } + else + SvLBox::NotifyCopying( + pTarget, pSource, pNewParent, rIdx); + } + } + else if ( bCopy ) + { + // the template organizer always tries copy after the move, so no error is required for move case + String aText( SfxResId( bCopy ? STR_ERROR_COPY_TEMPLATE : STR_ERROR_MOVE_TEMPLATE ) ); + aText.SearchAndReplaceAscii( "$1", + ( (SvTreeListBox *)pSourceBox )->GetEntryText( pSource ) ); + ErrorBox( this, WB_OK, aText ).Execute(); + } + } + return bOk; +} + +//------------------------------------------------------------------------- + +BOOL SfxOrganizeListBox_Impl::MoveOrCopyContents(SvLBox *pSourceBox, + SvLBoxEntry *pSource, + SvLBoxEntry* pTarget, + SvLBoxEntry *&pNewParent, + ULONG &rIdx, + BOOL bCopy) +/* [Beschreibung] + + Verschieben oder Kopieren von Dokumentinhalten + + [Parameter] + + SvLBox *pSourceBox Quell-Listbox, an der das Ereignis auftrat + SvLBoxEntry *pSource Quell-Eintrag, der kopiert / verschoben werden soll + SvLBoxEntry* pTarget Ziel-Eintrag, auf den verschoben werden soll + SvLBoxEntry *&pNewParent der Parent der an der Zielposition erzeugten + Eintrags (Out-Parameter) + ULONG &rIdx Index des Zieleintrags + BOOL bCopy Flag f"ur Kopieren / Verschieben + + + [Returnwert] BOOL: Erfolg oder Mi"serfolg + + [Querverweise] + + <SfxOrganizeListBox_Impl::MoveOrCopyTemplates(SvLBox *pSourceBox, + SvLBoxEntry *pSource, + SvLBoxEntry* pTarget, + SvLBoxEntry *&pNewParent, + ULONG &rIdx, + BOOL bCopy)> + <BOOL SfxOrganizeListBox_Impl::NotifyMoving(SvLBoxEntry *pTarget, + SvLBoxEntry* pSource, + SvLBoxEntry *&pNewParent, + ULONG &rIdx)> + <BOOL SfxOrganizeListBox_Impl::NotifyCopying(SvLBoxEntry *pTarget, + SvLBoxEntry* pSource, + SvLBoxEntry *&pNewParent, + ULONG &rIdx)> +*/ + +{ + SfxErrorContext aEc( ERRCTX_SFX_MOVEORCOPYCONTENTS, this); + BOOL bOk = FALSE, bKeepExpansion = FALSE; + BOOL bRemovedFromSource = FALSE; + Path aSource(pSourceBox, pSource); + Path aTarget(this, pTarget); + SfxObjectShellRef aSourceDoc = + ((SfxOrganizeListBox_Impl *)pSourceBox)->GetObjectShell(aSource); + + SfxObjectShellRef aTargetDoc = GetObjectShell(aTarget); + const USHORT nSLevel = + ((SfxOrganizeListBox_Impl *)pSourceBox)->GetDocLevel(); + const USHORT nTLevel = GetDocLevel(); + + if(aSourceDoc.Is() && aTargetDoc.Is()) + { + if (aSourceDoc->GetStyleSheetPool()) + aSourceDoc->GetStyleSheetPool()->SetSearchMask( + SFX_STYLE_FAMILY_ALL, SFXSTYLEBIT_USERDEF | SFXSTYLEBIT_USED); + + if (aTargetDoc->GetStyleSheetPool()) + aTargetDoc->GetStyleSheetPool()->SetSearchMask( + SFX_STYLE_FAMILY_ALL, SFXSTYLEBIT_USERDEF | SFXSTYLEBIT_USED); + USHORT p[3]; + USHORT nIdxDeleted = INDEX_IGNORE; + p[0]=aTarget[nTLevel+1]; + p[1]=aTarget[nTLevel+2]; + if(p[1]!=INDEX_IGNORE)p[1]++; + p[2]=aTarget[nTLevel+3]; + + bOk = aTargetDoc->Insert( + *aSourceDoc, aSource[nSLevel+1], + aSource[nSLevel+2], aSource[nSLevel+3], + p[0], p[1], p[2], nIdxDeleted); + // Positionskorrektur auswerten + // a = Dokumentinhalt + // b = Position Sub-Inhalt 1 + // c = Position Sub-Inhalt 2 + // doppelte Eintraege loeschen + if(bOk) + { + SvLBoxEntry *pParentIter = pTarget; + // bis auf die DokumentEbene nach oben als + // allgemeiner Bezugspunkt + while(GetModel()->GetDepth(pParentIter) != nTLevel) + pParentIter = GetParent(pParentIter); + if(pParentIter->HasChildsOnDemand() && + !GetModel()->HasChilds(pParentIter)) + RequestingChilds(pParentIter); + SvLBoxEntry *pChildIter = 0; + + USHORT i = 0; + while(i < 2 && p[i+1] != INDEX_IGNORE) + { + pChildIter = FirstChild(pParentIter); + // bis zum Index der aktuellen Ebene + for(USHORT j = 0; j < p[i]; ++j) + pChildIter = NextSibling(pChildIter); + // gfs Fuellen bei Items onDemand + ++i; + if(p[i+1] != INDEX_IGNORE && + pChildIter->HasChildsOnDemand() && + !GetModel()->HasChilds(pChildIter)) + RequestingChilds(pChildIter); + pParentIter = pChildIter; + } + rIdx = p[i]; + pNewParent = pParentIter; + if(!IsExpanded(pNewParent) && + pNewParent->HasChildsOnDemand() && + !GetModel()->HasChilds(pNewParent)) + { + bOk = FALSE; + if(!bCopy) + pSourceBox->GetModel()->Remove(pSource); + } + // Geloeschte Eintraege entfernen + // (kann durch Ueberschreiben geschehen) + if(nIdxDeleted != INDEX_IGNORE) + { + pChildIter = FirstChild(pParentIter); + for(USHORT j = 0; j < nIdxDeleted; ++j) + pChildIter = NextSibling(pChildIter); + if( pChildIter && pChildIter != pSource ) + { + bKeepExpansion = IsExpanded(pParentIter); + GetModel()->Remove(pChildIter); + } + else + bOk = FALSE; + } + if(!bCopy && &aSourceDoc != &aTargetDoc) + { + //#109566# pool styles that are moved produce + //an rIdx == INDEX_IGNORE + //the method has to return true to keep the box content consistent + bRemovedFromSource = aSourceDoc->Remove(aSource[nSLevel+1], + aSource[nSLevel+2], + aSource[nSLevel+3]); + } + } + } +// rIdx++; + return (((rIdx != INDEX_IGNORE)|| bRemovedFromSource) && bOk ) + ? bKeepExpansion? (BOOL)2: TRUE: FALSE; +} + +//------------------------------------------------------------------------- + +BOOL SfxOrganizeListBox_Impl::NotifyMoving(SvLBoxEntry *pTarget, + SvLBoxEntry* pSource, + SvLBoxEntry *&pNewParent, + ULONG &rIdx) + +/* [Beschreibung] + + Benachrichtigung, da"s ein Eintrag verschoben werden soll + (SV-Handler) + + [Parameter] + + SvLBoxEntry* pTarget Ziel-Eintrag, auf den verschoben werden soll + SvLBoxEntry *pSource Quell-Eintrag, der verschoben werden soll + SvLBoxEntry *&pNewParent der Parent der an der Zielposition erzeugten + Eintrags (Out-Parameter) + ULONG &rIdx Index des Zieleintrags + + + [Returnwert] BOOL: Erfolg oder Mi"serfolg + + [Querverweise] + + <SfxOrganizeListBox_Impl::MoveOrCopyTemplates(SvLBox *pSourceBox, + SvLBoxEntry *pSource, + SvLBoxEntry* pTarget, + SvLBoxEntry *&pNewParent, + ULONG &rIdx, + BOOL bCopy)> + <SfxOrganizeListBox_Impl::MoveOrCopyContents(SvLBox *pSourceBox, + SvLBoxEntry *pSource, + SvLBoxEntry* pTarget, + SvLBoxEntry *&pNewParent, + ULONG &rIdx, + BOOL bCopy)> + <BOOL SfxOrganizeListBox_Impl::NotifyCopying(SvLBoxEntry *pTarget, + SvLBoxEntry* pSource, + SvLBoxEntry *&pNewParent, + ULONG &rIdx)> +*/ + +{ + BOOL bOk = FALSE; + SvLBox* pSourceBox = GetSourceView(); + if ( !pSourceBox ) + pSourceBox = pDlg->pSourceView; + DBG_ASSERT( pSourceBox, "no source view" ); + if ( !pTarget ) + pTarget = pDlg->pTargetEntry; + + if ( pSourceBox->GetModel()->GetDepth( pSource ) <= GetDocLevel() && + GetModel()->GetDepth( pTarget ) <= GetDocLevel() ) + bOk = MoveOrCopyTemplates( pSourceBox, pSource, pTarget, pNewParent, rIdx, FALSE ); + else + bOk = MoveOrCopyContents(pSourceBox, pSource, pTarget, pNewParent, rIdx, FALSE ); + + return bOk; +} + +//------------------------------------------------------------------------- + +BOOL SfxOrganizeListBox_Impl::NotifyCopying(SvLBoxEntry *pTarget, + SvLBoxEntry* pSource, + SvLBoxEntry *&pNewParent, + ULONG &rIdx) +/* [Beschreibung] + + Benachrichtigung, da"s ein Eintrag kopiert werden soll + (SV-Handler) + + [Parameter] + + SvLBoxEntry* pTarget Ziel-Eintrag, auf den kopiert werden soll + SvLBoxEntry *pSource Quell-Eintrag, der kopiert werden soll + SvLBoxEntry *&pNewParent der Parent der an der Zielposition erzeugten + Eintrags (Out-Parameter) + ULONG &rIdx Index des Zieleintrags + + + [Returnwert] BOOL: Erfolg oder Mi"serfolg + + [Querverweise] + + <SfxOrganizeListBox_Impl::MoveOrCopyTemplates(SvLBox *pSourceBox, + SvLBoxEntry *pSource, + SvLBoxEntry* pTarget, + SvLBoxEntry *&pNewParent, + ULONG &rIdx, + BOOL bCopy)> + <SfxOrganizeListBox_Impl::MoveOrCopyContents(SvLBox *pSourceBox, + SvLBoxEntry *pSource, + SvLBoxEntry* pTarget, + SvLBoxEntry *&pNewParent, + ULONG &rIdx, + BOOL bCopy)> + <BOOL SfxOrganizeListBox_Impl::NotifyMoving(SvLBoxEntry *pTarget, + SvLBoxEntry* pSource, + SvLBoxEntry *&pNewParent, + ULONG &rIdx)> +*/ +{ + BOOL bOk = FALSE; + SvLBox* pSourceBox = GetSourceView(); + if ( !pSourceBox ) + pSourceBox = pDlg->pSourceView; + DBG_ASSERT( pSourceBox, "no source view" ); + if ( !pTarget ) + pTarget = pDlg->pTargetEntry; + if ( pSourceBox->GetModel()->GetDepth( pSource ) <= GetDocLevel() && + GetModel()->GetDepth( pTarget ) <= GetDocLevel() ) + bOk = MoveOrCopyTemplates( pSourceBox, pSource, pTarget, pNewParent, rIdx, TRUE ); + else + bOk = MoveOrCopyContents( pSourceBox, pSource, pTarget, pNewParent, rIdx, TRUE ); + + return bOk; +} + +//------------------------------------------------------------------------- + +BOOL SfxOrganizeListBox_Impl::EditingEntry( SvLBoxEntry* pEntry, Selection& ) + +/* [Beschreibung] + + Nachfrage, ob ein Eintrag editierbar ist + (SV-Handler) + + [Querverweise] + <SfxOrganizeListBox_Impl::EditedEntry(SvLBoxEntry* pEntry, const String& rText)> +*/ + +{ + if( VIEW_TEMPLATES == eViewType && + GetModel()->GetDepth(pEntry) < 2 ) + { + pDlg->pSuspend = new SuspendAccel( &pDlg->aEditAcc ); + return TRUE; + } + return FALSE; +} + +//------------------------------------------------------------------------- + +BOOL SfxOrganizeListBox_Impl::EditedEntry(SvLBoxEntry* pEntry, const String& rText) + +/* [Beschreibung] + + Der Name eines Eintrags wurde bearbeitet; ist der eingegebene Name + ein g"ultiger Name ("ange > 0), wird das Model aktualisiert. + (SV-Handler) + + [Returnwert] + + BOOL TRUE: der Name soll in der Anzeige ge"andert werden + FALSE:der Name soll nicht ge"andert werden + + [Querverweise] + <SfxOrganizeListBox_Impl::EditingEntry(SvLBoxEntry* pEntry, const String& rText)> +*/ + +{ + DBG_ASSERT(pEntry, "kein Entry selektiert"); + delete pDlg->pSuspend; + pDlg->pSuspend = NULL; + SvLBoxEntry* pParent = GetParent(pEntry); + if( !rText.Len() ) + { + ErrorBox aBox( this, SfxResId( MSG_ERROR_EMPTY_NAME ) ); + aBox.GrabFocus(); + aBox.Execute(); + return FALSE; + } + if ( !IsUniqName_Impl( rText, pParent, pEntry ) ) + { + ErrorBox aBox( this, SfxResId( MSG_ERROR_UNIQ_NAME ) ); + aBox.GrabFocus(); + aBox.Execute(); + return FALSE; + } + USHORT nRegion = 0, nIndex = 0; + GetIndices_Impl( this, pEntry, nRegion, nIndex ); + String aOldName; + if ( USHRT_MAX != nIndex ) + aOldName = pMgr->GetTemplates()->GetName( nRegion, nIndex ); + else + aOldName = pMgr->GetTemplates()->GetRegionName( nRegion ); + + if ( !pMgr->SetName( rText, nRegion, nIndex ) ) + { + SfxResId aResId( USHRT_MAX != nIndex ? MSG_ERROR_RENAME_TEMPLATE + : MSG_ERROR_RENAME_TEMPLATE_REGION ); + ErrorBox( this, aResId ).Execute(); + return FALSE; + } +/* + else + { + SfxTemplateOrganizeDlg* pDlg = (SfxTemplateOrganizeDlg*)Window::GetParent(); + } +*/ + return TRUE; +} + +//------------------------------------------------------------------------- + +DragDropMode SfxOrganizeListBox_Impl::NotifyStartDrag( TransferDataContainer&, SvLBoxEntry* pEntry ) +{ + USHORT nSourceLevel = GetModel()->GetDepth( pEntry ); + if ( VIEW_FILES == GetViewType() ) + ++nSourceLevel; + if ( nSourceLevel >= 2 ) + bDropMoveOk = FALSE; + else + bDropMoveOk = TRUE; + + return GetDragDropMode(); +} + +//------------------------------------------------------------------------- + +BOOL SfxOrganizeListBox_Impl::NotifyAcceptDrop( SvLBoxEntry* pEntry ) +{ + if(!pEntry) + return FALSE; + SvLBox *pSource = GetSourceView(); + SvLBoxEntry *pSourceEntry = pSource->FirstSelected(); + if(pEntry == pSourceEntry) + return FALSE; + USHORT nSourceLevel = pSource->GetModel()->GetDepth(pSourceEntry); + if(VIEW_FILES == ((SfxOrganizeListBox_Impl *)pSource)->GetViewType()) + ++nSourceLevel; + USHORT nTargetLevel = GetModel()->GetDepth(pEntry); + if(VIEW_FILES == GetViewType()) + ++nTargetLevel; + Path aSource(pSource, pSourceEntry); + Path aTarget(this, pEntry); + const USHORT SL = ((SfxOrganizeListBox_Impl *)pSource)->GetDocLevel(); + const USHORT TL = GetDocLevel(); + + return( (nSourceLevel == 1 && nTargetLevel == 0 && + VIEW_TEMPLATES == + ((SfxOrganizeListBox_Impl *)pSource)->GetViewType()) || + (nSourceLevel == 1 && nTargetLevel == 1 && + VIEW_TEMPLATES == + ((SfxOrganizeListBox_Impl *)pSource)->GetViewType() && + VIEW_TEMPLATES == GetViewType()) || + (nSourceLevel == 3 && nTargetLevel == 1) || + (nSourceLevel == 3 && nTargetLevel == 2 && + aSource[1+SL] == aTarget[1+TL]) || + (nSourceLevel == 3 && nTargetLevel == 3 && + aSource[1+SL] == aTarget[1+TL]) || + (nSourceLevel == 4 && nTargetLevel == 3 && + aSource[1+SL] == aTarget[1+TL] && + aSource[2+SL] == aTarget[2+TL]) || + (nSourceLevel == 4 && nTargetLevel == 4 && + aSource[1+SL] == aTarget[1+TL] && + aSource[2+SL] == aTarget[2+TL])); +} + +//------------------------------------------------------------------------- + +sal_Int8 SfxOrganizeListBox_Impl::AcceptDrop( const AcceptDropEvent& rEvt ) +{ + sal_Bool bAccept = ( eViewType == VIEW_FILES && IsDropFormatSupported( SOT_FORMAT_FILE ) ); + if ( bAccept ) + return rEvt.mnAction; + else + return SvTreeListBox::AcceptDrop( rEvt ); +} + +//------------------------------------------------------------------------- + +sal_Int8 SfxOrganizeListBox_Impl::ExecuteDrop( const ExecuteDropEvent& rEvt ) +{ + TransferableDataHelper aHelper( rEvt.maDropEvent.Transferable ); + sal_uInt32 nFormatCount = aHelper.GetFormatCount(); + BOOL bSuccess = FALSE; + for ( sal_uInt32 i = 0; i < nFormatCount; ++i ) + { + String aFileName; + SotFormatStringId nId = aHelper.GetFormat(i); + + if ( SOT_FORMAT_FILE == nId && aHelper.GetString( nId, aFileName ) ) + { + INetURLObject aObj( aFileName, INET_PROT_FILE ); + bSuccess |= pMgr->InsertFile( this, aObj.GetMainURL(INetURLObject::DECODE_TO_IURI) ); + } + } + bDropMoveOk = TRUE; + sal_Int8 nRet = rEvt.mnAction; + if ( !bSuccess ) + { + // asynchronous, because of MessBoxes + pDlg->pSourceView = GetSourceView(); + pDlg->pTargetEntry = pTargetEntry; + pDlg->pFinishedBox = NULL; + pDlg->nDropAction = NO_DROP_ACTION; + PostUserEvent( LINK( this, SfxOrganizeListBox_Impl, OnAsyncExecuteDrop ), + new ExecuteDropEvent( rEvt ) ); + } + + return nRet; +} + +//------------------------------------------------------------------------- + +void SfxOrganizeListBox_Impl::DragFinished( sal_Int8 nDropAction ) +{ + if ( pDlg->bExecDropFinished ) + { + if ( pDlg->nDropAction != NO_DROP_ACTION ) + nDropAction = pDlg->nDropAction; + SvTreeListBox::DragFinished( nDropAction ); + pDlg->nDropAction = NO_DROP_ACTION; + } + else + pDlg->pFinishedBox = this; +} + +//------------------------------------------------------------------------- + +inline USHORT SfxOrganizeListBox_Impl::GetDocLevel() const + +/* [Beschreibung] + + Ermittelt, auf welche Ebene sich Dokumente befinden (unterschiedlich + in der Dokumentvorlagensicht und der Dokumentensicht) + + [Returnwert] + + USHORT Die Ebene der Dokumente + +*/ + +{ + return eViewType == VIEW_FILES? 0: 1; +} + +//------------------------------------------------------------------------- + +SfxObjectShellRef SfxOrganizeListBox_Impl::GetObjectShell(const Path &rPath) + +/* [Beschreibung] + + Zugriff auf die ObjectShell, die dem aktuellen Eintrag zugeordnet + ist. + + [Parameter] + + const Path &rPath Beschreibung des aktuellen Eintrags + + [Returnwert] + + SfxObjectShellRef Referenz auf die ObjectShell + + [Querverweise] + + <class Path> + +*/ + +{ + SfxObjectShellRef aDoc; + if(eViewType == VIEW_FILES) + aDoc = pMgr->CreateObjectShell(rPath[0]); + else + aDoc = pMgr->CreateObjectShell(rPath[0], rPath[1]); + return aDoc; +} + +//------------------------------------------------------------------------- + +void SfxOrganizeListBox_Impl::RequestingChilds( SvLBoxEntry* pEntry ) + +/* [Beschreibung] + + Aufforderung, der Childs eines Eintrags einzuf"ugen + ist. + (SV-Handler) + + [Parameter] + + SvLBoxEntry* pEntry der Eintrag, dessen Childs erfragt werden + + +*/ + +{ + // wenn keine Childs vorhanden sind, gfs. Childs + // einfuegen + BmpColorMode eColorMode = BMP_COLOR_NORMAL; + + if ( GetSettings().GetStyleSettings().GetHighContrastMode() ) + eColorMode = BMP_COLOR_HIGHCONTRAST; + + + if ( !GetModel()->HasChilds( pEntry ) ) + { + WaitObject aWaitCursor( this ); + + // Choose the correct mask color dependent from eColorMode. This must be adopted if + // we change the mask color for normal images, too! + Color aMaskColor( COL_LIGHTMAGENTA ); + + // hier sind alle initial eingefuegt + SfxErrorContext aEc(ERRCTX_SFX_CREATEOBJSH, pDlg->pDialog); + if(VIEW_TEMPLATES == GetViewType() && 0 == GetModel()->GetDepth(pEntry)) + { + USHORT i = (USHORT)GetModel()->GetRelPos(pEntry); + const USHORT nEntryCount = pMgr->GetTemplates()->GetCount(i); + for(USHORT j = 0; j < nEntryCount; ++j) + InsertEntryByBmpType( pMgr->GetTemplates()->GetName( i, j ), BMPTYPE_DOC, pEntry, TRUE ); + } + else + { + const USHORT nDocLevel = GetDocLevel(); + Path aPath(this, pEntry); + SfxObjectShellRef aRef = GetObjectShell(aPath); + if(aRef.Is()) + { + const USHORT nCount = aRef->GetContentCount( + aPath[nDocLevel+1], aPath[nDocLevel+2]); + String aText; + Bitmap aClosedBmp, aOpenedBmp; + const BOOL bCanHaveChilds = + aRef->CanHaveChilds(aPath[nDocLevel+1], + aPath[nDocLevel+2]); + for(USHORT i = 0; i < nCount; ++i) + { + BOOL bDeletable; + aRef->GetContent( + aText, aClosedBmp, aOpenedBmp, eColorMode, bDeletable, + i, aPath[nDocLevel+1], aPath[nDocLevel+2]); + + // Create image with the correct mask color + Image aClosedImage( aClosedBmp, aMaskColor ); + Image aOpenedImage( aOpenedBmp, aMaskColor ); + + SvLBoxEntry *pNew = SvTreeListBox::InsertEntry( + aText, aOpenedImage, aClosedImage, + pEntry, bCanHaveChilds); + pNew->SetUserData(bDeletable ? &bDeletable : 0); + } + } + } + } +} + +//------------------------------------------------------------------------- + +long SfxOrganizeListBox_Impl::ExpandingHdl() + +/* [Beschreibung] + + SV-Handler, der nach dem und vor dem Aufklappen eines Eintrags + gerufen wird. + Wird verwendet, um gfs. die ObjectShell wieder zu schlie"sen; + die Eintr"age mit den Inhalten dieser Shell werden ebenfalls + entfernt. + +*/ + +{ + if ( !(nImpFlags & SVLBOX_IS_EXPANDING) ) + { + SvLBoxEntry* pEntry = GetHdlEntry(); + const USHORT nLevel = GetModel()->GetDepth(pEntry); + if((eViewType == VIEW_FILES && nLevel == 0) || + (eViewType == VIEW_TEMPLATES && nLevel == 1)) + { + Path aPath(this, pEntry); + // Beim Schliessen des Files die ObjectShell freigeben + if(eViewType == VIEW_FILES && nLevel == 0) + pMgr->DeleteObjectShell(aPath[0]); + else + pMgr->DeleteObjectShell(aPath[0], aPath[1]); + // alle SubEntries loeschen + SvLBoxEntry *pToDel = SvLBox::GetEntry(pEntry, 0); + while(pToDel) + { + GetModel()->Remove(pToDel); + pToDel = SvLBox::GetEntry(pEntry, 0); + } + } + } + return TRUE; +} + +//------------------------------------------------------------------------- + +BOOL SfxOrganizeListBox_Impl::IsUniqName_Impl(const String &rText, + SvLBoxEntry* pParent, SvLBoxEntry *pEntry) const + +/* [Beschreibung] + + Pr"uft, ob eine Name auf seiner Ebene eindeutig ist. + + [Parameter] + + const String & Name des zu suchenden Eintrags + SvLBoxEntry* pSibling Geschwister (bezeichnet die Ebene) + + [Returnwert] + + BOOL TRUE, wenn der Name eindeutig ist, sonst FALSE +*/ + +{ + SvLBoxEntry* pChild = FirstChild(pParent); + while(pChild) { + const String aEntryText(GetEntryText(pChild)); + if(COMPARE_EQUAL == aEntryText.CompareIgnoreCaseToAscii(rText)&&(!pEntry || pEntry!=pChild)) + return FALSE; + pChild = NextSibling(pChild); + } + return TRUE; +} + +//------------------------------------------------------------------------- + +USHORT SfxOrganizeListBox_Impl::GetLevelCount_Impl(SvLBoxEntry* pParent) const +{ + SvLBoxEntry* pChild = FirstChild(pParent); + USHORT nCount = 0; + while(pChild) { + pChild = NextSibling(pChild); + ++nCount; + } + return nCount; +} + +//------------------------------------------------------------------------- + +SvLBoxEntry* SfxOrganizeListBox_Impl::InsertEntryByBmpType( const XubString& rText, BMPTYPE eBmpType, + SvLBoxEntry* pParent, BOOL bChildsOnDemand, ULONG nPos, void* pUserData ) +{ + SvLBoxEntry* pEntry = NULL; + const Image* pExp = NULL; + const Image* pCol = NULL; + const Image* pExpHC = NULL; + const Image* pColHC = NULL; + + switch( eBmpType ) + { + case BMPTYPE_FOLDER: + pExp = &aOpenedFolderBmp; + pCol = &aClosedFolderBmp; + pExpHC = &aOpenedFolderBmpHC; + pColHC = &aClosedFolderBmpHC; + break; + default: + DBG_ERROR( "SfxOrganizeListBox_Impl::InsertEntryByBmpType(): something forgotten?!" ); + + case BMPTYPE_DOC: + pExp = &aOpenedDocBmp; + pCol = &aClosedDocBmp; + pExpHC = &aOpenedDocBmpHC; + pColHC = &aClosedDocBmpHC; + break; + } + + pEntry = SvTreeListBox::InsertEntry( rText, *pExp, *pCol, pParent, bChildsOnDemand, nPos, pUserData ); + + SetExpandedEntryBmp( pEntry, *pExpHC, BMP_COLOR_HIGHCONTRAST ); + SetCollapsedEntryBmp( pEntry, *pColHC, BMP_COLOR_HIGHCONTRAST ); + + return pEntry; +} + +//------------------------------------------------------------------------- + +SfxOrganizeListBox_Impl::SfxOrganizeListBox_Impl +( + SfxOrganizeDlg_Impl* pArgDlg, + Window* pParent, + WinBits nBits, + DataEnum eType +) : + + SvTreeListBox( pParent, nBits ), + + pMgr ( NULL ), + pDlg ( pArgDlg ), + eViewType ( eType ) + +/* [Beschreibung] + + Konstruktor SfxOrganizeListBox + +*/ + +{ + SetDragDropMode( + SV_DRAGDROP_CTRL_MOVE | SV_DRAGDROP_CTRL_COPY | + SV_DRAGDROP_APP_MOVE | SV_DRAGDROP_APP_COPY | SV_DRAGDROP_APP_DROP ); + SetEntryHeight( 16 ); + SetSelectionMode( SINGLE_SELECTION ); + GetModel()->SetSortMode( SortNone ); + + EnableContextMenuHandling(); +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxOrganizeListBox_Impl, OnAsyncExecuteDrop, ExecuteDropEvent*, pEvent ) +{ + DBG_ASSERT( pEvent, "invalid DropEvent" ); + if ( pEvent ) + { + SvLBox* pSourceView = GetSourceView(); + if ( !pSourceView ) + pSourceView = pDlg->pSourceView; + pDlg->bExecDropFinished = false; + // if a template can not be moved it should be copied + if ( pEvent->mnAction == DND_ACTION_MOVE ) + pEvent->mnAction = DND_ACTION_COPYMOVE; + pDlg->nDropAction = SvTreeListBox::ExecuteDrop( *pEvent, pSourceView ); + delete pEvent; + pDlg->pSourceView = NULL; + pDlg->pTargetEntry = NULL; + pDlg->bExecDropFinished = true; + if ( pDlg->pFinishedBox ) + { + pDlg->pFinishedBox->DragFinished( pDlg->nDropAction ); + pDlg->pFinishedBox = NULL; + } + } + return 0; +} + +//------------------------------------------------------------------------- + +void SfxOrganizeListBox_Impl::Reset() + +/* [Beschreibung] + + Einf"ugen der Elemente in die ListBox + +*/ + +{ + DBG_ASSERT( pMgr != 0, "kein Manager" ); + // Inhalte l"oschen + SetUpdateMode(FALSE); + Clear(); + if ( VIEW_TEMPLATES == eViewType ) + { + const USHORT nCount = pMgr->GetTemplates()->GetRegionCount(); + for ( USHORT i = 0; i < nCount; ++i ) + InsertEntryByBmpType( pMgr->GetTemplates()->GetFullRegionName(i), BMPTYPE_FOLDER, 0, TRUE ); + } + else + { + const SfxObjectList& rList = pMgr->GetObjectList(); + const USHORT nCount = rList.Count(); + for ( USHORT i = 0; i < nCount; ++i ) + InsertEntryByBmpType( rList.GetBaseName(i), BMPTYPE_DOC, 0, TRUE ); + + } + SetUpdateMode(TRUE); + Invalidate(); + Update(); +} + +//------------------------------------------------------------------------- + +const Image &SfxOrganizeListBox_Impl::GetClosedBmp(USHORT nLevel) const + +/* [Beschreibung] + + Zugriff auf die Bitmap f"ur einen geschlossenen Eintrag + der jeweiligen Ebene + + [Parameter] + + USHORT nLevel Angabe der Ebene, 2 Ebenen sind erlaubt + + [Returnwert] + + const Image & das Image auf der Ebenen nLevel + +*/ + +{ + BOOL bHC = GetSettings().GetStyleSettings().GetHighContrastMode(); + const Image* pRet = NULL; + + switch( nLevel ) + { + default: DBG_ERROR( "Bitmaps ueberindiziert" ); + + case 0: pRet = bHC? &aClosedFolderBmpHC : &aClosedFolderBmp; break; + case 1: pRet = bHC? &aClosedDocBmpHC : &aClosedDocBmp; break; + } + + return *pRet; +} + +//------------------------------------------------------------------------- + +const Image &SfxOrganizeListBox_Impl::GetOpenedBmp(USHORT nLevel) const + +/* [Beschreibung] + + Zugriff auf die Bitmap f"ur einen ge"offneten Eintrag + der jeweiligen Ebene + + [Parameter] + + USHORT nLevel Angabe der Ebene, 2 Ebenen sind erlaubt + + [Returnwert] + + const Image & das Image auf der Ebenen nLevel + +*/ + +{ + BOOL bHC = GetSettings().GetStyleSettings().GetHighContrastMode(); + const Image* pRet = NULL; + + switch( nLevel ) + { + case 0: + pRet = bHC ? &aOpenedFolderBmpHC : &aOpenedFolderBmp; break; + case 1: + pRet = bHC ? &aOpenedDocBmpHC : &aOpenedDocBmp; break; + default: + pRet = bHC ? &aClosedFolderBmpHC : &aClosedFolderBmp; break; + } + + return *pRet; +} + +//------------------------------------------------------------------------- + +PopupMenu* SfxOrganizeListBox_Impl::CreateContextMenu() +{ + return new PopupMenu( *( pDlg->aEditBtn.GetPopupMenu() ) ); +} + +//------------------------------------------------------------------------- + +String SfxOrganizeDlg_Impl::GetPath_Impl( BOOL bOpen, const String& rFileName ) + +/* [Beschreibung] + + Pfad per FileDialog erfragen, f"ur Import / Export von + Dokumentvorlagen + + [Parameter] + + BOOL bOpen Flag: "Offnen / Speichern + const String& rFileName aktueller Dateiname als Vorschlag + + [R"uckgabewert] Dateiname mit Pfad oder Leerstring, wenn + der Benutzer 'Abbrechen' gedr"uckt hat +*/ + +{ + String aPath; + m_sExtension4Save = DEFINE_CONST_UNICODE( "vor" ); + sal_Int16 nDialogType = bOpen + ? com::sun::star::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE + : com::sun::star::ui::dialogs::TemplateDescription::FILESAVE_SIMPLE; + if ( pFileDlg ) + delete pFileDlg; + pFileDlg = new sfx2::FileDialogHelper( nDialogType, 0L ); + + // add "All" filter + pFileDlg->AddFilter( String( SfxResId( STR_SFX_FILTERNAME_ALL ) ), + DEFINE_CONST_UNICODE( FILEDIALOG_FILTER_ALL ) ); + // add template filter + String sFilterName( SfxResId( STR_TEMPLATE_FILTER ) ); + String sFilterExt; + // add filters of modules which are installed + SvtModuleOptions aModuleOpt; + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) ) + sFilterExt += DEFINE_CONST_UNICODE( "*.ott;*.stw;*.oth" ); + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) ) + { + if ( sFilterExt.Len() > 0 ) + sFilterExt += ';'; + sFilterExt += DEFINE_CONST_UNICODE( "*.ots;*.stc" ); + } + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) ) + { + if ( sFilterExt.Len() > 0 ) + sFilterExt += ';'; + sFilterExt += DEFINE_CONST_UNICODE( "*.otp;*.sti" ); + } + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) ) + { + if ( sFilterExt.Len() > 0 ) + sFilterExt += ';'; + sFilterExt += DEFINE_CONST_UNICODE( "*.otg;*.std" ); + } + if ( sFilterExt.Len() > 0 ) + sFilterExt += ';'; + sFilterExt += DEFINE_CONST_UNICODE( "*.vor" ); + + sFilterName += DEFINE_CONST_UNICODE( " (" ); + sFilterName += sFilterExt; + sFilterName += ')'; + pFileDlg->AddFilter( sFilterName, sFilterExt ); + pFileDlg->SetCurrentFilter( sFilterName ); + + if ( aLastDir.Len() || rFileName.Len() ) + { + INetURLObject aObj; + if ( aLastDir.Len() ) + { + aObj.SetURL( aLastDir ); + if ( rFileName.Len() ) + aObj.insertName( rFileName ); + } + else + aObj.SetURL( rFileName ); + + if ( aObj.hasExtension() ) + { + m_sExtension4Save = aObj.getExtension( + INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + aObj.removeExtension(); + } + + DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + pFileDlg->SetDisplayDirectory( aObj.GetMainURL( INetURLObject::NO_DECODE ) ); + } + + pFileDlg->StartExecuteModal( LINK( this, SfxOrganizeDlg_Impl, ImportHdl ) ); + + return aPath; +} + +//------------------------------------------------------------------------- + +::com::sun::star::uno::Sequence< ::rtl::OUString > + SfxOrganizeDlg_Impl::GetPaths_Impl( const String& rFileName ) + +/* [Description] + + Query plural paths by FileDialog, for Import / Export from document + templates + + [Parameter] + + const String& rFileName The default file name when dialog executes + + [Return value] Empty sequence when users have clicked + 'Cancel', a sequence just containing one + file name with path when they have + choosed one file or a sequence containing + path and file names without path +*/ + +{ + ::com::sun::star::uno::Sequence< ::rtl::OUString > aPaths; + m_sExtension4Save = DEFINE_CONST_UNICODE( "vor" ); + if ( pFileDlg ) + delete pFileDlg; + pFileDlg = new sfx2::FileDialogHelper( + com::sun::star::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, SFXWB_MULTISELECTION ); + + // add "All" filter + pFileDlg->AddFilter( String( SfxResId( STR_SFX_FILTERNAME_ALL ) ), + DEFINE_CONST_UNICODE( FILEDIALOG_FILTER_ALL ) ); + + // add template filter + String sFilterName( SfxResId( STR_TEMPLATE_FILTER ) ); + String sFilterExt; + // add filters of modules which are installed + SvtModuleOptions aModuleOpt; + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) ) + sFilterExt += DEFINE_CONST_UNICODE( "*.ott;*.stw;*.oth" ); + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) ) + { + if ( sFilterExt.Len() > 0 ) + sFilterExt += ';'; + sFilterExt += DEFINE_CONST_UNICODE( "*.ots;*.stc" ); + } + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) ) + { + if ( sFilterExt.Len() > 0 ) + sFilterExt += ';'; + sFilterExt += DEFINE_CONST_UNICODE( "*.otp;*.sti" ); + } + if ( aModuleOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) ) + { + if ( sFilterExt.Len() > 0 ) + sFilterExt += ';'; + sFilterExt += DEFINE_CONST_UNICODE( "*.otg;*.std" ); + } + if ( sFilterExt.Len() > 0 ) + sFilterExt += ';'; + sFilterExt += DEFINE_CONST_UNICODE( "*.vor" ); + + sFilterName += DEFINE_CONST_UNICODE( " (" ); + sFilterName += sFilterExt; + sFilterName += ')'; + pFileDlg->AddFilter( sFilterName, sFilterExt ); + pFileDlg->SetCurrentFilter( sFilterName ); + + if ( aLastDir.Len() || rFileName.Len() ) + { + INetURLObject aObj; + if ( aLastDir.Len() ) + { + aObj.SetURL( aLastDir ); + if ( rFileName.Len() ) + aObj.insertName( rFileName ); + } + else + aObj.SetURL( rFileName ); + + if ( aObj.hasExtension() ) + { + m_sExtension4Save = aObj.getExtension( + INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + aObj.removeExtension(); + } + + DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + pFileDlg->SetDisplayDirectory( aObj.GetMainURL( INetURLObject::NO_DECODE ) ); + } + + pFileDlg->StartExecuteModal( LINK( this, SfxOrganizeDlg_Impl, ExportHdl ) ); + + return aPaths; +} + +//------------------------------------------------------------------------- + +BOOL SfxOrganizeDlg_Impl::DontDelete_Impl( SvLBoxEntry* pEntry ) +{ + USHORT nDepth = pFocusBox->GetModel()->GetDepth(pEntry); + if(SfxOrganizeListBox_Impl::VIEW_FILES == + pFocusBox->GetViewType()) + nDepth++; + if( (nDepth > 2 && !pEntry->GetUserData()) || + //Delete ueber GetContent verboten + nDepth==2 || //Vorlage / Konfigurtionsrubrik nicht loeshcen + (nDepth==1 && SfxOrganizeListBox_Impl::VIEW_FILES == + pFocusBox->GetViewType()) || //Files nicht loeschen + (0 == nDepth && pFocusBox->GetLevelCount_Impl(0) < 2)) + //Mindestens eine Vorlage behalten + { + return TRUE; + } + + USHORT nRegion = 0, nIndex = 0; + GetIndices_Impl( pFocusBox, pEntry, nRegion, nIndex ); + const SfxDocumentTemplates* pTemplates = aMgr.GetTemplates(); + if ( !pTemplates || !pTemplates->HasUserContents( nRegion, nIndex ) ) + return TRUE; + + return FALSE; +} + +SvStringsDtor* SfxOrganizeDlg_Impl::GetAllFactoryURLs_Impl( ) const +{ + SvtModuleOptions aModOpt; + const ::com::sun::star::uno::Sequence < ::rtl::OUString >& aServiceNames = aModOpt.GetAllServiceNames() ; + SvStringsDtor* pList = new SvStringsDtor; + sal_Int32 nCount = aServiceNames.getLength(); + for( sal_Int32 i=0; i<nCount; ++i ) + { + if ( SfxObjectFactory::GetStandardTemplate( aServiceNames[i] ).Len() > 0 ) + { + SvtModuleOptions::EFactory eFac = SvtModuleOptions::E_WRITER; + SvtModuleOptions::ClassifyFactoryByName( aServiceNames[i], eFac ); + String* pURL = new String( aModOpt.GetFactoryEmptyDocumentURL( eFac ) ); + pList->Insert( pURL, pList->Count() ); + } + } + + return pList; +} + +sal_Bool SfxOrganizeDlg_Impl::GetServiceName_Impl( String& rName, String& rFileURL ) const +{ + sal_Bool bRet = sal_False; + const SfxDocumentTemplates* pTemplates = aMgr.GetTemplates(); + SvLBoxEntry* pEntry = pFocusBox ? pFocusBox->FirstSelected() : NULL; + USHORT nRegion = 0, nIndex = 0; + GetIndices_Impl( pFocusBox, pEntry, nRegion, nIndex ); + rFileURL = pTemplates->GetPath( nRegion, nIndex ); + if ( rFileURL.Len() > 0 ) + { + try + { + uno::Reference< embed::XStorage > xStorage = ::comphelper::OStorageHelper::GetStorageFromURL( + rFileURL, + embed::ElementModes::READ ); + ULONG nFormat = SotStorage::GetFormatID( xStorage ); + const SfxFilter* pFilter = + SFX_APP()->GetFilterMatcher().GetFilter4ClipBoardId( nFormat ); + if ( pFilter ) + { + rName = pFilter->GetServiceName(); + bRet = TRUE; + } + } + catch( uno::Exception& ) + {} + } + + return bRet; +} + +long SfxOrganizeDlg_Impl::Dispatch_Impl( USHORT nId, Menu* _pMenu ) + +/* [Beschreibung] + + Verarbeiten der Events aus MenuButton oder Accelerator + + [Parameter] + + USHORT nId ID des Events + + [R"uckgabewert] 1: Event wurde verarbeitet, + 0: Event wurde nicht verarbeitet (SV-Menu) + +*/ + +{ + SuspendAccel aTmp(&aEditAcc); + SvLBoxEntry *pEntry = pFocusBox? pFocusBox->FirstSelected(): 0; + sal_Bool bHandled = sal_True; + switch(nId) + { + case ID_NEW: + { + if(!pEntry) + return 1; + if(pFocusBox->GetViewType() == SfxOrganizeListBox_Impl::VIEW_TEMPLATES) + { + if(0 == pFocusBox->GetModel()->GetDepth(pEntry)) + { + const String aNoName( SfxResId(STR_NONAME) ); + SvLBoxEntry* pParent = pFocusBox->GetParent(pEntry); + String aName(aNoName); + USHORT n = 1; + while(!pFocusBox->IsUniqName_Impl(aName, pParent)) + { + aName = aNoName; + aName += String::CreateFromInt32( n++ ); + } + aMgr.InsertDir( pFocusBox, aName, + (USHORT)pFocusBox->GetModel()->GetRelPos(pEntry)+1); + } + } + break; + } + + case ID_DELETE: + { + if(!pEntry || DontDelete_Impl(pEntry)) + return 1; + const USHORT nDepth = pFocusBox->GetModel()->GetDepth(pEntry); + if(nDepth < 2) + { + if(0 == nDepth && pFocusBox->GetLevelCount_Impl(0) < 2) return 1; + if(SfxOrganizeListBox_Impl::VIEW_TEMPLATES == pFocusBox->GetViewType()) + { + USHORT nResId = nDepth? STR_DELETE_TEMPLATE : + STR_DELETE_REGION; + if( !QueryDelete_Impl( + pDialog, nResId, pFocusBox->GetEntryText(pEntry))) + return 1; + if ( STR_DELETE_REGION == nResId && + pFocusBox->GetChildCount(pEntry)) + { + QueryBox aQBox(pDialog, SfxResId(MSG_REGION_NOTEMPTY)); + if(RET_NO == aQBox.Execute()) + return 1; + } + USHORT nRegion = 0, nIndex = 0; + GetIndices_Impl(pFocusBox, pEntry, nRegion, nIndex); + + USHORT nDeleteInd = ( STR_DELETE_REGION == nResId? USHRT_MAX: nIndex ); + if ( !aMgr.Delete( pFocusBox, nRegion, nDeleteInd ) ) + ErrorDelete_Impl( + pDialog, + pFocusBox->GetEntryText(pEntry), + ( nDeleteInd == USHRT_MAX && pFocusBox->GetChildCount(pEntry) ) ); + } + } + // Inhaltsformen + else if(nDepth + pFocusBox->GetDocLevel() >= 2) + { + if(!QueryDelete_Impl(pDialog, STR_DELETE_TEMPLATE, pFocusBox->GetEntryText(pEntry))) + return 1; + Path aPath(pFocusBox, pEntry); + SfxObjectShellRef aRef = pFocusBox->GetObjectShell(aPath); + if(aRef.Is() && + aRef->Remove(aPath[1+pFocusBox->GetDocLevel()], + aPath[2+pFocusBox->GetDocLevel()], + aPath[3+pFocusBox->GetDocLevel()])) + pFocusBox->GetModel()->Remove(pEntry); + else + ErrorDelete_Impl(pDialog, pFocusBox->GetEntryText(pEntry), sal_False ); + } + break; + } + + case ID_EDIT: + { + if(!pEntry) + return 1; + USHORT nRegion = 0, nIndex = 0; + GetIndices_Impl( pFocusBox, pEntry, nRegion, nIndex ); + const SfxStringItem aName( SID_FILE_NAME, aMgr.GetTemplates()->GetPath( nRegion, nIndex ) ); + const SfxStringItem aLongName( SID_FILE_LONGNAME, pFocusBox->GetEntryText( pEntry ) ); + const SfxStringItem aReferer( SID_REFERER, DEFINE_CONST_UNICODE( "private:user" ) ); + const SfxStringItem aTargetName( SID_TARGETNAME, DEFINE_CONST_UNICODE( "_default" ) ); + const SfxBoolItem aTemplateIndicator( SID_TEMPLATE, sal_False ); + + SFX_APP()->GetAppDispatcher_Impl()->Execute( SID_OPENTEMPLATE, SFX_CALLMODE_ASYNCHRON | SFX_CALLMODE_RECORD, + &aName, &aLongName, &aReferer, &aTargetName, &aTemplateIndicator, 0L ); + pDialog->EndDialog( RET_EDIT_STYLE ); + break; + } + + case ID_COPY_FROM: + { + if ( !pEntry ) + return 1; + m_nRegion = 0; + m_nIndex = 0; + GetIndices_Impl( pFocusBox, pEntry, m_nRegion, m_nIndex ); + GetPaths_Impl( String() ); + break; + } + + case ID_COPY_TO: + { + if ( !pEntry ) + return 1; + m_nRegion = 0; + m_nIndex = 0; + GetIndices_Impl( pFocusBox, pEntry, m_nRegion, m_nIndex ); + GetPath_Impl( FALSE, aMgr.GetTemplates()->GetFileName( m_nRegion, m_nIndex ) ); + break; + } + + case ID_RESCAN: + if ( !aMgr.Rescan() ) + ErrorBox( pDialog, SfxResId( MSG_ERROR_RESCAN ) ).Execute(); + if ( SfxOrganizeListBox_Impl::VIEW_TEMPLATES == aLeftLb.GetViewType() ) + aLeftLb.Reset(); + if ( SfxOrganizeListBox_Impl::VIEW_TEMPLATES == aRightLb.GetViewType() ) + aRightLb.Reset(); + break; + + case ID_PRINT: + { + if ( !pEntry ) + return 1; + Path aPath( pFocusBox, pEntry ); + SfxObjectShellRef aRef = pFocusBox->GetObjectShell( aPath ); + if ( aRef.Is() ) + { + const USHORT nDocLevel = pFocusBox->GetDocLevel(); + if ( !pPrt ) + pPrt = new Printer; + SvLBoxEntry *pDocEntry = pEntry; + while ( pFocusBox->GetModel()->GetDepth( pDocEntry ) > nDocLevel ) + pDocEntry = pFocusBox->GetParent( pDocEntry ); + const String aName(pFocusBox->GetEntryText(pDocEntry)); + if ( !aRef->Print( *pPrt, aPath[1+nDocLevel], + aPath[2+nDocLevel], aPath[3+nDocLevel], &aName ) ) + ErrorBox( pDialog, SfxResId( MSG_PRINT_ERROR ) ).Execute(); + } + break; + } + + case ID_PRINTER_SETUP: + { + PrinterSetupDialog* pDlg = new PrinterSetupDialog( pDialog ); + if ( !pPrt ) + pPrt = new Printer; + pDlg->SetPrinter( pPrt ); + pDlg->Execute(); + delete pDlg; + break; + } + + case ID_DEFAULT_TEMPLATE: + { + String aServiceName, aFileURL; + if ( GetServiceName_Impl( aServiceName, aFileURL ) ) + SfxObjectFactory::SetStandardTemplate( aServiceName, aFileURL ); + break; + } + + default: + bHandled = sal_False; + } + + if ( !bHandled && ( nId > ID_RESET_DEFAULT_TEMPLATE || nId <= ID_RESET_DEFAULT_TEMPLATE_END ) ) + { + Menu* pSubMenu = _pMenu ? _pMenu : aEditBtn.GetPopupMenu()->GetPopupMenu( ID_RESET_DEFAULT_TEMPLATE ); + if ( pSubMenu ) + { + String aServiceName = SfxObjectShell::GetServiceNameFromFactory( pSubMenu->GetItemCommand( nId ) ); + SfxObjectFactory::SetStandardTemplate( aServiceName, String() ); + bHandled = sal_True; + } + } + + return bHandled ? 1 : 0; +} + +//------------------------------------------------------------------------- + +IMPL_LINK_INLINE_START( SfxOrganizeDlg_Impl, MenuSelect_Impl, Menu *, pMenu ) + +/* [Beschreibung] + + SelectHandler des Men"us des Men"ubuttons (SV) + + [Parameter] + + MenuButton *pBtn der das Event ausl"osende Button + + [R"uckgabewert] 1: Event wurde verarbeitet, + 0: Event wurde nicht verarbeitet (SV-Menu) + +*/ +{ + return Dispatch_Impl( pMenu->GetCurItemId(), pMenu ); +} +IMPL_LINK_INLINE_END( SfxOrganizeDlg_Impl, MenuSelect_Impl, Menu *, pMenu ) + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxOrganizeDlg_Impl, AccelSelect_Impl, Accelerator *, pAccel ) + +/* [Beschreibung] + + SelectHandler des Accelerators (SV) + + [Parameter] + + Accelerator *pAccel der das Event ausl"osende Accelerator + + [R"uckgabewert] 1: Event wurde verarbeitet, + 0: Event wurde nicht verarbeitet (SV) + +*/ + +{ + SvLBoxEntry* pEntry = pFocusBox && pFocusBox->GetSelectionCount() ? + pFocusBox->FirstSelected() : NULL ; + return pEntry && ( pAccel->GetCurItemId() == ID_NEW || !DontDelete_Impl( pEntry ) ) ? + Dispatch_Impl( pAccel->GetCurItemId(), NULL ) : 0; +} + +//------------------------------------------------------------------------- + +void SfxOrganizeDlg_Impl::OkHdl(Button *pButton) +{ + if(pFocusBox && pFocusBox->IsEditingActive()) + pFocusBox->EndEditing(FALSE); + pButton->Click(); +} + + + +IMPL_LINK( SfxOrganizeDlg_Impl, MenuActivate_Impl, Menu *, pMenu ) + +/* [Beschreibung] + + ActivateHandler des Men"us des Men"ubuttons (SV) + + [Parameter] + + Menu *pMenu das das Event ausl"osende Men"u + + [R"uckgabewert] 1: Event wurde verarbeitet, + 0: Event wurde nicht verarbeitet (SV-Menu) + +*/ +{ + if ( pFocusBox && pFocusBox->IsEditingActive() ) + pFocusBox->EndEditing( FALSE ); + BOOL bEnable = ( pFocusBox && pFocusBox->GetSelectionCount() ); + SvLBoxEntry* pEntry = bEnable ? pFocusBox->FirstSelected() : NULL; + const USHORT nDepth = + ( bEnable && pFocusBox->GetSelectionCount() ) ? pFocusBox->GetModel()->GetDepth( pEntry ) : 0; + const USHORT nDocLevel = bEnable ? pFocusBox->GetDocLevel() : 0; + int eVT = pFocusBox ? pFocusBox->GetViewType() : 0; + // nur Vorlagen anlegen + pMenu->EnableItem( ID_NEW, bEnable && 0 == nDepth && SfxOrganizeListBox_Impl::VIEW_TEMPLATES == eVT ); + // Vorlagen: Loeschen Ebene 0,1,3ff + // ein Bereich mu"s mindestens erhalten bleiben + // Dateien : Loeschen Ebene > 2 + + pMenu->EnableItem( ID_DELETE, bEnable && !DontDelete_Impl( pEntry ) ); + pMenu->EnableItem( ID_EDIT, + bEnable && eVT == SfxOrganizeListBox_Impl::VIEW_TEMPLATES && nDepth == nDocLevel + && !DontDelete_Impl( pEntry ) ); + pMenu->EnableItem( ID_COPY_FROM, + bEnable && eVT == SfxOrganizeListBox_Impl::VIEW_TEMPLATES && + ( nDepth == nDocLevel || nDepth == nDocLevel - 1 ) ); + pMenu->EnableItem( ID_COPY_TO, + bEnable && eVT == SfxOrganizeListBox_Impl::VIEW_TEMPLATES && + nDepth == nDocLevel ); + pMenu->EnableItem( ID_RESCAN, + SfxOrganizeListBox_Impl::VIEW_TEMPLATES == aRightLb.GetViewType() || + SfxOrganizeListBox_Impl::VIEW_TEMPLATES == aLeftLb.GetViewType() ); + BOOL bPrint = bEnable && nDepth > pFocusBox->GetDocLevel(); + if ( bPrint && pPrt ) + bPrint = !pPrt->IsPrinting() && !pPrt->IsJobActive(); + if ( bPrint && bEnable ) + { + // only styles printable + Path aPath( pFocusBox, pFocusBox->FirstSelected() ); + USHORT nIndex = aPath[ nDocLevel + 1 ]; + bPrint = ( nIndex == CONTENT_STYLE ); + } + pMenu->EnableItem( ID_PRINT, bPrint ); + + if ( bEnable && eVT == SfxOrganizeListBox_Impl::VIEW_TEMPLATES && nDepth == nDocLevel ) + { + String aFactoryURL, aFileURL; + bEnable = GetServiceName_Impl( aFactoryURL, aFileURL ); + } + else if ( bEnable ) + bEnable = FALSE; + pMenu->EnableItem( ID_DEFAULT_TEMPLATE, bEnable ); + + bEnable = sal_True; + SvStringsDtor* pList = GetAllFactoryURLs_Impl(); + USHORT nCount = pList->Count(); + if ( nCount > 0 ) + { + PopupMenu* pSubMenu = new PopupMenu; + USHORT nItemId = ID_RESET_DEFAULT_TEMPLATE + 1; + for ( USHORT i = 0; i < nCount; ++i ) + { + String aObjFacURL( *pList->GetObject(i) ); + String aTitle = SvFileInformationManager::GetDescription( + INetURLObject(aObjFacURL) ); + pSubMenu->InsertItem( nItemId, aTitle, + SvFileInformationManager::GetImage(INetURLObject(aObjFacURL)) ); + pSubMenu->SetItemCommand( nItemId++, aObjFacURL ); + DBG_ASSERT( nItemId <= ID_RESET_DEFAULT_TEMPLATE_END, "menu item id overflow" ); + } + pMenu->SetPopupMenu( ID_RESET_DEFAULT_TEMPLATE, pSubMenu ); + } + else + bEnable = sal_False; + + delete pList; + pMenu->EnableItem( ID_RESET_DEFAULT_TEMPLATE, bEnable ); + + return 1; +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxOrganizeDlg_Impl, GetFocus_Impl, SfxOrganizeListBox_Impl *, pBox ) + +/* [Beschreibung] + + GetFocus-Handler, wird aus den Select-Handler der Listboxen + gerufen. + Wird verwendet, im die Listbox, die den Focus besitzt sowie + deren Zustand zu ermitteln. + + [Parameter] + + SfxOrganizeListBox *pBox die rufende Box + +*/ + +{ + if(pFocusBox && pFocusBox != pBox) + pFocusBox->SelectAll(FALSE); + pFocusBox = pBox; + aFilesBtn.Enable( SfxOrganizeListBox_Impl::VIEW_FILES == + pFocusBox->GetViewType() ); + return 0; +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxOrganizeDlg_Impl, LeftListBoxSelect_Impl, ListBox *, pBox ) + +/* [Beschreibung] + + Select-Handler, wird aus den Select-Handler der Listboxen + gerufen. + Wenn sich der Modus der Boxen (Dokumentsicht, Dokumentvorlagensicht) + unterscheiden, werden die Models getrennt; andernfalls zusammengefa"st. + + [Parameter] + + ListBox *pBox die rufende Box + +*/ +{ + const SfxOrganizeListBox_Impl::DataEnum + eViewType = pBox->GetSelectEntryPos() == 0 ? + SfxOrganizeListBox_Impl::VIEW_TEMPLATES : SfxOrganizeListBox_Impl::VIEW_FILES; + if(eViewType!= aLeftLb.GetViewType()) { + aLeftLb.SetViewType(eViewType); + if(aRightLb.GetViewType() == eViewType) + aLeftLb.SetModel(aRightLb.GetModel()); + else { + // Models trennen + aLeftLb.DisconnectFromModel(); + aLeftLb.Reset(); + } + } + GetFocus_Impl(&aLeftLb); + return 0; +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxOrganizeDlg_Impl, RightListBoxSelect_Impl, ListBox *, pBox ) + +/* [Beschreibung] + + Select-Handler, wird aus den Select-Handler der Listboxen + gerufen. + Wenn sich der Modus der Boxen (Dokumentsicht, Dokumentvorlagensicht) + unterscheiden, werden die Models getrennt; andernfalls zusammengefa"st. + + [Parameter] + + ListBox *pBox die rufende Box + +*/ +{ + const SfxOrganizeListBox_Impl::DataEnum eViewType = + pBox->GetSelectEntryPos() == 0 ? + SfxOrganizeListBox_Impl::VIEW_TEMPLATES : SfxOrganizeListBox_Impl::VIEW_FILES; + if(eViewType!= aRightLb.GetViewType()) + { + aRightLb.SetViewType(eViewType); + if(aLeftLb.GetViewType() == eViewType) + aRightLb.SetModel(aLeftLb.GetModel()); + else + { + // Models trennen + aRightLb.DisconnectFromModel(); + aRightLb.Reset(); + } + } + aRightLb.GrabFocus(); + GetFocus_Impl(&aRightLb); + return 0; +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxOrganizeDlg_Impl, OnAddressTemplateClicked, Button *, pButton ) +{ + (void)pButton; //unused + svt::AddressBookSourceDialog aDialog(pDialog, ::comphelper::getProcessServiceFactory()); + aDialog.Execute(); + return 0L; +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxOrganizeDlg_Impl, AddFiles_Impl, Button *, pButton ) + +/* [Beschreibung] + + Handler des Buttons f"ur das Hinzuf"ugen von Dateien per Dialog. + + [Parameter] + + Button * der Button, der dieses Events ausgel"ost hat. + +*/ +{ + (void)pButton; //unused + if ( pFileDlg ) + delete pFileDlg; + pFileDlg = new sfx2::FileDialogHelper( WB_OPEN, String() ); + + // add config and basic filter + static String sOpenBracket( DEFINE_CONST_UNICODE( " (" ) ); + static String sCloseBracket( DEFINE_CONST_UNICODE( ")" ) ); + static String sConfigExt( DEFINE_CONST_UNICODE( "*.cfg" ) ); + static String sBasicExt( DEFINE_CONST_UNICODE( "*.sbl" ) ); + + String sFilterName( SfxResId( RID_STR_FILTCONFIG ) ); + sFilterName += sOpenBracket; + sFilterName += sConfigExt; + sFilterName += sCloseBracket; + pFileDlg->AddFilter( sFilterName, sConfigExt ); + + sFilterName = String( SfxResId( RID_STR_FILTBASIC ) ); + sFilterName += sOpenBracket; + sFilterName += sBasicExt; + sFilterName += sCloseBracket; + pFileDlg->AddFilter( sFilterName, sBasicExt ); + + // set "All" filter as current + pFileDlg->SetCurrentFilter( String( SfxResId( STR_SFX_FILTERNAME_ALL ) ) ); + + if ( aLastDir.Len() ) + pFileDlg->SetDisplayDirectory( aLastDir ); + + pFileDlg->StartExecuteModal( LINK( this, SfxOrganizeDlg_Impl, AddFilesHdl ) ); + + return 0; +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxOrganizeDlg_Impl, ImportHdl, sfx2::FileDialogHelper *, EMPTYARG ) +{ + DBG_ASSERT( pFileDlg, "SfxOrganizeDlg_Impl::ImportHdl(): no file dialog" ); + + if ( ERRCODE_NONE == pFileDlg->GetError() ) + { + String aPath = pFileDlg->GetPath(); + INetURLObject aObj( aPath ); + + // we want to keep the original extension when exporting, the file open dialog + // always sets the extension to *.vor + if ( pFileDlg->GetDialogType() == + com::sun::star::ui::dialogs::TemplateDescription::FILESAVE_SIMPLE ) + { + if ( aObj.hasExtension() ) + aObj.removeExtension(); + + aObj.setExtension( m_sExtension4Save ); + aPath = aObj.GetMainURL( INetURLObject::DECODE_TO_IURI ); + } + + aObj.removeSegment(); + aLastDir = aObj.GetMainURL( INetURLObject::DECODE_TO_IURI ); + + if ( aPath.Len() && !aMgr.CopyTo( m_nRegion, m_nIndex, aPath ) ) + { + String aText( SfxResId( STR_ERROR_COPY_TEMPLATE ) ); + aText.SearchAndReplaceAscii( "$1", aPath ); + ErrorBox( pDialog, WB_OK, aText ).Execute(); + } + } + + return 0L; +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxOrganizeDlg_Impl, ExportHdl, sfx2::FileDialogHelper *, EMPTYARG ) +{ + DBG_ASSERT( pFileDlg, "SfxOrganizeDlg_Impl::ImportHdl(): no file dialog" ); + ::com::sun::star::uno::Sequence< ::rtl::OUString > aPaths; + + if ( ERRCODE_NONE == pFileDlg->GetError() ) + { + aPaths = pFileDlg->GetMPath(); + sal_Int32 lastCount = aPaths.getLength() - 1; + INetURLObject aObj( aPaths.getArray()[ lastCount ] ); + + aObj.removeSegment(); + aLastDir = aObj.GetMainURL( INetURLObject::DECODE_TO_IURI ); + } + + sal_Int32 nCount = aPaths.getLength(); + if ( 1 == nCount ) + { + String aPath = String( aPaths.getArray()[0] ); + if ( aPath.Len() && !aMgr.CopyFrom( pFocusBox, m_nRegion, m_nIndex, aPath ) ) + { + String aText( SfxResId( STR_ERROR_COPY_TEMPLATE ) ); + aText.SearchAndReplaceAscii( "$1", aPath ); + ErrorBox( pDialog, WB_OK, aText ).Execute(); + } + } + else if ( nCount > 1 ) + { + INetURLObject aPathObj( aPaths[0] ); + aPathObj.setFinalSlash(); + for ( USHORT i = 1; i < nCount; ++i ) + { + if ( 1 == i ) + aPathObj.Append( aPaths[i] ); + else + aPathObj.setName( aPaths[i] ); + String aPath = aPathObj.GetMainURL( INetURLObject::NO_DECODE ); + if ( aPath.Len() && !aMgr.CopyFrom( pFocusBox, m_nRegion, m_nIndex, aPath ) ) + { + String aText( SfxResId( STR_ERROR_COPY_TEMPLATE ) ); + aText.SearchAndReplaceAscii( "$1", aPath ); + ErrorBox( pDialog, WB_OK, aText ).Execute(); + } + } + } + + return 0L; +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxOrganizeDlg_Impl, AddFilesHdl, sfx2::FileDialogHelper *, EMPTYARG ) +{ + if ( ERRCODE_NONE == pFileDlg->GetError() ) + { + String aPath = pFileDlg->GetPath(); + aMgr.InsertFile( pFocusBox, aPath ); + INetURLObject aObj( aPath ); + aObj.removeSegment(); + aObj.setFinalSlash(); + aLastDir = aObj.GetMainURL( INetURLObject::DECODE_TO_IURI ); + } + + return 0L; +} + +//------------------------------------------------------------------------- + +short SfxTemplateOrganizeDlg::Execute() + +/* [Beschreibung] + + "Uberladene Execute- Methode; speichert gfs. "Anderungen an den + Dokumentvorlagen + (SV-Methode) + +*/ + +{ + const short nRet = ModalDialog::Execute(); + if(RET_CANCEL != nRet) + { + pImp->aMgr.SaveAll(this); + SfxTemplateDialog* pTemplDlg = SFX_APP()->GetTemplateDialog(); + if(pTemplDlg) + pTemplDlg->Update(); + } + return nRet; +} + + +//------------------------------------------------------------------------- + +SfxTemplateOrganizeDlg::SfxTemplateOrganizeDlg(Window * pParent, + SfxDocumentTemplates *pTempl) +: ModalDialog( pParent, SfxResId(DLG_ORGANIZE)), + pImp( new SfxOrganizeDlg_Impl(this, pTempl) ) + +/* [Beschreibung] + + Konstruktor + +*/ +{ + FreeResource(); +} + +//------------------------------------------------------------------------- + +SfxTemplateOrganizeDlg::~SfxTemplateOrganizeDlg() +{ + GetpApp()->RemoveAccel(&pImp->aEditAcc); + delete pImp->pPrt; + delete pImp; +} + diff --git a/sfx2/source/doc/docvor.hrc b/sfx2/source/doc/docvor.hrc new file mode 100644 index 000000000000..842aa73fb8a3 --- /dev/null +++ b/sfx2/source/doc/docvor.hrc @@ -0,0 +1,75 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define IMG_OPENED_FOLDER 2 +#define IMG_CLOSED_FOLDER 1 +#define IMG_OPENED_DOC 3 +#define IMG_CLOSED_DOC 4 +#define IMG_OPENED_FOLDER_HC 5 +#define IMG_CLOSED_FOLDER_HC 6 +#define IMG_OPENED_DOC_HC 7 +#define IMG_CLOSED_DOC_HC 8 + +#define ACC_EDIT 1 +#define ID_COPY 201 +#define ID_MOVE 202 +#define ID_DELETE 203 +#define ID_EDIT 204 +#define ID_COPY_FROM 211 +#define ID_EXPORT 221 +#define ID_RESCAN 220 +#define ID_COPY_TO 210 +#define ID_NEW 200 +#define ID_PRINT 240 +#define ID_PRINTER_SETUP 2341 + +#define ID_DEFAULT_TEMPLATE 300 +#define ID_RESET_DEFAULT_TEMPLATE 301 +//!!! dont use the ids from 302 to 350, we need them as dynamic ids +#define ID_RESET_DEFAULT_TEMPLATE_END (ID_RESET_DEFAULT_TEMPLATE+49) + +#define LB_RIGHT_TYP 11 +#define LB_RIGHT 10 +#define LB_LEFT_TYP 2 +#define BTN_EDIT 105 +#define BTN_FILES 3 +#define BTN_ADDRESSTEMPLATE 4 +#define LB_LEFT 1 +#define FT_DEFAULT_TEMPLATE_LABEL 20 +#define FT_DEFAULT_TEMPLATE 21 +#define BTN_HELP 100 + +#ifdef BTN_OK +#undef BTN_OK +#endif +#define BTN_OK 100 + +#ifdef BTN_CANCEL +#undef BTN_CANCEL +#endif +#define BTN_CANCEL 101 + diff --git a/sfx2/source/doc/docvor.src b/sfx2/source/doc/docvor.src new file mode 100644 index 000000000000..2c9975de9bb8 --- /dev/null +++ b/sfx2/source/doc/docvor.src @@ -0,0 +1,315 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + // include --------------------------------------------------------------- +#include <sfx2/sfx.hrc> +#include "doc.hrc" +#include "docvor.hrc" +#include "helpid.hrc" +// pragma ---------------------------------------------------------------- + +// DLG_ORGANIZE ---------------------------------------------------------- + +#define MASKCOLOR MaskColor = Color { Red = 0xFFFF ; Green = 0x0000 ; Blue = 0xFFFF ; } + +ModalDialog DLG_ORGANIZE +{ + HelpId = SID_ORGANIZER ; + OutputSize = TRUE ; + SVLook = TRUE ; + Size = MAP_APPFONT ( 271 , 162 ) ; + Text [ en-US ] = "Template Management" ; + Moveable = TRUE ; + HelpButton BTN_HELP + { + Pos = MAP_APPFONT ( 205 , 43 ) ; + Size = MAP_APPFONT ( 60 , 14 ) ; + TabStop = TRUE ; + }; + OKButton BTN_OK + { + Pos = MAP_APPFONT ( 205 , 6 ) ; + Size = MAP_APPFONT ( 60 , 14 ) ; + /* ### ACHTUNG: Neuer Text in Resource? Schließen : Schlie˜en */ + /* ### ACHTUNG: Neuer Text in Resource? Schließen : Schlie˜en */ + Text [ en-US ] = "Close" ; + TabStop = TRUE ; + DefButton = TRUE ; + }; + PushButton BTN_FILES + { + Pos = MAP_APPFONT ( 205 , 143 ) ; + Size = MAP_APPFONT ( 60 , 14 ) ; + Text [ en-US ] = "~File..." ; + TabStop = TRUE ; + }; + PushButton BTN_ADDRESSTEMPLATE + { + Pos = MAP_APPFONT ( 205 , 124 ) ; + Size = MAP_APPFONT ( 60 , 14 ) ; + Text [ en-US ] = "~Address Book..." ; + }; + ListBox LB_LEFT_TYP + { + Border = TRUE ; + Pos = MAP_APPFONT ( 3 , 144 ) ; + Size = MAP_APPFONT ( 94 , 55 ) ; + TabStop = TRUE ; + DropDown = TRUE ; + CurPos = 0 ; + StringList [ en-US ] = + { + < "Templates" ; Default ; > ; + < "Documents" ; Default ; > ; + }; + }; + ListBox LB_RIGHT_TYP + { + Border = TRUE ; + Pos = MAP_APPFONT ( 103 , 144 ) ; + Size = MAP_APPFONT ( 94 , 55 ) ; + TabStop = TRUE ; + DropDown = TRUE ; + CurPos = 1 ; + StringList [ en-US ] = + { + < "Templates" ; Default ; > ; + < "Documents" ; Default ; > ; + }; + }; + Control LB_LEFT + { + HelpId = HID_CTL_ORGANIZER_LEFT ; + Border = TRUE ; + Pos = MAP_APPFONT ( 3 , 6 ) ; + Size = MAP_APPFONT ( 94 , 132 ) ; + TabStop = TRUE ; + ClipChildren = TRUE ; + }; + Control LB_RIGHT + { + HelpId = HID_CTL_ORGANIZER_RIGHT ; + Border = TRUE ; + Pos = MAP_APPFONT ( 103 , 6 ) ; + Size = MAP_APPFONT ( 94 , 132 ) ; + TabStop = TRUE ; + ClipChildren = TRUE ; + }; + Accelerator ACC_EDIT + { + ItemList = + { + AcceleratorItem + { + Identifier = ID_NEW ; + Key = KeyCode + { + Code = KEY_INSERT ; + }; + }; + AcceleratorItem + { + Identifier = ID_DELETE ; + Key = KeyCode + { + Code = KEY_DELETE ; + }; + }; + }; + }; + MenuButton BTN_EDIT + { + Pos = MAP_APPFONT ( 205 , 23 ) ; + Size = MAP_APPFONT ( 60 , 14 ) ; + Text [ en-US ] = "Commands" ; + TabStop = TRUE ; + ButtonMenu = Menu + { + ItemList = + { + MenuItem + { + Identifier = ID_NEW ; + HelpId = HID_ORGANIZE_NEW ; + Text [ en-US ] = "~New" ; + AccelKey = KeyCode + { + Code = KEY_INSERT ; + }; + }; + MenuItem + { + Identifier = ID_DELETE ; + HelpId = HID_ORGANIZE_DELETE ; + /* ### ACHTUNG: Neuer Text in Resource? ~Löschen : ~L÷schen */ + /* ### ACHTUNG: Neuer Text in Resource? ~Löschen : ~L÷schen */ + Text [ en-US ] = "~Delete" ; + AccelKey = KeyCode + { + Code = KEY_DELETE ; + }; + }; + MenuItem + { + Identifier = ID_EDIT ; + HelpId = HID_ORGANIZE_EDIT ; + Text [ en-US ] = "~Edit" ; + }; + MenuItem + { + Separator = TRUE ; + }; + MenuItem + { + Identifier = ID_COPY_FROM ; + HelpId = HID_ORGANIZE_COPY_FROM ; + Text [ en-US ] = "Import Template..." ; + }; + MenuItem + { + Identifier = ID_COPY_TO ; + HelpId = HID_ORGANIZE_COPY_TO ; + Text [ en-US ] = "Export Template..." ; + }; + MenuItem + { + Separator = TRUE ; + }; + MenuItem + { + Identifier = ID_PRINT ; + HelpId = HID_ORGANIZE_PRINT ; + Text [ en-US ] = "~Print" ; + }; + MenuItem + { + Identifier = ID_PRINTER_SETUP ; + HelpId = HID_ORGANIZE_PRINTER_SETUP ; + Text [ en-US ] = "Printer Settings..." ; + }; + MenuItem + { + Separator = TRUE ; + }; + MenuItem + { + Identifier = ID_RESCAN ; + HelpId = HID_ORGANIZE_RESCAN ; + Text [ en-US ] = "Update" ; + }; + MenuItem + { + Separator = TRUE ; + }; + MenuItem + { + Identifier = ID_DEFAULT_TEMPLATE ; + HelpId = HID_ORGANIZE_STDTEMPLATE_ADD ; + Text [ en-US ] = "Set As Default Template" ; + }; + MenuItem + { + Identifier = ID_RESET_DEFAULT_TEMPLATE ; + HelpId = HID_ORGANIZE_STDTEMPLATE_DEL ; + Text [ en-US ] = "Reset Default Template" ; + }; + }; + }; + }; + Image IMG_OPENED_FOLDER + { + MASKCOLOR ; + ImageBitmap = Bitmap { File = "folderop.bmp" ; } ; + }; + Image IMG_CLOSED_FOLDER + { + MASKCOLOR ; + ImageBitmap = Bitmap { File = "foldercl.bmp" ; } ; + }; + Image IMG_OPENED_DOC + { + MASKCOLOR ; + ImageBitmap = Bitmap { File = "doccl.bmp" ; } ; + }; + Image IMG_CLOSED_DOC + { + MASKCOLOR ; + ImageBitmap = Bitmap { File = "doccl.bmp" ; } ; + }; + Image IMG_OPENED_FOLDER_HC + { + MASKCOLOR ; + ImageBitmap = Bitmap { File = "folderop_h.bmp" ; } ; + }; + Image IMG_CLOSED_FOLDER_HC + { + MASKCOLOR ; + ImageBitmap = Bitmap { File = "foldercl_h.bmp" ; } ; + }; + Image IMG_OPENED_DOC_HC + { + MASKCOLOR ; + ImageBitmap = Bitmap { File = "doccl_h.bmp" ; } ; + }; + Image IMG_CLOSED_DOC_HC + { + MASKCOLOR ; + ImageBitmap = Bitmap { File = "doccl_h.bmp" ; } ; + }; + /* FixedText FT_DEFAULT_TEMPLATE_LABEL + { + Pos = MAP_APPFONT ( 3 , 161 ) ; + Size = MAP_APPFONT ( 61 , 10 ) ; + Text [ en-US ] = "Default template:" ; + }; + FixedText FT_DEFAULT_TEMPLATE + { + Pos = MAP_APPFONT ( 66 , 161 ) ; + Size = MAP_APPFONT ( 131 , 10 ) ; + };*/ +}; + // ********************************************************************** EOF + + + + + + + + + + + + + + + + + + + + + diff --git a/sfx2/source/doc/frmdescr.cxx b/sfx2/source/doc/frmdescr.cxx new file mode 100644 index 000000000000..04c3e78a7e7b --- /dev/null +++ b/sfx2/source/doc/frmdescr.cxx @@ -0,0 +1,329 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include <sot/object.hxx> +#include <tools/stream.hxx> +#include <vcl/splitwin.hxx> +#include <svl/itemset.hxx> +#ifndef GCC +#endif + +#include <sfx2/frmdescr.hxx> +#include <sfx2/app.hxx> + +DBG_NAME(SfxFrameDescriptor); + +#define VERSION (USHORT) 3 + +struct SfxFrameDescriptor_Impl +{ + Wallpaper* pWallpaper; + SfxItemSet* pArgs; + BOOL bEditable; + + SfxFrameDescriptor_Impl() : pWallpaper( NULL ), pArgs( NULL ), bEditable( TRUE ) {} + ~SfxFrameDescriptor_Impl() + { + delete pWallpaper; + delete pArgs; + } +}; + +SfxFrameDescriptor::SfxFrameDescriptor() : + aMargin( -1, -1 ), + nWidth( 0L ), + eScroll( ScrollingAuto ), + eSizeSelector( SIZE_ABS ), + nHasBorder( BORDER_YES ), + nItemId( 0 ), + bResizeHorizontal( TRUE ), + bResizeVertical( TRUE ), + bHasUI( TRUE ), + bReadOnly( FALSE ) +{ + DBG_CTOR(SfxFrameDescriptor, 0); + + pImp = new SfxFrameDescriptor_Impl; +} + +SfxFrameDescriptor::~SfxFrameDescriptor() +{ + DBG_DTOR(SfxFrameDescriptor, 0); + delete pImp; +} + +SfxItemSet* SfxFrameDescriptor::GetArgs() +{ + if( !pImp->pArgs ) + pImp->pArgs = new SfxAllItemSet( SFX_APP()->GetPool() ); + return pImp->pArgs; +} + +void SfxFrameDescriptor::SetURL( const String& rURL ) +{ + aURL = INetURLObject(rURL); + SetActualURL( aURL ); +} + +void SfxFrameDescriptor::SetURL( const INetURLObject& rURL ) +{ + aURL = rURL.GetMainURL( INetURLObject::DECODE_TO_IURI ); + SetActualURL( aURL ); +} + +void SfxFrameDescriptor::SetActualURL( const String& rURL ) +{ + aActualURL = INetURLObject(rURL); + if ( pImp->pArgs ) + pImp->pArgs->ClearItem(); +} + +void SfxFrameDescriptor::SetActualURL( const INetURLObject& rURL ) +{ + SetActualURL(String(rURL.GetMainURL( INetURLObject::DECODE_TO_IURI ))); +} + +void SfxFrameDescriptor::SetEditable( BOOL bSet ) +{ + pImp->bEditable = bSet; +} + +BOOL SfxFrameDescriptor::IsEditable() const +{ + return pImp->bEditable; +} + +BOOL SfxFrameDescriptor::CompareOriginal( SfxFrameDescriptor& rDescr ) const +{ + if( aURL != rDescr.aURL ) + return FALSE; + else + return TRUE; +} + +BOOL SfxFrameDescriptor::CheckContent() const +{ + BOOL bRet = !( aURL == aActualURL ); + return bRet; +} + +void SfxFrameDescriptor::UnifyContent( BOOL bTakeActual ) +{ + if ( bTakeActual ) + aURL = aActualURL; + else + aActualURL = aURL; +} + +SfxFrameDescriptor* SfxFrameDescriptor::Clone( BOOL bWithIds ) const +{ + SfxFrameDescriptor *pFrame = new SfxFrameDescriptor; + + pFrame->aURL = aURL; + pFrame->aActualURL = aActualURL; + pFrame->aName = aName; + pFrame->aMargin = aMargin; + pFrame->nWidth = nWidth; + pFrame->eSizeSelector = eSizeSelector; + pFrame->eScroll = eScroll; + pFrame->bResizeHorizontal = bResizeHorizontal; + pFrame->bResizeVertical = bResizeVertical; + pFrame->nHasBorder = nHasBorder; + pFrame->bHasUI = bHasUI; + pFrame->SetReadOnly( IsReadOnly() ); + pFrame->SetEditable( IsEditable() ); + if ( pImp->pWallpaper ) + pFrame->pImp->pWallpaper = new Wallpaper( *pImp->pWallpaper ); + if( pImp->pArgs ) + { + // Aktuell ist im Clone von SfxAllItemSets noch ein Bug... + pFrame->pImp->pArgs = new SfxAllItemSet( SFX_APP()->GetPool() ); + pFrame->pImp->pArgs->Put(*pImp->pArgs); + } + + if ( bWithIds ) + pFrame->nItemId = nItemId; + else + pFrame->nItemId = 0; + + return pFrame; +} + +USHORT SfxFrameDescriptor::GetWinBits() const +{ + USHORT nBits = 0; + if ( eSizeSelector == SIZE_REL ) + nBits |= SWIB_RELATIVESIZE; + if ( eSizeSelector == SIZE_PERCENT ) + nBits |= SWIB_PERCENTSIZE; + if ( !IsResizable() ) + nBits |= SWIB_FIXED; + if ( !nWidth ) + nBits |= SWIB_INVISIBLE; + return nBits; +} + +BOOL SfxFrameDescriptor::HasFrameBorder() const +{ + return (nHasBorder & BORDER_YES) != 0; +} + +long SfxFrameDescriptor::GetSize() const +{ + return nWidth; +} + +void SfxFrameDescriptor::TakeProperties( const SfxFrameProperties& rProp ) +{ + aURL = aActualURL = INetURLObject(rProp.aURL); + aName = rProp.aName; + aMargin.Width() = rProp.lMarginWidth; + aMargin.Height() = rProp.lMarginHeight; + nWidth = rProp.lSize; + eScroll = rProp.eScroll; + eSizeSelector = rProp.eSizeSelector; + nHasBorder = rProp.bHasBorder ? BORDER_YES : BORDER_NO; + if ( rProp.bBorderSet ) + nHasBorder |= BORDER_SET; + bResizeHorizontal = bResizeVertical = rProp.bResizable; +} + +void SfxFrameDescriptor::SetWallpaper( const Wallpaper& rWallpaper ) +{ + DELETEZ( pImp->pWallpaper ); + + if ( rWallpaper.GetStyle() != WALLPAPER_NULL ) + pImp->pWallpaper = new Wallpaper( rWallpaper ); +} + +const Wallpaper* SfxFrameDescriptor::GetWallpaper() const +{ + return pImp->pWallpaper; +} + +USHORT SfxFrameDescriptor::GetItemPos() const +{ + return USHRT_MAX; +} + + +SfxFrameProperties::SfxFrameProperties( const SfxFrameDescriptor *pD ) + : aURL( pD->GetURL().GetMainURL( INetURLObject::DECODE_TO_IURI ) ) + , aName( pD->GetName() ) + , lMarginWidth( pD->GetMargin().Width() ) + , lMarginHeight( pD->GetMargin().Height() ) + , lSize( pD->GetWidth() ) + , lSetSize( SIZE_NOT_SET ) + , lFrameSpacing( SPACING_NOT_SET ) + , lInheritedFrameSpacing( SPACING_NOT_SET ) + , eScroll( pD->GetScrollingMode() ) + , eSizeSelector( pD->GetSizeSelector() ) + , eSetSizeSelector( SIZE_REL ) + , bHasBorder( pD->HasFrameBorder() ) + , bBorderSet( pD->IsFrameBorderSet() ) + , bResizable( pD->IsResizable() ) + , bSetResizable( FALSE ) + , bIsRootSet( FALSE ) + , bIsInColSet( FALSE ) + , bHasBorderInherited( FALSE ) + , pFrame( pD->Clone() ) +{ + bBorderSet = TRUE; +} + +SfxFrameProperties& SfxFrameProperties::operator =( + const SfxFrameProperties &rProp ) +{ + aURL = rProp.aURL; + aName = rProp.aName; + lMarginWidth = rProp.lMarginWidth; + lMarginHeight = rProp.lMarginHeight; + lSize = rProp.lSize; + lSetSize = rProp.lSetSize; + lFrameSpacing = rProp.lFrameSpacing; + lInheritedFrameSpacing = rProp.lInheritedFrameSpacing; + eScroll = rProp.eScroll; + eSizeSelector = rProp.eSizeSelector; + eSetSizeSelector = rProp.eSetSizeSelector; + bHasBorder = rProp.bHasBorder; + bBorderSet = rProp.bBorderSet; + bResizable = rProp.bResizable; + bSetResizable = rProp.bSetResizable; + bIsRootSet = rProp.bIsRootSet; + bIsInColSet = rProp.bIsInColSet; + bHasBorderInherited = rProp.bHasBorderInherited; + pFrame = rProp.pFrame->Clone(); + return *this; +} + +int SfxFrameProperties::operator ==( const SfxFrameProperties& rProp ) const +{ + return aURL == rProp.aURL && aName == rProp.aName && lMarginWidth == rProp.lMarginWidth && lMarginHeight == rProp.lMarginHeight && + lSize == rProp.lSize && eScroll == rProp.eScroll && eSizeSelector == rProp.eSizeSelector && + lSetSize == rProp.lSetSize && lFrameSpacing == rProp.lFrameSpacing && eSetSizeSelector == rProp.eSetSizeSelector && + bHasBorder == rProp.bHasBorder && bBorderSet == rProp.bBorderSet && + bResizable == rProp.bResizable && bSetResizable == rProp.bSetResizable; +} + +TYPEINIT1(SfxFrameDescriptorItem, SfxPoolItem); + +SfxFrameDescriptorItem::~SfxFrameDescriptorItem() +{} + +int SfxFrameDescriptorItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + return aProperties == ((SfxFrameDescriptorItem&)rAttr).aProperties; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SfxFrameDescriptorItem::Clone( SfxItemPool* ) const +{ + return new SfxFrameDescriptorItem( *this ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SfxFrameDescriptorItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, + const IntlWrapper * +) const +{ + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; +} + + diff --git a/sfx2/source/doc/graphhelp.cxx b/sfx2/source/doc/graphhelp.cxx new file mode 100644 index 000000000000..388d85cefc25 --- /dev/null +++ b/sfx2/source/doc/graphhelp.cxx @@ -0,0 +1,529 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#ifdef WNT + +#undef WB_LEFT +#undef WB_RIGHT + +#define UINT64 USE_WIN_UINT64 +#define INT64 USE_WIN_INT64 +#define UINT32 USE_WIN_UINT32 +#define INT32 USE_WIN_INT32 + +#include <tools/presys.h> +#if defined _MSC_VER +#pragma warning(push, 1) +#endif +#include <windows.h> +#if defined _MSC_VER +#pragma warning(pop) +#endif +#include <tools/postsys.h> + +#undef UINT64 +#undef INT64 +#undef UINT32 +#undef INT32 + +#endif +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/graphic/XGraphicProvider.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/io/XStream.hpp> + + +#include <osl/thread.h> +#include <vcl/gdimtf.hxx> +#include <vcl/graph.hxx> +#include <vcl/cvtgrf.hxx> +#include <vcl/outdev.hxx> +#include <vcl/virdev.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/salbtype.hxx> + +#include <tools/stream.hxx> +#include <unotools/tempfile.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <unotools/streamwrap.hxx> +#include <comphelper/processfactory.hxx> + + +#include "sfxresid.hxx" +#include "graphhelp.hxx" +#include "doc.hrc" + +using namespace ::com::sun::star; + +#define THUMBNAIL_RESOLUTION 256 + +//--------------------------------------------------------------- +// static +SvMemoryStream* GraphicHelper::getFormatStrFromGDI_Impl( const GDIMetaFile* pGDIMeta, sal_uInt32 nFormat ) +{ + SvMemoryStream* pResult = NULL; + if ( pGDIMeta ) + { + SvMemoryStream* pStream = new SvMemoryStream( 65535, 65535 ); + if ( pStream ) + { + Graphic aGraph( *pGDIMeta ); + if ( GraphicConverter::Export( *pStream, aGraph, nFormat ) == 0 ) + pResult = pStream; + else + delete pStream; + } + } + + return pResult; +} + +//--------------------------------------------------------------- +// static +void* GraphicHelper::getEnhMetaFileFromGDI_Impl( const GDIMetaFile* pGDIMeta ) +{ + (void)pGDIMeta; // unused + void* pResult = NULL; + +#ifdef WNT + if ( pGDIMeta ) + { + String aStr = ::rtl::OUString::createFromAscii( ".emf" ); + ::utl::TempFile aTempFile( ::rtl::OUString(), + &aStr, + NULL, + sal_False ); + + ::rtl::OUString aMetaFile = aTempFile.GetFileName(); + ::rtl::OUString aMetaURL = aTempFile.GetURL(); + ::rtl::OString aWinFile = ::rtl::OUStringToOString( aMetaFile, osl_getThreadTextEncoding() ); + + SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aMetaURL, STREAM_STD_READWRITE ); + if ( pStream ) + { + Graphic aGraph( *pGDIMeta ); + sal_Bool bFailed = (sal_Bool)GraphicConverter::Export( *pStream, aGraph, CVT_EMF ); + pStream->Flush(); + delete pStream; + + if ( !bFailed ) + pResult = GetEnhMetaFileA( aWinFile.getStr() ); + } + } +#endif + + return pResult; +} + +//--------------------------------------------------------------- +// static +void* GraphicHelper::getWinMetaFileFromGDI_Impl( const GDIMetaFile* pGDIMeta, const Size& aMetaSize ) +{ + (void)pGDIMeta; // unused + (void)aMetaSize; // unused + void* pResult = NULL; + +#ifdef WNT + if ( pGDIMeta ) + { + SvMemoryStream* pStream = new SvMemoryStream( 65535, 65535 ); + if ( pStream ) + { + Graphic aGraph( *pGDIMeta ); + sal_Bool bFailed = (sal_Bool)GraphicConverter::Export( *pStream, aGraph, CVT_WMF ); + pStream->Flush(); + if ( !bFailed ) + { + sal_Int32 nLength = pStream->Seek( STREAM_SEEK_TO_END ); + if ( nLength > 22 ) + { + HMETAFILE hMeta = SetMetaFileBitsEx( nLength - 22, + ( reinterpret_cast< const sal_uChar*>( pStream->GetData() ) ) + 22 ); + + if ( hMeta ) + { + HGLOBAL hMemory = GlobalAlloc( GMEM_DDESHARE | GMEM_MOVEABLE, sizeof( METAFILEPICT ) ); + + if ( hMemory ) + { + METAFILEPICT* pMF = (METAFILEPICT*)GlobalLock( hMemory ); + + pMF->hMF = hMeta; + pMF->mm = MM_ANISOTROPIC; + + MapMode aMetaMode = pGDIMeta->GetPrefMapMode(); + MapMode aWinMode( MAP_100TH_MM ); + + if ( aWinMode == pGDIMeta->GetPrefMapMode() ) + { + pMF->xExt = aMetaSize.Width(); + pMF->yExt = aMetaSize.Height(); + } + else + { + Size aWinSize = OutputDevice::LogicToLogic( Size( aMetaSize.Width(), aMetaSize.Height() ), + pGDIMeta->GetPrefMapMode(), + aWinMode ); + pMF->xExt = aWinSize.Width(); + pMF->yExt = aWinSize.Height(); + } + + GlobalUnlock( hMemory ); + pResult = (void*)hMemory; + } + else + DeleteMetaFile( hMeta ); + } + } + } + + delete pStream; + } + } + +#endif + + + return pResult; +} + +//--------------------------------------------------------------- +// static +sal_Bool GraphicHelper::supportsMetaFileHandle_Impl() +{ +#ifdef WNT + return sal_True; +#else + return sal_False; +#endif +} + +//--------------------------------------------------------------- +// static +sal_Bool GraphicHelper::mergeBitmaps_Impl( const BitmapEx& rBmpEx, const BitmapEx& rOverlay, + const Rectangle& rOverlayRect, BitmapEx& rReturn ) +{ + // the implementation is provided by KA + + Point aNullPt; + Rectangle aBmpRect( aNullPt, rBmpEx.GetSizePixel() ); + VirtualDevice aVDev; + + if( !rReturn.IsEmpty() ) + rReturn.SetEmpty(); + + if( !rBmpEx.IsEmpty() && aVDev.SetOutputSizePixel( aBmpRect.GetSize() ) ) + { + Rectangle aOverlayRect( rOverlayRect ); + + aOverlayRect.Intersection( aBmpRect ); + + if( rOverlay.IsEmpty() || rOverlayRect.IsEmpty() ) + rReturn = rBmpEx; + else + { + aVDev.DrawBitmap( aNullPt, aVDev.GetOutputSizePixel(), rBmpEx.GetBitmap() ); + aVDev.DrawBitmapEx( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), rOverlay ); + + Bitmap aBmp( aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) ); + aBmp.Convert( BMP_CONVERSION_24BIT ); + + if( !rBmpEx.IsTransparent() ) + rReturn = aBmp; + else + { + aVDev.DrawBitmap( aNullPt, aVDev.GetOutputSizePixel(), rBmpEx.GetMask() ); + Bitmap aOverlayMergeBmp( aVDev.GetBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize() ) ); + + if( rOverlay.IsTransparent() ) + aVDev.DrawBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), rOverlay.GetMask() ); + else + { + aVDev.SetLineColor( COL_BLACK ); + aVDev.SetFillColor( COL_BLACK ); + aVDev.DrawRect( aOverlayRect); + } + + aOverlayMergeBmp.CombineSimple( aVDev.GetBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize() ), BMP_COMBINE_AND ); + aVDev.DrawBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), aOverlayMergeBmp ); + rReturn = BitmapEx( aBmp, aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) ); + } + } + } + + return !rReturn.IsEmpty(); +} + + +//--------------------------------------------------------------- +// static +sal_Bool GraphicHelper::createThumb_Impl( const GDIMetaFile& rMtf, + sal_uInt32 nMaximumExtent, + BitmapEx& rBmpEx, + const BitmapEx* pOverlay, + const Rectangle* pOverlayRect ) +{ + // the implementation is provided by KA + + // initialization seems to be complicated but is used to avoid rounding errors + VirtualDevice aVDev; + const Point aNullPt; + const Point aTLPix( aVDev.LogicToPixel( aNullPt, rMtf.GetPrefMapMode() ) ); + const Point aBRPix( aVDev.LogicToPixel( Point( rMtf.GetPrefSize().Width() - 1, rMtf.GetPrefSize().Height() - 1 ), rMtf.GetPrefMapMode() ) ); + Size aDrawSize( aVDev.LogicToPixel( rMtf.GetPrefSize(), rMtf.GetPrefMapMode() ) ); + Size aSizePix( labs( aBRPix.X() - aTLPix.X() ) + 1, labs( aBRPix.Y() - aTLPix.Y() ) + 1 ); + Point aPosPix; + + if ( !rBmpEx.IsEmpty() ) + rBmpEx.SetEmpty(); + + // determine size that has the same aspect ratio as image size and + // fits into the rectangle determined by nMaximumExtent + if ( aSizePix.Width() && aSizePix.Height() && + ( sal::static_int_cast<sal_uInt32>(aSizePix.Width()) > nMaximumExtent || + sal::static_int_cast<sal_uInt32>(aSizePix.Height()) > nMaximumExtent ) ) + { + const Size aOldSizePix( aSizePix ); + double fWH = static_cast< double >( aSizePix.Width() ) / aSizePix.Height(); + + if ( fWH <= 1.0 ) + { + aSizePix.Width() = FRound( nMaximumExtent * fWH ); + aSizePix.Height() = nMaximumExtent; + } + else + { + aSizePix.Width() = nMaximumExtent; + aSizePix.Height() = FRound( nMaximumExtent / fWH ); + } + + aDrawSize.Width() = FRound( ( static_cast< double >( aDrawSize.Width() ) * aSizePix.Width() ) / aOldSizePix.Width() ); + aDrawSize.Height() = FRound( ( static_cast< double >( aDrawSize.Height() ) * aSizePix.Height() ) / aOldSizePix.Height() ); + } + + Size aFullSize; + Point aBackPosPix; + Rectangle aOverlayRect; + + // calculate addigtional positions and sizes if an overlay image is used + if ( pOverlay ) + { + aFullSize = Size( nMaximumExtent, nMaximumExtent ); + aOverlayRect = Rectangle( aNullPt, aFullSize ); + + aOverlayRect.Intersection( pOverlayRect ? *pOverlayRect : Rectangle( aNullPt, pOverlay->GetSizePixel() ) ); + + if ( !aOverlayRect.IsEmpty() ) + aBackPosPix = Point( ( nMaximumExtent - aSizePix.Width() ) >> 1, ( nMaximumExtent - aSizePix.Height() ) >> 1 ); + else + pOverlay = NULL; + } + else + { + aFullSize = aSizePix; + pOverlay = NULL; + } + + // draw image(s) into VDev and get resulting image + if ( aVDev.SetOutputSizePixel( aFullSize ) ) + { + // draw metafile into VDev + const_cast< GDIMetaFile& >( rMtf ).WindStart(); + const_cast< GDIMetaFile& >( rMtf ).Play( &aVDev, aBackPosPix, aDrawSize ); + + // draw overlay if neccessary + if ( pOverlay ) + aVDev.DrawBitmapEx( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), *pOverlay ); + + // get paint bitmap + Bitmap aBmp( aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) ); + + // assure that we have a true color image + if ( aBmp.GetBitCount() != 24 ) + aBmp.Convert( BMP_CONVERSION_24BIT ); + + rBmpEx = BitmapEx( aBmp ); + } + + return !rBmpEx.IsEmpty(); +} + +//--------------------------------------------------------------- +// static +sal_Bool GraphicHelper::getThumbnailFormatFromGDI_Impl( GDIMetaFile* pMetaFile, + sal_Bool bSigned, + const uno::Reference< io::XStream >& xStream ) +{ + sal_Bool bResult = sal_False; + SvStream* pStream = NULL; + + if ( xStream.is() ) + pStream = ::utl::UcbStreamHelper::CreateStream( xStream ); + + if ( pMetaFile && pStream && !pStream->GetError() ) + { + BitmapEx aResultBitmap; + BitmapEx* pSignatureBitmap = NULL; + + if ( bSigned ) + pSignatureBitmap = new BitmapEx( SfxResId( BMP_SIGNATURE ) ); + + bResult = createThumb_Impl( *pMetaFile, + THUMBNAIL_RESOLUTION, + aResultBitmap, + pSignatureBitmap ); + if ( bResult ) + bResult = ( !aResultBitmap.IsEmpty() + && GraphicConverter::Export( *pStream, aResultBitmap, CVT_PNG ) == 0 + && ( pStream->Flush(), !pStream->GetError() ) ); + + if ( pSignatureBitmap ) + delete pSignatureBitmap; + + delete pStream; + } + + return bResult; +} + +//--------------------------------------------------------------- +// static +sal_Bool GraphicHelper::getSignedThumbnailFormatFromBitmap_Impl( const BitmapEx& aBitmap, + const uno::Reference< io::XStream >& xStream ) +{ + sal_Bool bResult = sal_False; + SvStream* pStream = NULL; + + if ( xStream.is() ) + pStream = ::utl::UcbStreamHelper::CreateStream( xStream ); + + if ( pStream && !pStream->GetError() ) + { + BitmapEx aResultBitmap; + BitmapEx aSignatureBitmap( SfxResId( BMP_SIGNATURE ) ); + + bResult = mergeBitmaps_Impl( aBitmap, + aSignatureBitmap, + Rectangle( Point(), aBitmap.GetSizePixel() ), + aResultBitmap ); + + if ( bResult ) + { + bResult = ( !aResultBitmap.IsEmpty() + && GraphicConverter::Export( *pStream, aResultBitmap, CVT_PNG ) == 0 + && ( pStream->Flush(), !pStream->GetError() ) ); + } + + delete pStream; + } + + return bResult; +} + +//--------------------------------------------------------------- +// static +sal_Bool GraphicHelper::getThumbnailReplacement_Impl( sal_Int32 nResID, const uno::Reference< io::XStream >& xStream ) +{ + sal_Bool bResult = sal_False; + if ( nResID && xStream.is() ) + { + uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory(); + if ( xServiceManager.is() ) + { + try + { + uno::Reference< graphic::XGraphicProvider > xGraphProvider( + xServiceManager->createInstance( + ::rtl::OUString::createFromAscii( "com.sun.star.graphic.GraphicProvider" ) ), + uno::UNO_QUERY ); + if ( xGraphProvider.is() ) + { + ::rtl::OUString aURL = ::rtl::OUString::createFromAscii( "private:resource/sfx/bitmapex/" ); + aURL += ::rtl::OUString::valueOf( nResID ); + + uno::Sequence< beans::PropertyValue > aMediaProps( 1 ); + aMediaProps[0].Name = ::rtl::OUString::createFromAscii( "URL" ); + aMediaProps[0].Value <<= aURL; + + uno::Reference< graphic::XGraphic > xGraphic = xGraphProvider->queryGraphic( aMediaProps ); + if ( xGraphic.is() ) + { + uno::Sequence< beans::PropertyValue > aStoreProps( 2 ); + aStoreProps[0].Name = ::rtl::OUString::createFromAscii( "OutputStream" ); + aStoreProps[0].Value <<= xStream; + aStoreProps[1].Name = ::rtl::OUString::createFromAscii( "MimeType" ); + aStoreProps[1].Value <<= ::rtl::OUString::createFromAscii( "image/png" ); + + xGraphProvider->storeGraphic( xGraphic, aStoreProps ); + bResult = sal_True; + } + } + } + catch( uno::Exception& ) + { + } + } + } + + return bResult; +} + +//--------------------------------------------------------------- +// static +sal_uInt16 GraphicHelper::getThumbnailReplacementIDByFactoryName_Impl( const ::rtl::OUString& aFactoryShortName, sal_Bool /*bIsTemplate*/ ) +{ + sal_uInt16 nResult = 0; + + if ( aFactoryShortName.equalsAscii( "scalc" ) ) + { + nResult = BMP_128X128_CALC_DOC; + } + else if ( aFactoryShortName.equalsAscii( "sdraw" ) ) + { + nResult = BMP_128X128_DRAW_DOC; + } + else if ( aFactoryShortName.equalsAscii( "simpress" ) ) + { + nResult = BMP_128X128_IMPRESS_DOC; + } + else if ( aFactoryShortName.equalsAscii( "smath" ) ) + { + nResult = BMP_128X128_MATH_DOC; + } + else if ( aFactoryShortName.equalsAscii( "swriter" ) || aFactoryShortName.compareToAscii( "swriter/", 8 ) == 0 ) + { + nResult = BMP_128X128_WRITER_DOC; + } + + return nResult; +} + diff --git a/sfx2/source/doc/graphhelp.hxx b/sfx2/source/doc/graphhelp.hxx new file mode 100644 index 000000000000..22f8ad5a115e --- /dev/null +++ b/sfx2/source/doc/graphhelp.hxx @@ -0,0 +1,75 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/io/XStream.hpp> + +#include <rtl/ustring.hxx> +class SvMemoryStream; +class GDIMetaFile; +class BitmapEx; + +class GraphicHelper +{ + + static sal_Bool mergeBitmaps_Impl( const BitmapEx& rBmpEx, const BitmapEx& rOverlay, + const Rectangle& rOverlayRect, BitmapEx& rReturn ); + + static sal_Bool createThumb_Impl( const GDIMetaFile& rMtf, + sal_uInt32 nMaximumExtent, + BitmapEx& rBmpEx, + const BitmapEx* pOverlay = NULL, + const Rectangle* pOverlayRect = NULL ); + +public: + + static SvMemoryStream* getFormatStrFromGDI_Impl( const GDIMetaFile* pGDIMeta, sal_uInt32 nFormat ); + + static void* getEnhMetaFileFromGDI_Impl( const GDIMetaFile* pGDIMeta ); + + static void* getWinMetaFileFromGDI_Impl( const GDIMetaFile* pGDIMeta, const Size& aMetaSize ); + + static sal_Bool supportsMetaFileHandle_Impl(); + + static sal_Bool getThumbnailFormatFromGDI_Impl( + GDIMetaFile* pMetaFile, + sal_Bool bSigned, + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xStream ); + + static sal_Bool getSignedThumbnailFormatFromBitmap_Impl( + const BitmapEx& aBitmap, + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xStream ); + + static sal_uInt16 getThumbnailReplacementIDByFactoryName_Impl( const ::rtl::OUString& aFactoryShortName, + sal_Bool bIsTemplate ); + + static sal_Bool getThumbnailReplacement_Impl( + sal_Int32 nResID, + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xStream ); + +}; + diff --git a/sfx2/source/doc/graphhelp.src b/sfx2/source/doc/graphhelp.src new file mode 100644 index 000000000000..1936a8460d25 --- /dev/null +++ b/sfx2/source/doc/graphhelp.src @@ -0,0 +1,59 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "doc.hrc" + +Bitmap BMP_SIGNATURE +{ + File = "signet.png"; +}; + +Bitmap BMP_128X128_CALC_DOC +{ + File = "128x128_calc_doc-p.png"; +}; + +Bitmap BMP_128X128_DRAW_DOC +{ + File = "128x128_draw_doc-p.png"; +}; + +Bitmap BMP_128X128_IMPRESS_DOC +{ + File = "128x128_impress_doc-p.png"; +}; + +Bitmap BMP_128X128_MATH_DOC +{ + File = "128x128_math_doc-p.png"; +}; + +Bitmap BMP_128X128_WRITER_DOC +{ + File = "128x128_writer_doc-p.png"; +}; + diff --git a/sfx2/source/doc/guisaveas.cxx b/sfx2/source/doc/guisaveas.cxx new file mode 100644 index 000000000000..3c4df7276d6b --- /dev/null +++ b/sfx2/source/doc/guisaveas.cxx @@ -0,0 +1,1842 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker.hpp> +#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> +#include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp> +#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> +#include "com/sun/star/ui/dialogs/TemplateDescription.hpp" +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyContainer.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/document/XDocumentInfoSupplier.hpp> +#include <com/sun/star/document/XDocumentInfo.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/frame/XStorable2.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/frame/XTitle.hpp> +#include <com/sun/star/util/XModifyListener.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <com/sun/star/util/XModifyBroadcaster.hpp> + +#include <com/sun/star/util/XCloneable.hpp> +#include <com/sun/star/frame/XModuleManager.hpp> +#include <com/sun/star/io/IOException.hpp> + +#include "guisaveas.hxx" + +#include <unotools/pathoptions.hxx> +#include <unotools/pathoptions.hxx> +#include <svl/itemset.hxx> +#include <svl/eitem.hxx> +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <unotools/useroptions.hxx> +#include <unotools/saveopt.hxx> +#include <tools/debug.hxx> +#include <tools/urlobj.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/configurationhelper.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/window.hxx> +#include <toolkit/awt/vclxwindow.hxx> + +#include <sfx2/sfxsids.hrc> +#include <doc.hrc> +#include <sfxresid.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/app.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/dinfdlg.hxx> +#include <sfx2/request.hxx> +#include <sfxtypes.hxx> +#include "alienwarn.hxx" + +#include "../appl/app.hrc" + +#define DOCPROPSNUM 17 + +// flags that specify requested operation +#define EXPORT_REQUESTED 1 +#define PDFEXPORT_REQUESTED 2 +#define PDFDIRECTEXPORT_REQUESTED 4 +#define WIDEEXPORT_REQUESTED 8 +#define SAVE_REQUESTED 16 +#define SAVEAS_REQUESTED 32 + +// possible statuses of save operation +#define STATUS_NO_ACTION 0 +#define STATUS_SAVE 1 +#define STATUS_SAVEAS 2 +#define STATUS_SAVEAS_STANDARDNAME 3 + +const ::rtl::OUString aFilterNameString = ::rtl::OUString::createFromAscii( "FilterName" ); +const ::rtl::OUString aFilterOptionsString = ::rtl::OUString::createFromAscii( "FilterOptions" ); +const ::rtl::OUString aFilterDataString = ::rtl::OUString::createFromAscii( "FilterData" ); +const ::rtl::OUString aFilterFlagsString = ::rtl::OUString::createFromAscii( "FilterFlags" ); + +using namespace ::com::sun::star; + +namespace { +//------------------------------------------------------------------------- +static sal_uInt16 getSlotIDFromMode( sal_Int8 nStoreMode ) +{ + // This is a temporary hardcoded solution must be removed when + // dialogs do not need parameters in SidSet representation any more + + sal_uInt16 nResult = 0; + if ( nStoreMode == EXPORT_REQUESTED ) + nResult = SID_EXPORTDOC; + else if ( nStoreMode == ( EXPORT_REQUESTED | PDFEXPORT_REQUESTED ) ) + nResult = SID_EXPORTDOCASPDF; + else if ( nStoreMode == ( EXPORT_REQUESTED | PDFEXPORT_REQUESTED | PDFDIRECTEXPORT_REQUESTED ) ) + nResult = SID_DIRECTEXPORTDOCASPDF; + else if ( nStoreMode == SAVEAS_REQUESTED || nStoreMode == ( EXPORT_REQUESTED | WIDEEXPORT_REQUESTED ) ) + nResult = SID_SAVEASDOC; + else { + DBG_ASSERT( sal_False, "Unacceptable slot name is provided!\n" ); + } + + return nResult; +} + +//------------------------------------------------------------------------- +static sal_uInt8 getStoreModeFromSlotName( const ::rtl::OUString& aSlotName ) +{ + sal_uInt8 nResult = 0; + if ( aSlotName.equalsAscii( "ExportTo" ) ) + nResult = EXPORT_REQUESTED; + else if ( aSlotName.equalsAscii( "ExportToPDF" ) ) + nResult = EXPORT_REQUESTED | PDFEXPORT_REQUESTED; + else if ( aSlotName.equalsAscii( "ExportDirectToPDF" ) ) + nResult = EXPORT_REQUESTED | PDFEXPORT_REQUESTED | PDFDIRECTEXPORT_REQUESTED; + else if ( aSlotName.equalsAscii( "Save" ) ) + nResult = SAVE_REQUESTED; + else if ( aSlotName.equalsAscii( "SaveAs" ) ) + nResult = SAVEAS_REQUESTED; + else + throw task::ErrorCodeIOException( ::rtl::OUString(), + uno::Reference< uno::XInterface >(), + ERRCODE_IO_INVALIDPARAMETER ); + + return nResult; +} + +//------------------------------------------------------------------------- +static sal_Int32 getMustFlags( sal_Int8 nStoreMode ) +{ + return ( SFX_FILTER_EXPORT + | ( ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) ) ? 0 : SFX_FILTER_IMPORT ) ); +} + +//------------------------------------------------------------------------- +static sal_Int32 getDontFlags( sal_Int8 nStoreMode ) +{ + return ( SFX_FILTER_INTERNAL + | SFX_FILTER_NOTINFILEDLG + | ( ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) ) ? SFX_FILTER_IMPORT : 0 ) ); +} + +//========================================================================= +// class DocumentSettingsGuard +//========================================================================= + +class DocumentSettingsGuard +{ + uno::Reference< beans::XPropertySet > m_xDocumentSettings; + sal_Bool m_bPreserveReadOnly; + sal_Bool m_bReadOnlySupported; + + sal_Bool m_bRestoreSettings; +public: + DocumentSettingsGuard( const uno::Reference< frame::XModel >& xModel, sal_Bool bReadOnly, sal_Bool bRestore ) + : m_bPreserveReadOnly( sal_False ) + , m_bReadOnlySupported( sal_False ) + , m_bRestoreSettings( bRestore ) + { + try + { + uno::Reference< lang::XMultiServiceFactory > xDocSettingsSupplier( xModel, uno::UNO_QUERY_THROW ); + m_xDocumentSettings.set( + xDocSettingsSupplier->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.Settings" ) ) ), + uno::UNO_QUERY_THROW ); + + ::rtl::OUString aLoadReadonlyString( RTL_CONSTASCII_USTRINGPARAM( "LoadReadonly" ) ); + + try + { + m_xDocumentSettings->getPropertyValue( aLoadReadonlyString ) >>= m_bPreserveReadOnly; + m_xDocumentSettings->setPropertyValue( aLoadReadonlyString, uno::makeAny( bReadOnly ) ); + m_bReadOnlySupported = sal_True; + } + catch( uno::Exception& ) + {} + } + catch( uno::Exception& ) + {} + + if ( ( bReadOnly && !m_bReadOnlySupported ) ) + throw uno::RuntimeException(); // the user could provide the data, so it must be stored + } + + ~DocumentSettingsGuard() + { + if ( m_bRestoreSettings ) + { + ::rtl::OUString aLoadReadonlyString( RTL_CONSTASCII_USTRINGPARAM( "LoadReadonly" ) ); + + try + { + if ( m_bReadOnlySupported ) + m_xDocumentSettings->setPropertyValue( aLoadReadonlyString, uno::makeAny( m_bPreserveReadOnly ) ); + } + catch( uno::Exception& ) + { + OSL_ASSERT( "Unexpected exception!" ); + } + } + } +}; +} // anonymous namespace + +//========================================================================= +// class ModelData_Impl +//========================================================================= +class ModelData_Impl +{ + SfxStoringHelper* m_pOwner; + uno::Reference< frame::XModel > m_xModel; + uno::Reference< frame::XStorable > m_xStorable; + uno::Reference< frame::XStorable2 > m_xStorable2; + uno::Reference< util::XModifiable > m_xModifiable; + + ::rtl::OUString m_aModuleName; + ::comphelper::SequenceAsHashMap* m_pDocumentPropsHM; + ::comphelper::SequenceAsHashMap* m_pModulePropsHM; + + ::comphelper::SequenceAsHashMap m_aMediaDescrHM; + + sal_Bool m_bRecommendReadOnly; + +public: + ModelData_Impl( SfxStoringHelper& aOwner, + const uno::Reference< frame::XModel >& xModel, + const uno::Sequence< beans::PropertyValue >& aMediaDescr ); + + ~ModelData_Impl(); + + void FreeDocumentProps(); + + uno::Reference< frame::XModel > GetModel(); + uno::Reference< frame::XStorable > GetStorable(); + uno::Reference< frame::XStorable2 > GetStorable2(); + uno::Reference< util::XModifiable > GetModifiable(); + + ::comphelper::SequenceAsHashMap& GetMediaDescr() { return m_aMediaDescrHM; } + + sal_Bool IsRecommendReadOnly() { return m_bRecommendReadOnly; } + + const ::comphelper::SequenceAsHashMap& GetDocProps(); + + ::rtl::OUString GetModuleName(); + const ::comphelper::SequenceAsHashMap& GetModuleProps(); + + void CheckInteractionHandler(); + + + ::rtl::OUString GetDocServiceName(); + uno::Sequence< beans::PropertyValue > GetDocServiceDefaultFilterCheckFlags( sal_Int32 nMust, sal_Int32 nDont ); + uno::Sequence< beans::PropertyValue > GetDocServiceAnyFilter( sal_Int32 nMust, sal_Int32 nDont ); + uno::Sequence< beans::PropertyValue > GetPreselectedFilter_Impl( sal_Int8 nStoreMode ); + uno::Sequence< beans::PropertyValue > GetDocServiceDefaultFilter(); + + sal_Bool ExecuteFilterDialog_Impl( const ::rtl::OUString& aFilterName ); + + sal_Int8 CheckSaveAcceptable( sal_Int8 nCurStatus ); + sal_Int8 CheckStateForSave(); + + sal_Int8 CheckFilter( const ::rtl::OUString& ); + + sal_Bool CheckFilterOptionsDialogExistence(); + + sal_Bool OutputFileDialog( sal_Int8 nStoreMode, + const ::comphelper::SequenceAsHashMap& aPreselectedFilterPropsHM, + sal_Bool bSetStandardName, + ::rtl::OUString& aSuggestedName, + sal_Bool bPreselectPassword, + const ::rtl::OUString& aSuggestedDir, + sal_Int16 nDialog, + const ::rtl::OUString& rStandardDir, + const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rBlackList + ); + + sal_Bool ShowDocumentInfoDialog(); + + ::rtl::OUString GetReccomendedDir( const ::rtl::OUString& aSuggestedDir, + const sfx2::FileDialogHelper::Context& aCtxt ); + ::rtl::OUString GetReccomendedName( const ::rtl::OUString& aSuggestedName, + const ::rtl::OUString& aTypeName ); + +}; + +//------------------------------------------------------------------------- +ModelData_Impl::ModelData_Impl( SfxStoringHelper& aOwner, + const uno::Reference< frame::XModel >& xModel, + const uno::Sequence< beans::PropertyValue >& aMediaDescr ) +: m_pOwner( &aOwner ) +, m_xModel( xModel ) +, m_pDocumentPropsHM( NULL ) +, m_pModulePropsHM( NULL ) +, m_aMediaDescrHM( aMediaDescr ) +, m_bRecommendReadOnly( sal_False ) +{ + CheckInteractionHandler(); +} + +//------------------------------------------------------------------------- +ModelData_Impl::~ModelData_Impl() +{ + FreeDocumentProps(); + if ( m_pDocumentPropsHM ) + delete m_pDocumentPropsHM; + + if ( m_pModulePropsHM ) + delete m_pModulePropsHM; +} + +//------------------------------------------------------------------------- +void ModelData_Impl::FreeDocumentProps() +{ + if ( m_pDocumentPropsHM ) + { + delete m_pDocumentPropsHM; + m_pDocumentPropsHM = NULL; + } +} + +//------------------------------------------------------------------------- +uno::Reference< frame::XModel > ModelData_Impl::GetModel() +{ + if ( !m_xModel.is() ) + throw uno::RuntimeException(); + + return m_xModel; +} + +//------------------------------------------------------------------------- +uno::Reference< frame::XStorable > ModelData_Impl::GetStorable() +{ + if ( !m_xStorable.is() ) + { + m_xStorable = uno::Reference< frame::XStorable >( m_xModel, uno::UNO_QUERY ); + if ( !m_xStorable.is() ) + throw uno::RuntimeException(); + } + + return m_xStorable; +} + +//------------------------------------------------------------------------- +uno::Reference< frame::XStorable2 > ModelData_Impl::GetStorable2() +{ + if ( !m_xStorable2.is() ) + { + m_xStorable2 = uno::Reference< frame::XStorable2 >( m_xModel, uno::UNO_QUERY ); + if ( !m_xStorable2.is() ) + throw uno::RuntimeException(); + } + + return m_xStorable2; +} + +//------------------------------------------------------------------------- +uno::Reference< util::XModifiable > ModelData_Impl::GetModifiable() +{ + if ( !m_xModifiable.is() ) + { + m_xModifiable = uno::Reference< util::XModifiable >( m_xModel, uno::UNO_QUERY ); + if ( !m_xModifiable.is() ) + throw uno::RuntimeException(); + } + + return m_xModifiable; +} + +//------------------------------------------------------------------------- +const ::comphelper::SequenceAsHashMap& ModelData_Impl::GetDocProps() +{ + if ( !m_pDocumentPropsHM ) + m_pDocumentPropsHM = new ::comphelper::SequenceAsHashMap( GetModel()->getArgs() ); + + return *m_pDocumentPropsHM; +} + +//------------------------------------------------------------------------- +::rtl::OUString ModelData_Impl::GetModuleName() +{ + if ( !m_aModuleName.getLength() ) + { + m_aModuleName = m_pOwner->GetModuleManager()->identify( + uno::Reference< uno::XInterface >( m_xModel, uno::UNO_QUERY ) ); + if ( !m_aModuleName.getLength() ) + throw uno::RuntimeException(); // TODO: + } + return m_aModuleName; +} + +//------------------------------------------------------------------------- +const ::comphelper::SequenceAsHashMap& ModelData_Impl::GetModuleProps() +{ + if ( !m_pModulePropsHM ) + { + uno::Sequence< beans::PropertyValue > aModuleProps; + m_pOwner->GetNamedModuleManager()->getByName( GetModuleName() ) >>= aModuleProps; + if ( !aModuleProps.getLength() ) + throw uno::RuntimeException(); // TODO; + m_pModulePropsHM = new ::comphelper::SequenceAsHashMap( aModuleProps ); + } + + return *m_pModulePropsHM; +} + +//------------------------------------------------------------------------- +::rtl::OUString ModelData_Impl::GetDocServiceName() +{ + return GetModuleProps().getUnpackedValueOrDefault(::rtl::OUString::createFromAscii( "ooSetupFactoryDocumentService" ), ::rtl::OUString()); +} + +//------------------------------------------------------------------------- +void ModelData_Impl::CheckInteractionHandler() +{ + ::comphelper::SequenceAsHashMap::const_iterator aInteractIter = + m_aMediaDescrHM.find( ::rtl::OUString::createFromAscii( "InteractionHandler" ) ); + + if ( aInteractIter == m_aMediaDescrHM.end() ) + { + try { + m_aMediaDescrHM[ ::rtl::OUString::createFromAscii( "InteractionHandler" ) ] + <<= uno::Reference< task::XInteractionHandler >( + m_pOwner->GetServiceFactory()->createInstance( + DEFINE_CONST_UNICODE("com.sun.star.task.InteractionHandler") ), + uno::UNO_QUERY ); + } + catch( uno::Exception& ) + { + } + } + else + { + uno::Reference< task::XInteractionHandler > xInteract; + DBG_ASSERT( ( aInteractIter->second >>= xInteract ) && xInteract.is(), "Broken interaction handler is provided!\n" ); + } +} + +//------------------------------------------------------------------------- +uno::Sequence< beans::PropertyValue > ModelData_Impl::GetDocServiceDefaultFilter() +{ + uno::Sequence< beans::PropertyValue > aProps; + + ::rtl::OUString aFilterName = GetModuleProps().getUnpackedValueOrDefault( + ::rtl::OUString::createFromAscii( "ooSetupFactoryDefaultFilter" ), + ::rtl::OUString() ); + + m_pOwner->GetFilterConfiguration()->getByName( aFilterName ) >>= aProps; + + return aProps; +} + +//------------------------------------------------------------------------- +uno::Sequence< beans::PropertyValue > ModelData_Impl::GetDocServiceDefaultFilterCheckFlags( sal_Int32 nMust, + sal_Int32 nDont ) +{ + uno::Sequence< beans::PropertyValue > aFilterProps; + uno::Sequence< beans::PropertyValue > aProps = GetDocServiceDefaultFilter(); + if ( aProps.getLength() ) + { + ::comphelper::SequenceAsHashMap aFiltHM( aProps ); + sal_Int32 nFlags = aFiltHM.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "Flags" ), + (sal_Int32)0 ); + if ( ( ( nFlags & nMust ) == nMust ) && !( nFlags & nDont ) ) + aFilterProps = aProps; + } + + return aFilterProps; +} + + +//------------------------------------------------------------------------- +uno::Sequence< beans::PropertyValue > ModelData_Impl::GetDocServiceAnyFilter( sal_Int32 nMust, sal_Int32 nDont ) +{ + uno::Sequence< beans::NamedValue > aSearchRequest( 1 ); + aSearchRequest[0].Name = ::rtl::OUString::createFromAscii( "DocumentService" ); + aSearchRequest[0].Value <<= GetDocServiceName(); + + return SfxStoringHelper::SearchForFilter( m_pOwner->GetFilterQuery(), aSearchRequest, nMust, nDont ); +} + +//------------------------------------------------------------------------- +uno::Sequence< beans::PropertyValue > ModelData_Impl::GetPreselectedFilter_Impl( sal_Int8 nStoreMode ) +{ + uno::Sequence< beans::PropertyValue > aFilterProps; + + sal_Int32 nMust = getMustFlags( nStoreMode ); + sal_Int32 nDont = getDontFlags( nStoreMode ); + + if ( nStoreMode & PDFEXPORT_REQUESTED ) + { + // Preselect PDF-Filter for EXPORT + uno::Sequence< beans::NamedValue > aSearchRequest( 2 ); + aSearchRequest[0].Name = ::rtl::OUString::createFromAscii( "Type" ); + aSearchRequest[0].Value <<= ::rtl::OUString::createFromAscii( "pdf_Portable_Document_Format" ); + aSearchRequest[1].Name = ::rtl::OUString::createFromAscii( "DocumentService" ); + aSearchRequest[1].Value <<= GetDocServiceName(); + + aFilterProps = SfxStoringHelper::SearchForFilter( m_pOwner->GetFilterQuery(), aSearchRequest, nMust, nDont ); + } + else + { + aFilterProps = GetDocServiceDefaultFilterCheckFlags( nMust, nDont ); + + if ( !aFilterProps.getLength() ) + { + // the default filter was not faund, use just the first acceptable one + aFilterProps = GetDocServiceAnyFilter( nMust, nDont ); + } + } + + return aFilterProps; +} + +//------------------------------------------------------------------------- +sal_Bool ModelData_Impl::ExecuteFilterDialog_Impl( const ::rtl::OUString& aFilterName ) +{ + sal_Bool bDialogUsed = sal_False; + + try { + uno::Sequence < beans::PropertyValue > aProps; + uno::Any aAny = m_pOwner->GetFilterConfiguration()->getByName( aFilterName ); + if ( aAny >>= aProps ) + { + sal_Int32 nPropertyCount = aProps.getLength(); + for( sal_Int32 nProperty=0; nProperty < nPropertyCount; ++nProperty ) + if( aProps[nProperty].Name.equals( ::rtl::OUString::createFromAscii("UIComponent")) ) + { + ::rtl::OUString aServiceName; + aProps[nProperty].Value >>= aServiceName; + if( aServiceName.getLength() ) + { + uno::Reference< ui::dialogs::XExecutableDialog > xFilterDialog( + m_pOwner->GetServiceFactory()->createInstance( aServiceName ), uno::UNO_QUERY ); + uno::Reference< beans::XPropertyAccess > xFilterProperties( xFilterDialog, uno::UNO_QUERY ); + + if( xFilterDialog.is() && xFilterProperties.is() ) + { + bDialogUsed = sal_True; + + uno::Reference< document::XExporter > xExporter( xFilterDialog, uno::UNO_QUERY ); + if( xExporter.is() ) + xExporter->setSourceDocument( + uno::Reference< lang::XComponent >( GetModel(), uno::UNO_QUERY ) ); + + uno::Sequence< beans::PropertyValue > aPropsForDialog; + GetMediaDescr() >> aPropsForDialog; + xFilterProperties->setPropertyValues( aPropsForDialog ); + + if( xFilterDialog->execute() ) + { + uno::Sequence< beans::PropertyValue > aPropsFromDialog = + xFilterProperties->getPropertyValues(); + for ( sal_Int32 nInd = 0; nInd < aPropsFromDialog.getLength(); nInd++ ) + GetMediaDescr()[aPropsFromDialog[nInd].Name] = aPropsFromDialog[nInd].Value; + } + else + { + throw task::ErrorCodeIOException( ::rtl::OUString(), + uno::Reference< uno::XInterface >(), + ERRCODE_IO_ABORT ); + } + } + } + + break; + } + } + } + catch( container::NoSuchElementException& ) + { + // the filter name is unknown + throw task::ErrorCodeIOException( ::rtl::OUString(), + uno::Reference< uno::XInterface >(), + ERRCODE_IO_INVALIDPARAMETER ); + } + catch( task::ErrorCodeIOException& ) + { + throw; + } + catch( uno::Exception& ) + { + } + + return bDialogUsed; +} + +//------------------------------------------------------------------------- +sal_Int8 ModelData_Impl::CheckSaveAcceptable( sal_Int8 nCurStatus ) +{ + sal_Int8 nResult = nCurStatus; + + if ( nResult != STATUS_NO_ACTION && GetStorable()->hasLocation() ) + { + // check whether save is acceptable by the configuration + // it is done only for documents that have persistence already + uno::Reference< uno::XInterface > xCommonConfig = ::comphelper::ConfigurationHelper::openConfig( + m_pOwner->GetServiceFactory(), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common" ) ), + ::comphelper::ConfigurationHelper::E_STANDARD ); + if ( !xCommonConfig.is() ) + throw uno::RuntimeException(); // should the saving proceed as usual instead? + + try + { + sal_Bool bAlwaysSaveAs = sal_False; + + // the saving is acceptable + // in case the configuration entry is not set or set to false + // or in case of version creation + ::rtl::OUString aVersionCommentString = ::rtl::OUString::createFromAscii( "VersionComment" ); + if ( ( ::comphelper::ConfigurationHelper::readRelativeKey( + xCommonConfig, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Save/Document/" ) ), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AlwaysSaveAs" ) ) ) >>= bAlwaysSaveAs ) + && bAlwaysSaveAs + && GetMediaDescr().find( aVersionCommentString ) == GetMediaDescr().end() ) + { + // notify the user that SaveAs is going to be done + String aString( SfxResId( STR_NEW_FILENAME_SAVE ) ); + Window* pWin = SfxStoringHelper::GetModelWindow( m_xModel ); + QueryBox aMessageBox( pWin, WB_OK_CANCEL | WB_DEF_OK, aString ); + if ( aMessageBox.Execute() == RET_OK ) + nResult = STATUS_SAVEAS; + else + nResult = STATUS_NO_ACTION; + } + } + catch( uno::Exception& ) + { + // impossibility to get the configuration access means normal saving flow for now + } + } + + return nResult; +} + +//------------------------------------------------------------------------- +sal_Int8 ModelData_Impl::CheckStateForSave() +{ + // check acceptable entries for media descriptor + sal_Bool bVersInfoNeedsStore = sal_False; + ::comphelper::SequenceAsHashMap aAcceptedArgs; + + ::rtl::OUString aVersionCommentString = ::rtl::OUString::createFromAscii( "VersionComment" ); + ::rtl::OUString aAuthorString = ::rtl::OUString::createFromAscii( "Author" ); + ::rtl::OUString aInteractionHandlerString = ::rtl::OUString::createFromAscii( "InteractionHandler" ); + ::rtl::OUString aStatusIndicatorString = ::rtl::OUString::createFromAscii( "StatusIndicator" ); + + if ( GetMediaDescr().find( aVersionCommentString ) != GetMediaDescr().end() ) + { + bVersInfoNeedsStore = sal_True; + aAcceptedArgs[ aVersionCommentString ] = GetMediaDescr()[ aVersionCommentString ]; + } + if ( GetMediaDescr().find( aAuthorString ) != GetMediaDescr().end() ) + aAcceptedArgs[ aAuthorString ] = GetMediaDescr()[ aAuthorString ]; + if ( GetMediaDescr().find( aInteractionHandlerString ) != GetMediaDescr().end() ) + aAcceptedArgs[ aInteractionHandlerString ] = GetMediaDescr()[ aInteractionHandlerString ]; + if ( GetMediaDescr().find( aStatusIndicatorString ) != GetMediaDescr().end() ) + aAcceptedArgs[ aStatusIndicatorString ] = GetMediaDescr()[ aStatusIndicatorString ]; + + // remove unacceptable entry if there is any + DBG_ASSERT( GetMediaDescr().size() == aAcceptedArgs.size(), + "Unacceptable parameters are provided in Save request!\n" ); + if ( GetMediaDescr().size() != aAcceptedArgs.size() ) + GetMediaDescr() = aAcceptedArgs; + + // the document must be modified + if ( !GetModifiable()->isModified() && !bVersInfoNeedsStore ) + return STATUS_NO_ACTION; + + // if the document is readonly or a new one a SaveAs operation must be used + if ( !GetStorable()->hasLocation() || GetStorable()->isReadonly() ) + return STATUS_SAVEAS; + + // check that the old filter is acceptable + ::rtl::OUString aOldFilterName = GetDocProps().getUnpackedValueOrDefault( + aFilterNameString, + ::rtl::OUString() ); + sal_Int8 nResult = CheckFilter( aOldFilterName ); + + return nResult; +} + +sal_Int8 ModelData_Impl::CheckFilter( const ::rtl::OUString& aFilterName ) +{ + ::comphelper::SequenceAsHashMap aFiltPropsHM; + sal_Int32 nFiltFlags = 0; + if ( aFilterName.getLength() ) + { + // get properties of filter + uno::Sequence< beans::PropertyValue > aFilterProps; + if ( aFilterName.getLength() ) + m_pOwner->GetFilterConfiguration()->getByName( aFilterName ) >>= aFilterProps; + + aFiltPropsHM = ::comphelper::SequenceAsHashMap( aFilterProps ); + nFiltFlags = aFiltPropsHM.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "Flags" ), (sal_Int32)0 ); + } + + // only a temporary solution until default filter retrieving feature is implemented + // then GetDocServiceDefaultFilter() must be used + ::comphelper::SequenceAsHashMap aDefFiltPropsHM = GetDocServiceDefaultFilterCheckFlags( 3, 0 ); + sal_Int32 nDefFiltFlags = aDefFiltPropsHM.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "Flags" ), (sal_Int32)0 ); + + // if the old filter is not acceptable + // and there is no default filter or it is not acceptable for requested parameters then proceed with saveAs + if ( ( !aFiltPropsHM.size() || !( nFiltFlags & SFX_FILTER_EXPORT ) ) + && ( !aDefFiltPropsHM.size() || !( nDefFiltFlags & SFX_FILTER_EXPORT ) || nDefFiltFlags & SFX_FILTER_INTERNAL ) ) + return STATUS_SAVEAS; + + // so at this point there is either an acceptable old filter or default one + if ( !aFiltPropsHM.size() || !( nFiltFlags & SFX_FILTER_EXPORT ) ) + { + // so the default filter must be acceptable + return STATUS_SAVEAS_STANDARDNAME; + } + else if ( ( !( nFiltFlags & SFX_FILTER_OWN ) || ( nFiltFlags & SFX_FILTER_ALIEN ) ) + && !( nFiltFlags & SFX_FILTER_SILENTEXPORT ) && aDefFiltPropsHM.size() + && ( nDefFiltFlags & SFX_FILTER_EXPORT ) && !( nDefFiltFlags & SFX_FILTER_INTERNAL )) + { + // the default filter is acceptable and the old filter is alian one + // so ask to make a saveAs operation + ::rtl::OUString aUIName = aFiltPropsHM.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "UIName" ), + ::rtl::OUString() ); + ::rtl::OUString aDefUIName = aDefFiltPropsHM.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "UIName" ), + ::rtl::OUString() ); + ::rtl::OUString aPreusedFilterName = GetDocProps().getUnpackedValueOrDefault( + ::rtl::OUString::createFromAscii( "PreusedFilterName" ), + ::rtl::OUString() ); + if ( !aPreusedFilterName.equals( aFilterName ) && !aUIName.equals( aDefUIName ) ) + { + if ( !SfxStoringHelper::WarnUnacceptableFormat( GetModel(), aUIName, aDefUIName, sal_True ) ) + return STATUS_SAVEAS_STANDARDNAME; + } + } + + return STATUS_SAVE; +} + +//------------------------------------------------------------------------- +sal_Bool ModelData_Impl::CheckFilterOptionsDialogExistence() +{ + uno::Sequence< beans::NamedValue > aSearchRequest( 1 ); + aSearchRequest[0].Name = ::rtl::OUString::createFromAscii( "DocumentService" ); + aSearchRequest[0].Value <<= GetDocServiceName(); + + uno::Reference< container::XEnumeration > xFilterEnum = + m_pOwner->GetFilterQuery()->createSubSetEnumerationByProperties( aSearchRequest ); + + while ( xFilterEnum->hasMoreElements() ) + { + uno::Sequence< beans::PropertyValue > pProps; + if ( xFilterEnum->nextElement() >>= pProps ) + { + ::comphelper::SequenceAsHashMap aPropsHM( pProps ); + ::rtl::OUString aUIServName = aPropsHM.getUnpackedValueOrDefault( + ::rtl::OUString::createFromAscii( "UIComponent" ), + ::rtl::OUString() ); + if ( aUIServName.getLength() ) + return sal_True; + } + } + + return sal_False; +} + +//------------------------------------------------------------------------- +sal_Bool ModelData_Impl::OutputFileDialog( sal_Int8 nStoreMode, + const ::comphelper::SequenceAsHashMap& aPreselectedFilterPropsHM, + sal_Bool bSetStandardName, + ::rtl::OUString& aSuggestedName, + sal_Bool bPreselectPassword, + const ::rtl::OUString& aSuggestedDir, + sal_Int16 nDialog, + const ::rtl::OUString& rStandardDir, + const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rBlackList) +{ + sal_Bool bUseFilterOptions = sal_False; + + ::comphelper::SequenceAsHashMap::const_iterator aOverwriteIter = + GetMediaDescr().find( ::rtl::OUString::createFromAscii( "Overwrite" ) ); + + // the file name must be specified if overwrite option is set + if ( aOverwriteIter != GetMediaDescr().end() ) + throw task::ErrorCodeIOException( ::rtl::OUString(), + uno::Reference< uno::XInterface >(), + ERRCODE_IO_INVALIDPARAMETER ); + + // no target file name is specified + // we need to show the file dialog + + // check if we have a filter which allows for filter options, so we need a corresponding checkbox in the dialog + sal_Bool bAllowOptions = sal_False; + + // in case of Export, filter options dialog is used if available + if( !( nStoreMode & EXPORT_REQUESTED ) || ( nStoreMode & WIDEEXPORT_REQUESTED ) ) + bAllowOptions = CheckFilterOptionsDialogExistence(); + + // get the filename by dialog ... + // create the file dialog + sal_Int16 aDialogMode = bAllowOptions + ? (com::sun::star::ui::dialogs::TemplateDescription:: + FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS) + : (com::sun::star::ui::dialogs::TemplateDescription:: + FILESAVE_AUTOEXTENSION_PASSWORD); + sal_Int64 aDialogFlags = 0; + + if( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) ) + { + if ( nStoreMode & PDFEXPORT_REQUESTED ) + aDialogMode = com::sun::star::ui::dialogs::TemplateDescription:: + FILESAVE_AUTOEXTENSION; + else + aDialogMode = com::sun::star::ui::dialogs::TemplateDescription:: + FILESAVE_AUTOEXTENSION_SELECTION; + aDialogFlags = SFXWB_EXPORT; + } + + sfx2::FileDialogHelper* pFileDlg = NULL; + + ::rtl::OUString aDocServiceName = GetDocServiceName(); + DBG_ASSERT( aDocServiceName.getLength(), "No document service for this module set!" ); + + sal_Int32 nMust = getMustFlags( nStoreMode ); + sal_Int32 nDont = getDontFlags( nStoreMode ); + sfx2::FileDialogHelper::Context eCtxt = sfx2::FileDialogHelper::UNKNOWN_CONTEXT; + + if ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) ) + { + if ( ( nStoreMode & PDFEXPORT_REQUESTED ) && aPreselectedFilterPropsHM.size() ) + { + // this is a PDF export + // the filter options has been shown already + ::rtl::OUString aFilterUIName = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( + ::rtl::OUString::createFromAscii( "UIName" ), + ::rtl::OUString() ); + + pFileDlg = new sfx2::FileDialogHelper( aDialogMode, aDialogFlags, aFilterUIName, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "pdf" ) ), rStandardDir, rBlackList ); + pFileDlg->SetCurrentFilter( aFilterUIName ); + } + else + { + // This is the normal dialog + pFileDlg = new sfx2::FileDialogHelper( aDialogMode, aDialogFlags, aDocServiceName, nDialog, nMust, nDont, rStandardDir, rBlackList ); + } + + if( aDocServiceName.equalsAscii( "com.sun.star.drawing.DrawingDocument" ) ) + eCtxt = sfx2::FileDialogHelper::SD_EXPORT; + if( aDocServiceName.equalsAscii( "com.sun.star.presentation.PresentationDocument" ) ) + eCtxt = sfx2::FileDialogHelper::SI_EXPORT; + if( aDocServiceName.equalsAscii( "com.sun.star.text.TextDocument" ) ) + eCtxt = sfx2::FileDialogHelper::SW_EXPORT; + + if ( eCtxt != sfx2::FileDialogHelper::UNKNOWN_CONTEXT ) + pFileDlg->SetContext( eCtxt ); + + pFileDlg->CreateMatcher( aDocServiceName ); + + uno::Reference< ui::dialogs::XFilePicker > xFilePicker = pFileDlg->GetFilePicker(); + uno::Reference< ui::dialogs::XFilePickerControlAccess > xControlAccess = + uno::Reference< ui::dialogs::XFilePickerControlAccess >( xFilePicker, uno::UNO_QUERY ); + + if ( xControlAccess.is() ) + { + ::rtl::OUString aCtrlText = String( SfxResId( STR_EXPORTBUTTON ) ); + xControlAccess->setLabel( ui::dialogs::CommonFilePickerElementIds::PUSHBUTTON_OK, aCtrlText ); + + aCtrlText = ::rtl::OUString( String( SfxResId( STR_LABEL_FILEFORMAT ) ) ); + xControlAccess->setLabel( ui::dialogs::CommonFilePickerElementIds::LISTBOX_FILTER_LABEL, aCtrlText ); + } + } + else + { + // This is the normal dialog + pFileDlg = new sfx2::FileDialogHelper( aDialogMode, aDialogFlags, aDocServiceName, nDialog, nMust, nDont, rStandardDir, rBlackList ); + pFileDlg->CreateMatcher( aDocServiceName ); + } + + ::rtl::OUString aAdjustToType; + + if ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) ) + { + // it is export, set the preselected filter + ::rtl::OUString aFilterUIName = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( + ::rtl::OUString::createFromAscii( "UIName" ), + ::rtl::OUString() ); + pFileDlg->SetCurrentFilter( aFilterUIName ); + } + // it is no export, bSetStandardName == true means that user agreed to store document in the default (default default ;-)) format + else if ( bSetStandardName || GetStorable()->hasLocation() ) + { + uno::Sequence< beans::PropertyValue > aOldFilterProps; + ::rtl::OUString aOldFilterName = GetDocProps().getUnpackedValueOrDefault( + aFilterNameString, + ::rtl::OUString() ); + + if ( aOldFilterName.getLength() ) + m_pOwner->GetFilterConfiguration()->getByName( aOldFilterName ) >>= aOldFilterProps; + + ::comphelper::SequenceAsHashMap aOldFiltPropsHM( aOldFilterProps ); + sal_Int32 nOldFiltFlags = aOldFiltPropsHM.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "Flags" ), (sal_Int32)0 ); + + if ( bSetStandardName || ( nOldFiltFlags & nMust ) != nMust || nOldFiltFlags & nDont ) + { + // the suggested type will be changed, the extension should be adjusted + aAdjustToType = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( + ::rtl::OUString::createFromAscii( "Type" ), + ::rtl::OUString() ); + + ::rtl::OUString aFilterUIName = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( + ::rtl::OUString::createFromAscii( "UIName" ), + ::rtl::OUString() ); + pFileDlg->SetCurrentFilter( aFilterUIName ); + } + else + { + pFileDlg->SetCurrentFilter( aOldFiltPropsHM.getUnpackedValueOrDefault( + ::rtl::OUString::createFromAscii( "UIName" ), + ::rtl::OUString() ) ); + } + } + + ::rtl::OUString aReccomendedDir = GetReccomendedDir( aSuggestedDir, eCtxt ); + if ( aReccomendedDir.getLength() ) + pFileDlg->SetDisplayDirectory( aReccomendedDir ); + ::rtl::OUString aReccomendedName = GetReccomendedName( aSuggestedName, aAdjustToType ); + if ( aReccomendedName.getLength() ) + pFileDlg->SetFileName( aReccomendedName ); + + uno::Reference < view::XSelectionSupplier > xSel( GetModel()->getCurrentController(), uno::UNO_QUERY ); + if ( xSel.is() && xSel->getSelection().hasValue() ) + GetMediaDescr()[::rtl::OUString::createFromAscii( "SelectionOnly" )] <<= sal_True; + + // This is a temporary hardcoded solution must be removed when + // dialogs do not need parameters in SidSet representation any more + sal_uInt16 nSlotID = getSlotIDFromMode( nStoreMode ); + if ( !nSlotID ) + throw lang::IllegalArgumentException(); // TODO: + + // generate SidSet from MediaDescriptor and provide it into FileDialog + // than merge changed SidSet back + SfxAllItemSet aDialogParams( SFX_APP()->GetPool() ); + SfxItemSet* pDialogParams = &aDialogParams; + TransformParameters( nSlotID, + GetMediaDescr().getAsConstPropertyValueList(), + aDialogParams, + NULL ); + + const SfxPoolItem* pItem = NULL; + if ( bPreselectPassword && aDialogParams.GetItemState( SID_PASSWORD, sal_True, &pItem ) != SFX_ITEM_SET ) + { + // the file dialog preselects the password checkbox if the provided mediadescriptor has password entry + // after dialog execution the password entry will be either removed or replaced with the password + // entered by the user + aDialogParams.Put( SfxStringItem( SID_PASSWORD, String() ) ); + } + + // aStringTypeFN is a pure output parameter, pDialogParams is an in/out parameter + String aStringTypeFN; + if ( pFileDlg->Execute( pDialogParams, aStringTypeFN ) != ERRCODE_NONE ) + { + delete pFileDlg; + throw task::ErrorCodeIOException( ::rtl::OUString(), uno::Reference< uno::XInterface >(), ERRCODE_IO_ABORT ); + } + + ::rtl::OUString aFilterName = aStringTypeFN; + + // the following two arguments can not be converted in MediaDescriptor, + // so they should be removed from the ItemSet after retrieving + SFX_ITEMSET_ARG( pDialogParams, pRecommendReadOnly, SfxBoolItem, SID_RECOMMENDREADONLY, sal_False ); + m_bRecommendReadOnly = ( pRecommendReadOnly && pRecommendReadOnly->GetValue() ); + pDialogParams->ClearItem( SID_RECOMMENDREADONLY ); + + uno::Sequence< beans::PropertyValue > aPropsFromDialog; + TransformItems( nSlotID, *pDialogParams, aPropsFromDialog, NULL ); + GetMediaDescr() << aPropsFromDialog; + + // get the path from the dialog + INetURLObject aURL( pFileDlg->GetPath() ); + // the path should be provided outside since it might be used for further calls to the dialog + aSuggestedName = aURL.GetName( INetURLObject::DECODE_WITH_CHARSET ); + + // old filter options should be cleared in case different filter is used + + ::rtl::OUString aFilterFromMediaDescr = GetMediaDescr().getUnpackedValueOrDefault( + aFilterNameString, + ::rtl::OUString() ); + ::rtl::OUString aOldFilterName = GetDocProps().getUnpackedValueOrDefault( + aFilterNameString, + ::rtl::OUString() ); + if ( aFilterName.equals( aFilterFromMediaDescr ) ) + { + // preserv current settings if any + // if there no current settings and the name is the same + // as old filter name use old filter settings + + if ( aFilterFromMediaDescr.equals( aOldFilterName ) ) + { + ::comphelper::SequenceAsHashMap::const_iterator aIter = + GetDocProps().find( aFilterOptionsString ); + if ( aIter != GetDocProps().end() + && GetMediaDescr().find( aFilterOptionsString ) == GetMediaDescr().end() ) + GetMediaDescr()[aIter->first] = aIter->second; + + aIter = GetDocProps().find( aFilterDataString ); + if ( aIter != GetDocProps().end() + && GetMediaDescr().find( aFilterDataString ) == GetMediaDescr().end() ) + GetMediaDescr()[aIter->first] = aIter->second; + } + } + else + { + GetMediaDescr().erase( aFilterDataString ); + GetMediaDescr().erase( aFilterOptionsString ); + + if ( aFilterName.equals( aOldFilterName ) ) + { + // merge filter option of the document filter + + ::comphelper::SequenceAsHashMap::const_iterator aIter = + GetDocProps().find( aFilterOptionsString ); + if ( aIter != GetDocProps().end() ) + GetMediaDescr()[aIter->first] = aIter->second; + + aIter = GetDocProps().find( aFilterDataString ); + if ( aIter != GetDocProps().end() ) + GetMediaDescr()[aIter->first] = aIter->second; + } + } + + uno::Reference< ui::dialogs::XFilePickerControlAccess > xExtFileDlg( pFileDlg->GetFilePicker(), uno::UNO_QUERY ); + if ( xExtFileDlg.is() ) + { + if ( SfxStoringHelper::CheckFilterOptionsAppearence( m_pOwner->GetFilterConfiguration(), aFilterName ) ) + bUseFilterOptions = sal_True; + + if ( ( !( nStoreMode & EXPORT_REQUESTED ) || ( nStoreMode & WIDEEXPORT_REQUESTED ) ) && bUseFilterOptions ) + { + try + { + // for exporters: always show dialog if format uses options + // for save: show dialog if format uses options and no options given or if forced by user + uno::Any aVal = + xExtFileDlg->getValue( ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS, 0 ); + + aVal >>= bUseFilterOptions; + if ( !bUseFilterOptions ) + bUseFilterOptions = + ( GetMediaDescr().find( aFilterDataString ) == GetMediaDescr().end() + && GetMediaDescr().find( aFilterOptionsString ) == GetMediaDescr().end() ); + } + catch( lang::IllegalArgumentException& ) + {} + } + } + + delete pFileDlg; + + // merge in results of the dialog execution + GetMediaDescr()[::rtl::OUString::createFromAscii( "URL" )] <<= + ::rtl::OUString( aURL.GetMainURL( INetURLObject::NO_DECODE )); + GetMediaDescr()[aFilterNameString] <<= aFilterName; + + return bUseFilterOptions; +} + +//------------------------------------------------------------------------- +sal_Bool ModelData_Impl::ShowDocumentInfoDialog() +{ + sal_Bool bDialogUsed = sal_False; + + try { + uno::Reference< frame::XController > xController = GetModel()->getCurrentController(); + if ( xController.is() ) + { + uno::Reference< frame::XDispatchProvider > xFrameDispatch( xController->getFrame(), uno::UNO_QUERY ); + if ( xFrameDispatch.is() ) + { + util::URL aURL; + aURL.Complete = ::rtl::OUString::createFromAscii( ".uno:SetDocumentProperties" ); + + uno::Reference< util::XURLTransformer > xTransformer( + m_pOwner->GetServiceFactory()->createInstance( + DEFINE_CONST_UNICODE("com.sun.star.util.URLTransformer") ), + uno::UNO_QUERY ); + if ( xTransformer.is() && xTransformer->parseStrict( aURL ) ) + { + uno::Reference< frame::XDispatch > xDispatch = xFrameDispatch->queryDispatch( + aURL, + ::rtl::OUString::createFromAscii( "_self" ), + 0 ); + if ( xDispatch.is() ) + { + xDispatch->dispatch( aURL, uno::Sequence< beans::PropertyValue >() ); + bDialogUsed = sal_True; + } + } + } + } + } + catch ( uno::Exception& ) + { + } + + return bDialogUsed; +} + +//------------------------------------------------------------------------- +::rtl::OUString ModelData_Impl::GetReccomendedDir( const ::rtl::OUString& aSuggestedDir, const sfx2::FileDialogHelper::Context& aCtxt ) +{ + ::rtl::OUString aReccomendedDir; + + if ( ( aSuggestedDir.getLength() || GetStorable()->hasLocation() ) + && !GetMediaDescr().getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "RepairPackage" ), + sal_False ) ) + { + INetURLObject aLocation; + if ( aSuggestedDir.getLength() ) + aLocation = INetURLObject( aSuggestedDir ); + else + { + ::rtl::OUString aOldURL = GetStorable()->getLocation(); + if ( aOldURL.getLength() ) + { + INetURLObject aTmp( aOldURL ); + if ( aTmp.removeSegment() ) + aLocation = aTmp; + } + + if ( aLocation.HasError() ) + aLocation = INetURLObject( SvtPathOptions().GetWorkPath() ); + } + + aLocation.setFinalSlash(); + if ( !aLocation.HasError() ) + aReccomendedDir = aLocation.GetMainURL( INetURLObject::NO_DECODE ); + } + else + { + // pb: set graphic path if context == SD_EXPORT or SI_EXPORT else work path + ::rtl::OUString aConfigSuggestion( ( aCtxt != sfx2::FileDialogHelper::UNKNOWN_CONTEXT ) ? SvtPathOptions().GetGraphicPath() : SvtPathOptions().GetWorkPath() ); + aReccomendedDir = INetURLObject( aConfigSuggestion ).GetMainURL( INetURLObject::NO_DECODE ); + } + + return aReccomendedDir; +} + +//------------------------------------------------------------------------- +::rtl::OUString ModelData_Impl::GetReccomendedName( const ::rtl::OUString& aSuggestedName, const ::rtl::OUString& aTypeName ) +{ + // the last used name might be provided by aSuggestedName from the old selection, or from the MediaDescriptor + ::rtl::OUString aReccomendedName; + + if ( aSuggestedName.getLength() ) + aReccomendedName = aSuggestedName; + else + { + aReccomendedName = INetURLObject( GetStorable()->getLocation() ).GetName( INetURLObject::DECODE_WITH_CHARSET ); + if ( !aReccomendedName.getLength() ) + { + try { + uno::Reference< frame::XTitle > xTitle( GetModel(), uno::UNO_QUERY_THROW ); + aReccomendedName = xTitle->getTitle(); + } catch( uno::Exception& ) {} + } + + if ( aReccomendedName.getLength() && aTypeName.getLength() ) + { + // adjust the extension to the type + uno::Reference< container::XNameAccess > xTypeDetection = uno::Reference< container::XNameAccess >( + m_pOwner->GetServiceFactory()->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.TypeDetection" ) ), + uno::UNO_QUERY ); + if ( xTypeDetection.is() ) + { + INetURLObject aObj( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "file:///c:/" ) ) + aReccomendedName ); + + uno::Sequence< beans::PropertyValue > aTypeNameProps; + if ( ( xTypeDetection->getByName( aTypeName ) >>= aTypeNameProps ) && aTypeNameProps.getLength() ) + { + ::comphelper::SequenceAsHashMap aTypeNamePropsHM( aTypeNameProps ); + uno::Sequence< ::rtl::OUString > aExtensions = aTypeNamePropsHM.getUnpackedValueOrDefault( + ::rtl::OUString::createFromAscii( "Extensions" ), + ::uno::Sequence< ::rtl::OUString >() ); + if ( aExtensions.getLength() ) + aObj.SetExtension( aExtensions[0] ); + } + + aReccomendedName = aObj.GetName( INetURLObject::DECODE_WITH_CHARSET ); + } + } + } + + return aReccomendedName; +} + + +//========================================================================= +// class SfxStoringHelper +//========================================================================= +//------------------------------------------------------------------------- +SfxStoringHelper::SfxStoringHelper( const uno::Reference< lang::XMultiServiceFactory >& xFactory ) +: m_xFactory( xFactory ) +{ +} + +//------------------------------------------------------------------------- +uno::Reference< lang::XMultiServiceFactory > SfxStoringHelper::GetServiceFactory() +{ + if ( !m_xFactory.is() ) + { + m_xFactory = ::comphelper::getProcessServiceFactory(); + if( !m_xFactory.is() ) + throw uno::RuntimeException(); // TODO: + } + + return m_xFactory; +} + +//------------------------------------------------------------------------- +uno::Reference< container::XNameAccess > SfxStoringHelper::GetFilterConfiguration() +{ + if ( !m_xFilterCFG.is() ) + { + m_xFilterCFG = uno::Reference< container::XNameAccess >( + GetServiceFactory()->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ), + uno::UNO_QUERY ); + + if ( !m_xFilterCFG.is() ) + throw uno::RuntimeException(); + } + + return m_xFilterCFG; +} + +//------------------------------------------------------------------------- +uno::Reference< container::XContainerQuery > SfxStoringHelper::GetFilterQuery() +{ + if ( !m_xFilterQuery.is() ) + { + m_xFilterQuery = uno::Reference< container::XContainerQuery >( GetFilterConfiguration(), uno::UNO_QUERY ); + if ( !m_xFilterQuery.is() ) + throw uno::RuntimeException(); + } + + return m_xFilterQuery; +} + +//------------------------------------------------------------------------- +uno::Reference< ::com::sun::star::frame::XModuleManager > SfxStoringHelper::GetModuleManager() +{ + if ( !m_xModuleManager.is() ) + { + m_xModuleManager = uno::Reference< ::com::sun::star::frame::XModuleManager >( + GetServiceFactory()->createInstance( + ::rtl::OUString::createFromAscii( "com.sun.star.frame.ModuleManager" ) ), + uno::UNO_QUERY ); + + if ( !m_xModuleManager.is() ) + throw uno::RuntimeException(); + } + + return m_xModuleManager; +} + +//------------------------------------------------------------------------- +uno::Reference< container::XNameAccess > SfxStoringHelper::GetNamedModuleManager() +{ + if ( !m_xNamedModManager.is() ) + { + m_xNamedModManager = uno::Reference< container::XNameAccess >( GetModuleManager(), uno::UNO_QUERY ); + if ( !m_xNamedModManager.is() ) + throw uno::RuntimeException(); + } + + return m_xNamedModManager; +} + +//------------------------------------------------------------------------- +sal_Bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xModel, + const ::rtl::OUString& aSlotName, + uno::Sequence< beans::PropertyValue >& aArgsSequence, + sal_Bool bPreselectPassword, + ::rtl::OUString aSuggestedName, + sal_uInt16 nDocumentSignatureState ) +{ + ModelData_Impl aModelData( *this, xModel, aArgsSequence ); + + sal_Bool bDialogUsed = sal_False; + + INetURLObject aURL; + + sal_Bool bSetStandardName = sal_False; // can be set only for SaveAs + + // parse the slot name + sal_Int8 nStoreMode = getStoreModeFromSlotName( aSlotName ); + sal_Int8 nStatusSave = STATUS_NO_ACTION; + + // handle the special cases + if ( nStoreMode & SAVEAS_REQUESTED ) + { + ::comphelper::SequenceAsHashMap::const_iterator aSaveToIter = + aModelData.GetMediaDescr().find( ::rtl::OUString::createFromAscii( "SaveTo" ) ); + if ( aSaveToIter != aModelData.GetMediaDescr().end() ) + { + sal_Bool bWideExport = sal_False; + aSaveToIter->second >>= bWideExport; + if ( bWideExport ) + nStoreMode = EXPORT_REQUESTED | WIDEEXPORT_REQUESTED; + } + + // if saving is not acceptable the warning must be shown even in case of SaveAs operation + if ( ( nStoreMode & SAVEAS_REQUESTED ) && aModelData.CheckSaveAcceptable( STATUS_SAVEAS ) == STATUS_NO_ACTION ) + throw task::ErrorCodeIOException( ::rtl::OUString(), uno::Reference< uno::XInterface >(), ERRCODE_IO_ABORT ); + } + else if ( nStoreMode & SAVE_REQUESTED ) + { + // if saving is not acceptable by the configuration the warning must be shown + nStatusSave = aModelData.CheckSaveAcceptable( STATUS_SAVE ); + + if ( nStatusSave == STATUS_NO_ACTION ) + throw task::ErrorCodeIOException( ::rtl::OUString(), uno::Reference< uno::XInterface >(), ERRCODE_IO_ABORT ); + else if ( nStatusSave == STATUS_SAVE ) + { + // check whether it is possible to use save operation + nStatusSave = aModelData.CheckStateForSave(); + } + + if ( nStatusSave == STATUS_NO_ACTION ) + { + throw task::ErrorCodeIOException( ::rtl::OUString(), uno::Reference< uno::XInterface >(), ERRCODE_IO_ABORT ); + } + else if ( nStatusSave != STATUS_SAVE ) + { + // this should be a usual SaveAs operation + nStoreMode = SAVEAS_REQUESTED; + if ( nStatusSave == STATUS_SAVEAS_STANDARDNAME ) + bSetStandardName = sal_True; + } + } + + if ( !( nStoreMode & EXPORT_REQUESTED ) ) + { + // if it is no export, warn user that the signature will be removed + if ( SIGNATURESTATE_SIGNATURES_OK == nDocumentSignatureState + || SIGNATURESTATE_SIGNATURES_INVALID == nDocumentSignatureState + || SIGNATURESTATE_SIGNATURES_NOTVALIDATED == nDocumentSignatureState + || SIGNATURESTATE_SIGNATURES_PARTIAL_OK == nDocumentSignatureState) + { + if ( QueryBox( NULL, SfxResId( RID_XMLSEC_QUERY_LOSINGSIGNATURE ) ).Execute() != RET_YES ) + { + // the user has decided not to store the document + throw task::ErrorCodeIOException( ::rtl::OUString(), + uno::Reference< uno::XInterface >(), + ERRCODE_IO_ABORT ); + } + } + } + + if ( nStoreMode & SAVE_REQUESTED && nStatusSave == STATUS_SAVE ) + { + // Document properties can contain streams that should be freed before storing + aModelData.FreeDocumentProps(); + + if ( aModelData.GetStorable2().is() ) + { + try + { + aModelData.GetStorable2()->storeSelf( aModelData.GetMediaDescr().getAsConstPropertyValueList() ); + } + catch( lang::IllegalArgumentException& ) + { + OSL_ENSURE( sal_False, "ModelData didn't handle illegal parameters, all the parameters are ignored!\n" ); + aModelData.GetStorable()->store(); + } + } + else + { + OSL_ENSURE( sal_False, "XStorable2 is not supported by the model!\n" ); + aModelData.GetStorable()->store(); + } + + return sal_False; + } + + // preselect a filter for the storing process + uno::Sequence< beans::PropertyValue > aFilterProps = aModelData.GetPreselectedFilter_Impl( nStoreMode ); + + DBG_ASSERT( aFilterProps.getLength(), "No filter for storing!\n" ); + if ( !aFilterProps.getLength() ) + throw task::ErrorCodeIOException( ::rtl::OUString(), + uno::Reference< uno::XInterface >(), + ERRCODE_IO_INVALIDPARAMETER ); + + ::comphelper::SequenceAsHashMap aFilterPropsHM( aFilterProps ); + ::rtl::OUString aFilterName = aFilterPropsHM.getUnpackedValueOrDefault( + ::rtl::OUString::createFromAscii( "Name" ), + ::rtl::OUString() ); + + ::rtl::OUString aFilterFromMediaDescr = aModelData.GetMediaDescr().getUnpackedValueOrDefault( + aFilterNameString, + ::rtl::OUString() ); + ::rtl::OUString aOldFilterName = aModelData.GetDocProps().getUnpackedValueOrDefault( + aFilterNameString, + ::rtl::OUString() ); + + sal_Bool bUseFilterOptions = sal_False; + ::comphelper::SequenceAsHashMap::const_iterator aFileNameIter = aModelData.GetMediaDescr().find( ::rtl::OUString::createFromAscii( "URL" ) ); + + if ( ( nStoreMode & EXPORT_REQUESTED ) && ( nStoreMode & PDFEXPORT_REQUESTED ) && !( nStoreMode & PDFDIRECTEXPORT_REQUESTED ) ) + { + // this is PDF export, the filter options dialog should be shown before the export + aModelData.GetMediaDescr()[aFilterNameString] <<= aFilterName; + if ( aModelData.GetMediaDescr().find( aFilterFlagsString ) == aModelData.GetMediaDescr().end() + && aModelData.GetMediaDescr().find( aFilterOptionsString ) == aModelData.GetMediaDescr().end() + && aModelData.GetMediaDescr().find( aFilterDataString ) == aModelData.GetMediaDescr().end() ) + { + // execute filter options dialog since no options are set in the media descriptor + if ( aModelData.ExecuteFilterDialog_Impl( aFilterName ) ) + bDialogUsed = sal_True; + } + } + + if ( aFileNameIter == aModelData.GetMediaDescr().end() ) + { + sal_Int16 nDialog = SFX2_IMPL_DIALOG_CONFIG; + ::comphelper::SequenceAsHashMap::const_iterator aDlgIter = + aModelData.GetMediaDescr().find( ::rtl::OUString::createFromAscii( "UseSystemDialog" ) ); + if ( aDlgIter != aModelData.GetMediaDescr().end() ) + { + sal_Bool bUseSystemDialog = sal_True; + if ( aDlgIter->second >>= bUseSystemDialog ) + { + if ( bUseSystemDialog ) + nDialog = SFX2_IMPL_DIALOG_SYSTEM; + else + nDialog = SFX2_IMPL_DIALOG_OOO; + } + } + + // The Dispatch supports parameter FolderName that overwrites SuggestedSaveAsDir + ::rtl::OUString aSuggestedDir = aModelData.GetMediaDescr().getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FolderName" ) ), ::rtl::OUString() ); + if ( !aSuggestedDir.getLength() ) + { + aSuggestedDir = aModelData.GetMediaDescr().getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SuggestedSaveAsDir" ) ), ::rtl::OUString() ); + if ( !aSuggestedDir.getLength() ) + aSuggestedDir = aModelData.GetDocProps().getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SuggestedSaveAsDir" ) ), ::rtl::OUString() ); + } + + aSuggestedName = aModelData.GetMediaDescr().getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SuggestedSaveAsName" ) ), ::rtl::OUString() ); + if ( !aSuggestedName.getLength() ) + aSuggestedName = aModelData.GetDocProps().getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SuggestedSaveAsName" ) ), ::rtl::OUString() ); + + ::rtl::OUString sStandardDir; + ::comphelper::SequenceAsHashMap::const_iterator aStdDirIter = + aModelData.GetMediaDescr().find( ::rtl::OUString::createFromAscii( "StandardDir" ) ); + if ( aStdDirIter != aModelData.GetMediaDescr().end() ) + aStdDirIter->second >>= sStandardDir; + + ::com::sun::star::uno::Sequence< ::rtl::OUString > aBlackList; + + ::comphelper::SequenceAsHashMap::const_iterator aBlackListIter = + aModelData.GetMediaDescr().find( ::rtl::OUString::createFromAscii( "BlackList" ) ); + if ( aBlackListIter != aModelData.GetMediaDescr().end() ) + aBlackListIter->second >>= aBlackList; + + sal_Bool bExit = sal_False; + while ( !bExit ) + { + bUseFilterOptions = aModelData.OutputFileDialog( nStoreMode, aFilterProps, bSetStandardName, aSuggestedName, bPreselectPassword, aSuggestedDir, nDialog, sStandardDir, aBlackList ); + + // in case the dialog is opend a second time the folder should be the same as before, not what was handed over by parameters + aSuggestedDir = ::rtl::OUString(); + if ( nStoreMode == SAVEAS_REQUESTED ) + { + // in case of saving check filter for possible alien warning + ::rtl::OUString aSelFilterName = aModelData.GetMediaDescr().getUnpackedValueOrDefault( + aFilterNameString, + ::rtl::OUString() ); + sal_Int8 nStatusFilterSave = aModelData.CheckFilter( aSelFilterName ); + if ( nStatusFilterSave == STATUS_SAVEAS_STANDARDNAME ) + { + // switch to best filter + bSetStandardName = sal_True; + } + else if ( nStatusFilterSave == STATUS_SAVE ) + { + // user confirmed alien filter or "good" filter is used + bExit = sal_True; + } + } + else + bExit = sal_True; + } + + bDialogUsed = sal_True; + aFileNameIter = aModelData.GetMediaDescr().find( ::rtl::OUString::createFromAscii( "URL" ) ); + } + else + { + // the target file name is provided so check if new filter options + // are provided or old options can be used + if ( aFilterFromMediaDescr.equals( aOldFilterName ) ) + { + ::comphelper::SequenceAsHashMap::const_iterator aIter = + aModelData.GetDocProps().find( aFilterOptionsString ); + if ( aIter != aModelData.GetDocProps().end() + && aModelData.GetMediaDescr().find( aFilterOptionsString ) == aModelData.GetMediaDescr().end() ) + aModelData.GetMediaDescr()[aIter->first] = aIter->second; + + aIter = aModelData.GetDocProps().find( aFilterDataString ); + if ( aIter != aModelData.GetDocProps().end() + && aModelData.GetMediaDescr().find( aFilterDataString ) == aModelData.GetMediaDescr().end() ) + aModelData.GetMediaDescr()[aIter->first] = aIter->second; + } + } + + if ( aFileNameIter != aModelData.GetMediaDescr().end() ) + { + ::rtl::OUString aFileName; + aFileNameIter->second >>= aFileName; + aURL.SetURL( aFileName ); + DBG_ASSERT( aURL.GetProtocol() != INET_PROT_NOT_VALID, "Illegal URL!" ); + + ::comphelper::SequenceAsHashMap::const_iterator aIter = + aModelData.GetMediaDescr().find( aFilterNameString ); + + if ( aIter != aModelData.GetMediaDescr().end() ) + aIter->second >>= aFilterName; + else + aModelData.GetMediaDescr()[aFilterNameString] <<= aFilterName; + + DBG_ASSERT( aFilterName.getLength(), "Illegal filter!" ); + } + else + { + DBG_ASSERT( sal_False, "This code must be unreachable!\n" ); + throw task::ErrorCodeIOException( ::rtl::OUString(), + uno::Reference< uno::XInterface >(), + ERRCODE_IO_INVALIDPARAMETER ); + } + + ::comphelper::SequenceAsHashMap::const_iterator aIter = + aModelData.GetMediaDescr().find( ::rtl::OUString::createFromAscii( "FilterFlags" ) ); + sal_Bool bFilterFlagsSet = ( aIter != aModelData.GetMediaDescr().end() ); + + if( !( nStoreMode & PDFEXPORT_REQUESTED ) && !bFilterFlagsSet + && ( ( nStoreMode & EXPORT_REQUESTED ) || bUseFilterOptions ) ) + { + // execute filter options dialog + if ( aModelData.ExecuteFilterDialog_Impl( aFilterName ) ) + bDialogUsed = sal_True; + } + + // so the arguments will not change any more and can be stored to the main location + aArgsSequence = aModelData.GetMediaDescr().getAsConstPropertyValueList(); + + // store the document and handle it's docinfo + SvtSaveOptions aOptions; + + DocumentSettingsGuard aSettingsGuard( aModelData.GetModel(), aModelData.IsRecommendReadOnly(), nStoreMode & EXPORT_REQUESTED ); + + if ( aOptions.IsDocInfoSave() + && ( !aModelData.GetStorable()->hasLocation() + || INetURLObject( aModelData.GetStorable()->getLocation() ) != aURL ) ) + { + // this is defenitly not a Save operation + // so the document info can be updated + + // on export document info must be preserved + uno::Reference<document::XDocumentInfoSupplier> xDIS( + aModelData.GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<util::XCloneable> xCloneable( + xDIS->getDocumentInfo(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentInfo> xOldDocInfo( + xCloneable->createClone(), uno::UNO_QUERY_THROW); + + // use dispatch API to show document info dialog + if ( aModelData.ShowDocumentInfoDialog() ) + bDialogUsed = sal_True; + else + { + DBG_ERROR( "Can't execute document info dialog!\n" ); + } + + try { + // Document properties can contain streams that should be freed before storing + aModelData.FreeDocumentProps(); + if ( ( nStoreMode & EXPORT_REQUESTED ) ) + aModelData.GetStorable()->storeToURL( aURL.GetMainURL( INetURLObject::NO_DECODE ), aArgsSequence ); + else + aModelData.GetStorable()->storeAsURL( aURL.GetMainURL( INetURLObject::NO_DECODE ), aArgsSequence ); + } + catch( uno::Exception& ) + { + if ( ( nStoreMode & EXPORT_REQUESTED ) ) + SetDocInfoState( aModelData.GetModel(), xOldDocInfo, sal_True ); + + throw; + } + + if ( ( nStoreMode & EXPORT_REQUESTED ) ) + SetDocInfoState( aModelData.GetModel(), xOldDocInfo, sal_True ); + } + else + { + // Document properties can contain streams that should be freed before storing + aModelData.FreeDocumentProps(); + + // this is actually a save operation with different parameters + // so storeTo or storeAs without DocInfo operations are used + if ( ( nStoreMode & EXPORT_REQUESTED ) ) + aModelData.GetStorable()->storeToURL( aURL.GetMainURL( INetURLObject::NO_DECODE ), aArgsSequence ); + else + aModelData.GetStorable()->storeAsURL( aURL.GetMainURL( INetURLObject::NO_DECODE ), aArgsSequence ); + } + + return bDialogUsed; +} + +//------------------------------------------------------------------------- +// static +uno::Sequence< beans::PropertyValue > SfxStoringHelper::SearchForFilter( + const uno::Reference< container::XContainerQuery >& xFilterQuery, + const uno::Sequence< beans::NamedValue >& aSearchRequest, + sal_Int32 nMustFlags, + sal_Int32 nDontFlags ) +{ + uno::Sequence< beans::PropertyValue > aFilterProps; + uno::Reference< container::XEnumeration > xFilterEnum = + xFilterQuery->createSubSetEnumerationByProperties( aSearchRequest ); + + // the first default filter will be taken, + // if there is no filter with flag default the first acceptable filter will be taken + if ( xFilterEnum.is() ) + { + while ( xFilterEnum->hasMoreElements() ) + { + uno::Sequence< beans::PropertyValue > aProps; + if ( xFilterEnum->nextElement() >>= aProps ) + { + ::comphelper::SequenceAsHashMap aPropsHM( aProps ); + sal_Int32 nFlags = aPropsHM.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "Flags" ), + (sal_Int32)0 ); + if ( ( ( nFlags & nMustFlags ) == nMustFlags ) && !( nFlags & nDontFlags ) ) + { + if ( ( nFlags & SFX_FILTER_DEFAULT ) == SFX_FILTER_DEFAULT ) + { + aFilterProps = aProps; + break; + } + else if ( !aFilterProps.getLength() ) + aFilterProps = aProps; + } + } + } + } + + return aFilterProps; +} + +//------------------------------------------------------------------------- +// static +sal_Bool SfxStoringHelper::CheckFilterOptionsAppearence( + const uno::Reference< container::XNameAccess >& xFilterCFG, + const ::rtl::OUString& aFilterName ) +{ + sal_Bool bUseFilterOptions = sal_False; + + DBG_ASSERT( xFilterCFG.is(), "No filter configuration!\n" ); + if( xFilterCFG.is() ) + { + try { + uno::Sequence < beans::PropertyValue > aProps; + uno::Any aAny = xFilterCFG->getByName( aFilterName ); + if ( aAny >>= aProps ) + { + ::comphelper::SequenceAsHashMap aPropsHM( aProps ); + ::rtl::OUString aServiceName = aPropsHM.getUnpackedValueOrDefault( + ::rtl::OUString::createFromAscii( "UIComponent" ), + ::rtl::OUString() ); + if( aServiceName.getLength() ) + bUseFilterOptions = sal_True; + } + } + catch( uno::Exception& ) + { + } + } + + return bUseFilterOptions; +} + +//------------------------------------------------------------------------- +// static +void SfxStoringHelper::SetDocInfoState( + const uno::Reference< frame::XModel >& xModel, + const uno::Reference< document::XDocumentInfo >& i_xOldDocInfo, + sal_Bool bNoModify ) +{ + uno::Reference< document::XDocumentInfoSupplier > xModelDocInfoSupplier( xModel, uno::UNO_QUERY ); + if ( !xModelDocInfoSupplier.is() ) + throw uno::RuntimeException(); // TODO: + + uno::Reference< document::XDocumentInfo > xDocInfoToFill = xModelDocInfoSupplier->getDocumentInfo(); + uno::Reference< beans::XPropertySet > xPropSet( i_xOldDocInfo, + uno::UNO_QUERY_THROW ); + + uno::Reference< util::XModifiable > xModifiable( xModel, uno::UNO_QUERY ); + if ( bNoModify && !xModifiable.is() ) + throw uno::RuntimeException(); + + sal_Bool bIsModified = bNoModify && xModifiable->isModified(); + + try + { + uno::Reference< beans::XPropertySet > xSet( xDocInfoToFill, uno::UNO_QUERY ); + uno::Reference< beans::XPropertyContainer > xContainer( xSet, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySetInfo > xSetInfo = xSet->getPropertySetInfo(); + uno::Sequence< beans::Property > lProps = xSetInfo->getProperties(); + const beans::Property* pProps = lProps.getConstArray(); + sal_Int32 c = lProps.getLength(); + sal_Int32 i = 0; + for (i=0; i<c; ++i) + { + uno::Any aValue = xPropSet->getPropertyValue( pProps[i].Name ); + if ( pProps[i].Attributes & ::com::sun::star::beans::PropertyAttribute::REMOVABLE ) + // QUESTION: DefaultValue?! + xContainer->addProperty( pProps[i].Name, pProps[i].Attributes, aValue ); + try + { + // it is possible that the propertysets from XML and binary files differ; we shouldn't break then + xSet->setPropertyValue( pProps[i].Name, aValue ); + } + catch ( uno::Exception& ) {} + } + + sal_Int16 nCount = i_xOldDocInfo->getUserFieldCount(); + sal_Int16 nSupportedCount = xDocInfoToFill->getUserFieldCount(); + for ( sal_Int16 nInd = 0; nInd < nCount && nInd < nSupportedCount; nInd++ ) + { + ::rtl::OUString aPropName = i_xOldDocInfo->getUserFieldName( nInd ); + xDocInfoToFill->setUserFieldName( nInd, aPropName ); + ::rtl::OUString aPropVal = i_xOldDocInfo->getUserFieldValue( nInd ); + xDocInfoToFill->setUserFieldValue( nInd, aPropVal ); + } + } + catch ( uno::Exception& ) {} + + // set the modified flag back if required + if ( bNoModify && bIsModified != xModifiable->isModified() ) + xModifiable->setModified( bIsModified ); +} + +//------------------------------------------------------------------------- +// static +sal_Bool SfxStoringHelper::WarnUnacceptableFormat( const uno::Reference< frame::XModel >& xModel, + ::rtl::OUString aOldUIName, + ::rtl::OUString /*aDefUIName*/, + sal_Bool /*bCanProceedFurther*/ ) +{ + if ( !SvtSaveOptions().IsWarnAlienFormat() ) + return sal_True; + + Window* pWin = SfxStoringHelper::GetModelWindow( xModel ); + SfxAlienWarningDialog aDlg( pWin, aOldUIName ); + + return aDlg.Execute() == RET_OK; +} + +// static +void SfxStoringHelper::ExecuteFilterDialog( SfxStoringHelper& _rStorageHelper + ,const ::rtl::OUString& _sFilterName + ,const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel >& _xModel + ,/*OUT*/::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& _rArgsSequence) +{ + ModelData_Impl aModelData( _rStorageHelper, _xModel, _rArgsSequence ); + if ( aModelData.ExecuteFilterDialog_Impl( _sFilterName ) ) + _rArgsSequence = aModelData.GetMediaDescr().getAsConstPropertyValueList(); +} + +// static +Window* SfxStoringHelper::GetModelWindow( const uno::Reference< frame::XModel >& xModel ) +{ + Window* pWin = 0; + try { + if ( xModel.is() ) + { + uno::Reference< frame::XController > xController = xModel->getCurrentController(); + if ( xController.is() ) + { + uno::Reference< frame::XFrame > xFrame = xController->getFrame(); + if ( xFrame.is() ) + { + uno::Reference< awt::XWindow > xWindow = xFrame->getContainerWindow(); + if ( xWindow.is() ) + { + VCLXWindow* pVCLWindow = VCLXWindow::GetImplementation( xWindow ); + if ( pVCLWindow ) + pWin = pVCLWindow->GetWindow(); + } + } + } + } + } + catch ( uno::Exception& ) + { + } + + return pWin; +} + diff --git a/sfx2/source/doc/iframe.cxx b/sfx2/source/doc/iframe.cxx new file mode 100644 index 000000000000..3ad0cc51a923 --- /dev/null +++ b/sfx2/source/doc/iframe.cxx @@ -0,0 +1,397 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include "iframe.hxx" +#include <sfx2/sfxdlg.hxx> +#include <sfx2/sfxsids.hrc> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/frame/XFramesSupplier.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> + +#include <tools/urlobj.hxx> +#include <tools/debug.hxx> +#include <rtl/ustring.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <svtools/miscopt.hxx> +#include <vcl/window.hxx> + +using namespace ::com::sun::star; + +namespace sfx2 +{ + +class IFrameWindow_Impl : public Window +{ + uno::Reference < frame::XFrame > mxFrame; + sal_Bool bActive; + sal_Bool bBorder; + +public: + IFrameWindow_Impl( Window *pParent, + sal_Bool bHasBorder, + WinBits nWinBits = 0 ); + +public: + void SetBorder( sal_Bool bNewBorder = sal_True ); + sal_Bool HasBorder() const { return bBorder; } +}; + +IFrameWindow_Impl::IFrameWindow_Impl( Window *pParent, sal_Bool bHasBorder, WinBits nWinBits ) + : Window( pParent, nWinBits | WB_CLIPCHILDREN | WB_NODIALOGCONTROL | WB_DOCKBORDER ) + , bActive(sal_False) + , bBorder(bHasBorder) +{ + if ( !bHasBorder ) + SetBorderStyle( WINDOW_BORDER_NOBORDER ); + else + SetBorderStyle( WINDOW_BORDER_NORMAL ); + //SetActivateMode( ACTIVATE_MODE_GRABFOCUS ); +} + +void IFrameWindow_Impl::SetBorder( sal_Bool bNewBorder ) +{ + if ( bBorder != bNewBorder ) + { + Size aSize = GetSizePixel(); + bBorder = bNewBorder; + if ( bBorder ) + SetBorderStyle( WINDOW_BORDER_NORMAL ); + else + SetBorderStyle( WINDOW_BORDER_NOBORDER ); + if ( GetSizePixel() != aSize ) + SetSizePixel( aSize ); + } +} + +#define PROPERTY_UNBOUND 0 + +#define WID_FRAME_URL 1 +#define WID_FRAME_NAME 2 +#define WID_FRAME_IS_AUTO_SCROLL 3 +#define WID_FRAME_IS_SCROLLING_MODE 4 +#define WID_FRAME_IS_BORDER 5 +#define WID_FRAME_IS_AUTO_BORDER 6 +#define WID_FRAME_MARGIN_WIDTH 7 +#define WID_FRAME_MARGIN_HEIGHT 8 + +const SfxItemPropertyMapEntry* lcl_GetIFramePropertyMap_Impl() +{ + static SfxItemPropertyMapEntry aIFramePropertyMap_Impl[] = + { + { MAP_CHAR_LEN("FrameIsAutoBorder"), WID_FRAME_IS_AUTO_BORDER, &::getBooleanCppuType(), PROPERTY_UNBOUND, 0 }, + { MAP_CHAR_LEN("FrameIsAutoScroll"), WID_FRAME_IS_AUTO_SCROLL, &::getBooleanCppuType(), PROPERTY_UNBOUND, 0 }, + { MAP_CHAR_LEN("FrameIsBorder"), WID_FRAME_IS_BORDER, &::getBooleanCppuType(), PROPERTY_UNBOUND, 0 }, + { MAP_CHAR_LEN("FrameIsScrollingMode"), WID_FRAME_IS_SCROLLING_MODE, &::getBooleanCppuType(), PROPERTY_UNBOUND, 0 }, + { MAP_CHAR_LEN("FrameMarginHeight"), WID_FRAME_MARGIN_HEIGHT, &::getCppuType( (sal_Int32*)0 ), PROPERTY_UNBOUND, 0 }, + { MAP_CHAR_LEN("FrameMarginWidth"), WID_FRAME_MARGIN_WIDTH, &::getCppuType( (sal_Int32*)0 ), PROPERTY_UNBOUND, 0 }, + { MAP_CHAR_LEN("FrameName"), WID_FRAME_NAME, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + { MAP_CHAR_LEN("FrameURL"), WID_FRAME_URL, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + {0,0,0,0,0,0} + }; + return aIFramePropertyMap_Impl; +} + +SFX_IMPL_XSERVICEINFO( IFrameObject, "com.sun.star.embed.SpecialEmbeddedObject", "com.sun.star.comp.sfx2.IFrameObject" ) +SFX_IMPL_SINGLEFACTORY( IFrameObject ); + +IFrameObject::IFrameObject( const uno::Reference < lang::XMultiServiceFactory >& rFact ) + : mxFact( rFact ) + , maPropMap( lcl_GetIFramePropertyMap_Impl() ) +{ +} + +IFrameObject::~IFrameObject() +{ +} + + +void SAL_CALL IFrameObject::initialize( const uno::Sequence< uno::Any >& aArguments ) throw ( uno::Exception, uno::RuntimeException ) +{ + if ( aArguments.getLength() ) + aArguments[0] >>= mxObj; +} + +sal_Bool SAL_CALL IFrameObject::load( + const uno::Sequence < com::sun::star::beans::PropertyValue >& /*lDescriptor*/, + const uno::Reference < frame::XFrame >& xFrame ) +throw( uno::RuntimeException ) +{ + if ( SvtMiscOptions().IsPluginsEnabled() ) + { + DBG_ASSERT( !mxFrame.is(), "Frame already existing!" ); + Window* pParent = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() ); + IFrameWindow_Impl* pWin = new IFrameWindow_Impl( pParent, maFrmDescr.IsFrameBorderOn() ); + pWin->SetSizePixel( pParent->GetOutputSizePixel() ); + pWin->SetBackground(); + pWin->Show(); + + uno::Reference < awt::XWindow > xWindow( pWin->GetComponentInterface(), uno::UNO_QUERY ); + xFrame->setComponent( xWindow, uno::Reference < frame::XController >() ); + + // we must destroy the IFrame before the parent is destroyed + xWindow->addEventListener( this ); + + mxFrame = uno::Reference< frame::XFrame >( mxFact->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.frame.Frame" ) ), + uno::UNO_QUERY ); + uno::Reference < awt::XWindow > xWin( pWin->GetComponentInterface(), uno::UNO_QUERY ); + mxFrame->initialize( xWin ); + mxFrame->setName( maFrmDescr.GetName() ); + + uno::Reference < frame::XFramesSupplier > xFramesSupplier( xFrame, uno::UNO_QUERY ); + if ( xFramesSupplier.is() ) + mxFrame->setCreator( xFramesSupplier ); + + uno::Reference< frame::XDispatchProvider > xProv( mxFrame, uno::UNO_QUERY ); + + util::URL aTargetURL; + aTargetURL.Complete = ::rtl::OUString( maFrmDescr.GetURL().GetMainURL( INetURLObject::NO_DECODE ) ); + uno::Reference < util::XURLTransformer > xTrans( mxFact->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), uno::UNO_QUERY ); + xTrans->parseStrict( aTargetURL ); + + uno::Sequence < beans::PropertyValue > aProps(2); + aProps[0].Name = ::rtl::OUString::createFromAscii("PluginMode"); + aProps[0].Value <<= (sal_Int16) 2; + aProps[1].Name = ::rtl::OUString::createFromAscii("ReadOnly"); + aProps[1].Value <<= (sal_Bool) sal_True; + uno::Reference < frame::XDispatch > xDisp = xProv->queryDispatch( aTargetURL, ::rtl::OUString::createFromAscii("_self"), 0 ); + if ( xDisp.is() ) + xDisp->dispatch( aTargetURL, aProps ); + + return TRUE; + } + + return FALSE; +} + +void SAL_CALL IFrameObject::cancel() throw( com::sun::star::uno::RuntimeException ) +{ + try + { + uno::Reference < util::XCloseable > xClose( mxFrame, uno::UNO_QUERY ); + if ( xClose.is() ) + xClose->close( sal_True ); + mxFrame = 0; + } + catch ( uno::Exception& ) + {} +} + +void SAL_CALL IFrameObject::close( sal_Bool /*bDeliverOwnership*/ ) throw( com::sun::star::util::CloseVetoException, com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL IFrameObject::addCloseListener( const com::sun::star::uno::Reference < com::sun::star::util::XCloseListener >& ) throw( com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL IFrameObject::removeCloseListener( const com::sun::star::uno::Reference < com::sun::star::util::XCloseListener >& ) throw( com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL IFrameObject::disposing( const com::sun::star::lang::EventObject& ) throw (com::sun::star::uno::RuntimeException) +{ + cancel(); +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL IFrameObject::getPropertySetInfo() throw( ::com::sun::star::uno::RuntimeException ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo = new SfxItemPropertySetInfo( &maPropMap ); + return xInfo; +} + +void SAL_CALL IFrameObject::setPropertyValue(const ::rtl::OUString& aPropertyName, const uno::Any& aAny) + throw ( beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException) +{ + const SfxItemPropertySimpleEntry* pEntry = maPropMap.getByName( aPropertyName ); + if( !pEntry ) + throw beans::UnknownPropertyException(); + switch( pEntry->nWID ) + { + case WID_FRAME_URL: + { + ::rtl::OUString aURL; + aAny >>= aURL; + maFrmDescr.SetURL( String(aURL) ); + } + break; + case WID_FRAME_NAME: + { + ::rtl::OUString aName; + if ( aAny >>= aName ) + maFrmDescr.SetName( aName ); + } + break; + case WID_FRAME_IS_AUTO_SCROLL: + { + sal_Bool bIsAutoScroll = sal_Bool(); + if ( (aAny >>= bIsAutoScroll) && bIsAutoScroll ) + maFrmDescr.SetScrollingMode( ScrollingAuto ); + } + break; + case WID_FRAME_IS_SCROLLING_MODE: + { + sal_Bool bIsScroll = sal_Bool(); + if ( aAny >>= bIsScroll ) + maFrmDescr.SetScrollingMode( bIsScroll ? ScrollingYes : ScrollingNo ); + } + break; + case WID_FRAME_IS_BORDER: + { + sal_Bool bIsBorder = sal_Bool(); + if ( aAny >>= bIsBorder ) + maFrmDescr.SetFrameBorder( bIsBorder ); + } + break; + case WID_FRAME_IS_AUTO_BORDER: + { + sal_Bool bIsAutoBorder = sal_Bool(); + if ( (aAny >>= bIsAutoBorder) ) + { + BOOL bBorder = maFrmDescr.IsFrameBorderOn(); + maFrmDescr.ResetBorder(); + if ( bIsAutoBorder ) + maFrmDescr.SetFrameBorder( bBorder ); + } + } + break; + case WID_FRAME_MARGIN_WIDTH: + { + sal_Int32 nMargin = 0; + Size aSize = maFrmDescr.GetMargin(); + if ( aAny >>= nMargin ) + { + aSize.Width() = nMargin; + maFrmDescr.SetMargin( aSize ); + } + } + break; + case WID_FRAME_MARGIN_HEIGHT: + { + sal_Int32 nMargin = 0; + Size aSize = maFrmDescr.GetMargin(); + if ( aAny >>= nMargin ) + { + aSize.Height() = nMargin; + maFrmDescr.SetMargin( aSize ); + } + } + break; + default: ; + } +} + +uno::Any SAL_CALL IFrameObject::getPropertyValue(const ::rtl::OUString& aPropertyName) + throw ( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + const SfxItemPropertySimpleEntry* pEntry = maPropMap.getByName( aPropertyName ); + if( !pEntry ) + throw beans::UnknownPropertyException(); + uno::Any aAny; + switch( pEntry->nWID ) + { + case WID_FRAME_URL: + { + aAny <<= ::rtl::OUString( maFrmDescr.GetURL().GetMainURL( INetURLObject::NO_DECODE ) ); + } + break; + case WID_FRAME_NAME: + { + aAny <<= ::rtl::OUString( maFrmDescr.GetName() ); + } + break; + case WID_FRAME_IS_AUTO_SCROLL: + { + sal_Bool bIsAutoScroll = ( maFrmDescr.GetScrollingMode() == ScrollingAuto ); + aAny <<= bIsAutoScroll; + } + break; + case WID_FRAME_IS_SCROLLING_MODE: + { + sal_Bool bIsScroll = ( maFrmDescr.GetScrollingMode() == ScrollingYes ); + aAny <<= bIsScroll; + } + break; + case WID_FRAME_IS_BORDER: + { + sal_Bool bIsBorder = maFrmDescr.IsFrameBorderOn(); + aAny <<= bIsBorder; + } + break; + case WID_FRAME_IS_AUTO_BORDER: + { + sal_Bool bIsAutoBorder = !maFrmDescr.IsFrameBorderSet(); + aAny <<= bIsAutoBorder; + } + break; + case WID_FRAME_MARGIN_WIDTH: + { + aAny <<= (sal_Int32 ) maFrmDescr.GetMargin().Width(); + } + break; + case WID_FRAME_MARGIN_HEIGHT: + { + aAny <<= (sal_Int32 ) maFrmDescr.GetMargin().Height(); + } + default: ; + } + return aAny; +} + +void SAL_CALL IFrameObject::addPropertyChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL IFrameObject::removePropertyChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL IFrameObject::addVetoableChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL IFrameObject::removeVetoableChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException ) +{ +} + +::sal_Int16 SAL_CALL IFrameObject::execute() throw (::com::sun::star::uno::RuntimeException) +{ + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + VclAbstractDialog* pDlg = pFact->CreateEditObjectDialog( NULL, SID_INSERT_FLOATINGFRAME, mxObj ); + if ( pDlg ) + pDlg->Execute(); + return 0; +} + +void SAL_CALL IFrameObject::setTitle( const ::rtl::OUString& ) throw (::com::sun::star::uno::RuntimeException) +{ +} + +} diff --git a/sfx2/source/doc/makefile.mk b/sfx2/source/doc/makefile.mk new file mode 100644 index 000000000000..b1bddf82e428 --- /dev/null +++ b/sfx2/source/doc/makefile.mk @@ -0,0 +1,105 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=sfx2 +TARGET=doc +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +.IF "$(SYSTEM_LIBXML)" == "YES" +CFLAGS+=-DSYSTEM_LIBXML $(LIBXML_CFLAGS) +.ENDIF + +# --- Files -------------------------------------------------------- + +SRS1NAME=$(TARGET) +SRC1FILES = \ + doc.src new.src doctdlg.src docvor.src doctempl.src graphhelp.src + +SLOFILES = \ + $(SLO)$/printhelper.obj \ + $(SLO)$/docinf.obj \ + $(SLO)$/oleprops.obj \ + $(SLO)$/iframe.obj \ + $(SLO)$/plugin.obj \ + $(SLO)$/docfile.obj \ + $(SLO)$/objuno.obj \ + $(SLO)$/frmdescr.obj \ + $(SLO)$/objxtor.obj \ + $(SLO)$/objmisc.obj \ + $(SLO)$/objstor.obj \ + $(SLO)$/objcont.obj \ + $(SLO)$/objserv.obj \ + $(SLO)$/objitem.obj \ + $(SLO)$/ownsubfilterservice.obj \ + $(SLO)$/docfac.obj \ + $(SLO)$/docfilt.obj \ + $(SLO)$/doctempl.obj \ + $(SLO)$/doctemplates.obj \ + $(SLO)$/doctemplateslocal.obj \ + $(SLO)$/docvor.obj \ + $(SLO)$/new.obj \ + $(SLO)$/doctdlg.obj \ + $(SLO)$/sfxbasemodel.obj \ + $(SLO)$/guisaveas.obj\ + $(SLO)$/objembed.obj\ + $(SLO)$/graphhelp.obj \ + $(SLO)$/QuerySaveDocument.obj \ + $(SLO)$/docinsert.obj \ + $(SLO)$/docmacromode.obj \ + $(SLO)$/SfxDocumentMetaData.obj \ + $(SLO)$/DocumentMetadataAccess.obj \ + $(SLO)$/Metadatable.obj \ + $(SLO)$/sfxmodelfactory.obj \ + $(SLO)$/sfxacldetect.obj \ + $(SLO)$/docstoragemodifylistener.obj \ + $(SLO)$/querytemplate.obj \ + $(SLO)$/syspath.obj \ + $(SLO)$/syspathw32.obj + +# $(SLO)$/applet.obj \ + +.IF "$(GUI)" == "WNT" + +#HACK TO DISABLE PCH +NOOPTFILES= \ + $(SLO)$/sfxacldetect.obj \ + $(SLO)$/syspathw32.obj +.ENDIF + + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + + diff --git a/sfx2/source/doc/new.cxx b/sfx2/source/doc/new.cxx new file mode 100644 index 000000000000..d3235b1c7a7f --- /dev/null +++ b/sfx2/source/doc/new.cxx @@ -0,0 +1,745 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" +#include <sfx2/new.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/morebtn.hxx> +#ifndef _SVMEDIT_HXX +#include <svtools/svmedit.hxx> +#endif +#include <svl/itemset.hxx> +#include <svl/eitem.hxx> +#include <svtools/sfxecode.hxx> +#include <svtools/ehdl.hxx> +#include <tools/urlobj.hxx> +#include <unotools/localfilehelper.hxx> + +#include "new.hrc" +#ifndef _SFX_DOC_HRC +#include "doc.hrc" +#endif +#include <sfx2/sfx.hrc> +#include "helpid.hrc" +#include "sfxtypes.hxx" +#include <sfx2/app.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/docfac.hxx> +#include <sfx2/objsh.hxx> +#include "fltfnc.hxx" +#include <sfx2/viewsh.hxx> +#include "viewfac.hxx" +#include "sfxresid.hxx" +#include <sfx2/docfile.hxx> +#include "preview.hxx" +#include <sfx2/printer.hxx> +#include <vcl/waitobj.hxx> +#include <vcl/virdev.hxx> +#include <vcl/jobset.hxx> +#include <svtools/accessibilityoptions.hxx> + +// Draw modes +#define OUTPUT_DRAWMODE_COLOR (DRAWMODE_DEFAULT) +#define OUTPUT_DRAWMODE_GRAYSCALE (DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_BLACKTEXT | DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT) +#define OUTPUT_DRAWMODE_BLACKWHITE (DRAWMODE_BLACKLINE | DRAWMODE_BLACKTEXT | DRAWMODE_WHITEFILL | DRAWMODE_GRAYBITMAP | DRAWMODE_WHITEGRADIENT) +#define OUTPUT_DRAWMODE_CONTRAST (DRAWMODE_SETTINGSLINE | DRAWMODE_SETTINGSFILL | DRAWMODE_SETTINGSTEXT | DRAWMODE_SETTINGSGRADIENT) + +//======================================================================== + +#define MORE_BTN(x) pMoreBt->x + +//======================================================================== + +void SfxPreviewBase_Impl::SetObjectShell( SfxObjectShell* pObj ) +{ + ::boost::shared_ptr<GDIMetaFile> pFile = pObj + ? pObj->GetPreviewMetaFile() + : ::boost::shared_ptr<GDIMetaFile>(); + pMetaFile = pFile; + Invalidate(); +} + +SfxPreviewBase_Impl::SfxPreviewBase_Impl( + Window* pParent, const ResId& rResId ) + : Window(pParent, rResId), pMetaFile() +{ +} + +SfxPreviewBase_Impl::SfxPreviewBase_Impl( Window* pParent ) + : Window(pParent, 0 ), pMetaFile() +{ + Resize(); + Show(); +} + +SfxPreviewBase_Impl::~SfxPreviewBase_Impl() +{ +} + +void SfxPreviewBase_Impl::Resize() +{ + Invalidate(); +} + +void SfxPreviewBase_Impl::SetGDIFile( ::boost::shared_ptr<GDIMetaFile> pFile ) +{ + pMetaFile = pFile; + Invalidate(); +} + +SfxFrameWindow* SfxPreviewWin_Impl::PreviewFactory( + SfxFrame* pFrame, const String& /*rName*/ ) +{ + return new SfxFrameWindow( new SfxPreviewWin_Impl( + &pFrame->GetCurrentViewFrame()->GetWindow() ) ); +} + +void SfxPreviewWin_Impl::ImpPaint( + const Rectangle&, GDIMetaFile* pFile, Window* pWindow ) +{ + Size aTmpSize = pFile ? pFile->GetPrefSize() : Size(1,1 ); + DBG_ASSERT( aTmpSize.Height()*aTmpSize.Width(), + "size of first page is 0, overload GetFirstPageSize or set vis-area!" ); +#define FRAME 4 + long nWidth = pWindow->GetOutputSize().Width() - 2*FRAME; + long nHeight = pWindow->GetOutputSize().Height() - 2*FRAME; + if( nWidth < 0 ) nWidth = 0; + if( nHeight < 0 ) nHeight = 0; + + double dRatio=((double)aTmpSize.Width())/aTmpSize.Height(); + double dRatioPreV=((double) nWidth ) / nHeight; + Size aSize; + Point aPoint; + if (dRatio>dRatioPreV) + { + aSize=Size(nWidth, (USHORT)(nWidth/dRatio)); + aPoint=Point( 0, (USHORT)((nHeight-aSize.Height())/2)); + } + else + { + aSize=Size((USHORT)(nHeight*dRatio), nHeight); + aPoint=Point((USHORT)((nWidth-aSize.Width())/2),0); + } + Point bPoint=Point(nWidth,nHeight)-aPoint; + + + pWindow->SetLineColor(); + Color aLightGrayCol( COL_LIGHTGRAY ); + pWindow->SetFillColor( aLightGrayCol ); + pWindow->DrawRect( Rectangle( Point( 0,0 ), pWindow->GetOutputSize() ) ); + if ( pFile ) + { + Color aBlackCol( COL_BLACK ); + Color aWhiteCol( COL_WHITE ); + pWindow->SetLineColor( aBlackCol ); + pWindow->SetFillColor( aWhiteCol ); + pWindow->DrawRect( Rectangle( aPoint + Point( FRAME, FRAME ), bPoint + Point( FRAME, FRAME ) ) ); +//! pFile->Move( Point( FRAME, FRAME ) ); +//! pFile->Scale( Fraction( aTmpSize.Width(), aSize.Width() ), +//! Fraction( aTmpSize.Height(), aSize.Height() ) ); + pFile->WindStart(); + pFile->Play( pWindow, aPoint + Point( FRAME, FRAME ), aSize ); + } +} + +void SfxPreviewWin_Impl::Paint( const Rectangle& rRect ) +{ + ImpPaint( rRect, pMetaFile.get(), this ); +} + +SfxPreviewWin::SfxPreviewWin( + Window* pParent, const ResId& rResId, SfxObjectShellLock &rDocSh ) + : Window(pParent, rResId), rDocShell( rDocSh ) +{ + SetHelpId( HID_PREVIEW_FRAME ); + + // adjust contrast mode initially + bool bUseContrast = UseHighContrastSetting(); + SetDrawMode( bUseContrast ? OUTPUT_DRAWMODE_CONTRAST : OUTPUT_DRAWMODE_COLOR ); + + // #107818# This preview window is for document previews. Therefore + // right-to-left mode should be off + EnableRTL( FALSE ); +} + +void SfxPreviewWin::Paint( const Rectangle& rRect ) +{ + SfxViewFrame *pFrame = SfxViewFrame::GetFirst( &rDocShell ); + if ( pFrame && pFrame->GetViewShell() && + pFrame->GetViewShell()->GetPrinter() && + pFrame->GetViewShell()->GetPrinter()->IsPrinting() ) + { + return; + } + + Size aTmpSize( rDocShell->GetFirstPageSize() ); + GDIMetaFile aMtf; + VirtualDevice aDevice; + + DBG_ASSERT( aTmpSize.Height() * aTmpSize.Width(), "size of first page is 0, overload GetFirstPageSize or set vis-area!" ); + + aMtf.SetPrefSize( aTmpSize ); + aDevice.EnableOutput( FALSE ); + aDevice.SetMapMode( rDocShell->GetMapUnit() ); + aDevice.SetDrawMode( GetDrawMode() ); + aMtf.Record( &aDevice ); + rDocShell->DoDraw( &aDevice, Point(0,0), aTmpSize, JobSetup(), ASPECT_THUMBNAIL ); + aMtf.Stop(); + aMtf.WindStart(); + SfxPreviewWin_Impl::ImpPaint( rRect, &aMtf, this ); +} + +void SfxPreviewWin::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE) ) + { + // adjust contrast mode + bool bUseContrast = UseHighContrastSetting(); + SetDrawMode( bUseContrast ? OUTPUT_DRAWMODE_CONTRAST : OUTPUT_DRAWMODE_COLOR ); + } +} + +bool SfxPreviewWin::UseHighContrastSetting() const +{ + return GetSettings().GetStyleSettings().GetHighContrastMode(); +} + + +class SfxNewFileDialog_Impl +{ + FixedText aRegionFt; + ListBox aRegionLb; + FixedText aTemplateFt; + ListBox aTemplateLb; + + CheckBox aPreviewBtn; + SfxPreviewWin_Impl aPreviewWin; + + FixedText aTitleFt; + Edit aTitleEd; + FixedText aThemaFt; + Edit aThemaEd; + FixedText aKeywordsFt; + Edit aKeywordsEd; + FixedText aDescFt; + MultiLineEdit aDescEd; + FixedLine aDocinfoGb; + + CheckBox aTextStyleCB; + CheckBox aFrameStyleCB; + CheckBox aPageStyleCB; + CheckBox aNumStyleCB; + CheckBox aMergeStyleCB; + PushButton aLoadFilePB; + + OKButton aOkBt; + CancelButton aCancelBt; + HelpButton aHelpBt; + MoreButton* pMoreBt; + Timer aPrevTimer; + String aNone; + String sLoadTemplate; + + USHORT nFlags; + SfxDocumentTemplates aTemplates; + SfxObjectShellLock xDocShell; + SfxNewFileDialog* pAntiImpl; + + void ClearInfo(); + DECL_LINK( Update, void * ); + + DECL_LINK( RegionSelect, ListBox * ); + DECL_LINK( TemplateSelect, ListBox * ); + DECL_LINK( DoubleClick, ListBox * ); + void TogglePreview(CheckBox *); + DECL_LINK( Expand, MoreButton * ); + DECL_LINK( PreviewClick, CheckBox * ); + DECL_LINK( LoadFile, PushButton* ); + USHORT GetSelectedTemplatePos() const; + +public: + + SfxNewFileDialog_Impl( SfxNewFileDialog* pAntiImplP, USHORT nFlags ); + ~SfxNewFileDialog_Impl(); + + // Liefert FALSE, wenn '- Keine -' als Vorlage eingestellt ist + // Nur wenn IsTemplate() TRUE liefert, koennen Vorlagennamen + // erfragt werden + BOOL IsTemplate() const; + String GetTemplateRegion() const; + String GetTemplateName() const; + String GetTemplateFileName() const; + + USHORT GetTemplateFlags()const; + void SetTemplateFlags(USHORT nSet); +}; + + +//------------------------------------------------------------------------- + +void SfxNewFileDialog_Impl::ClearInfo() +{ + const String aNo; + aTitleEd.SetText(aNo); + aThemaEd.SetText(aNo); + aKeywordsEd.SetText(aNo); + aDescEd.SetText(aNo); +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxNewFileDialog_Impl, Update, void *, EMPTYARG ) +{ + if ( xDocShell.Is() ) + { + if ( xDocShell->GetProgress() ) + return FALSE; + xDocShell.Clear(); + } + + const USHORT nEntry = GetSelectedTemplatePos(); + if(!nEntry) + { + ClearInfo(); + aPreviewWin.Invalidate(); + aPreviewWin.SetObjectShell( 0); + return 0; + } + + if ( aPreviewBtn.IsChecked() && (nFlags & SFXWB_PREVIEW) == SFXWB_PREVIEW) + { + + String aFileName = aTemplates.GetPath( aRegionLb.GetSelectEntryPos(), nEntry-1); + INetURLObject aTestObj( aFileName ); + if( aTestObj.GetProtocol() == INET_PROT_NOT_VALID ) + { + // temp. fix until Templates are managed by UCB compatible service + // does NOT work with locally cached components ! + String aTemp; + utl::LocalFileHelper::ConvertPhysicalNameToURL( aFileName, aTemp ); + aFileName = aTemp; + } + + INetURLObject aObj( aFileName ); + for ( SfxObjectShell* pTmp = SfxObjectShell::GetFirst(); + pTmp; + pTmp = SfxObjectShell::GetNext(*pTmp) ) + { + //! fsys bug op== + if ( pTmp->GetMedium()) + // ??? HasName() MM + if( INetURLObject( pTmp->GetMedium()->GetName() ) == aObj ) + { + xDocShell = pTmp; + break; + } + } + + if ( !xDocShell.Is() ) + { + Window *pParent = Application::GetDefDialogParent(); + Application::SetDefDialogParent( pAntiImpl ); + SfxErrorContext eEC(ERRCTX_SFX_LOADTEMPLATE,pAntiImpl); + SfxApplication *pSfxApp = SFX_APP(); + ULONG lErr; + SfxItemSet* pSet = new SfxAllItemSet( pSfxApp->GetPool() ); + pSet->Put( SfxBoolItem( SID_TEMPLATE, TRUE ) ); + pSet->Put( SfxBoolItem( SID_PREVIEW, TRUE ) ); + lErr = pSfxApp->LoadTemplate( xDocShell, aFileName, TRUE, pSet ); + if( lErr ) + ErrorHandler::HandleError(lErr); + Application::SetDefDialogParent( pParent ); + if ( !xDocShell.Is() ) + { + aPreviewWin.SetObjectShell( 0 ); + return FALSE; + } + } + + aPreviewWin.SetObjectShell( xDocShell ); + } + return TRUE; +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxNewFileDialog_Impl, RegionSelect, ListBox *, pBox ) +{ + if ( xDocShell.Is() && xDocShell->GetProgress() ) + return 0; + + const USHORT nRegion = pBox->GetSelectEntryPos(); + const USHORT nCount = aTemplates.GetRegionCount()? aTemplates.GetCount(nRegion): 0; + aTemplateLb.SetUpdateMode(FALSE); + aTemplateLb.Clear(); + String aSel=aRegionLb.GetSelectEntry(); + USHORT nc=aSel.Search('('); + if (nc-1&&nc!=STRING_NOTFOUND) + aSel.Erase(nc-1); + if (aSel.CompareIgnoreCaseToAscii( String(SfxResId(STR_STANDARD)) )==COMPARE_EQUAL) + aTemplateLb.InsertEntry(aNone); + for (USHORT i = 0; i < nCount; ++i) + aTemplateLb.InsertEntry(aTemplates.GetName(nRegion, i)); + aTemplateLb.SelectEntryPos(0); + aTemplateLb.SetUpdateMode(TRUE); + aTemplateLb.Invalidate(); + aTemplateLb.Update(); + return 0; +} + +//------------------------------------------------------------------------- + +IMPL_LINK_INLINE_START( SfxNewFileDialog_Impl, Expand, MoreButton *, EMPTYARG ) +{ + TemplateSelect(&aTemplateLb); + return 0; +} +IMPL_LINK_INLINE_END( SfxNewFileDialog_Impl, Expand, MoreButton *, pMoreButton ) + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxNewFileDialog_Impl, PreviewClick, CheckBox *, pBox ) +{ + if ( xDocShell.Is() && xDocShell->GetProgress() ) + return 0; + + USHORT nEntry = GetSelectedTemplatePos(); + if ( nEntry && pBox->IsChecked() ) + { + if(!Update(0)) + aPreviewWin.Invalidate(); + } + else + { + if (xDocShell.Is()) + xDocShell.Clear(); + aPreviewWin.SetObjectShell( 0 ); + } + return 0; +} + +//------------------------------------------------------------------------- + +IMPL_LINK( SfxNewFileDialog_Impl, TemplateSelect, ListBox *, EMPTYARG ) +{ + // noch am Laden + if ( xDocShell && xDocShell->GetProgress() ) + return 0; + + if ( !MORE_BTN(GetState()) ) + // Dialog nicht aufgeklappt + return 0; + + aPrevTimer.Start(); + return 0; +} + +//------------------------------------------------------------------------- + +IMPL_LINK_INLINE_START( SfxNewFileDialog_Impl, DoubleClick, ListBox *, pListBox ) +{ + (void)pListBox; + // noch am Laden + if ( !xDocShell.Is() || !xDocShell->GetProgress() ) + pAntiImpl->EndDialog(RET_OK); + return 0; +} +IMPL_LINK_INLINE_END( SfxNewFileDialog_Impl, DoubleClick, ListBox *, pListBox ) + +//------------------------------------------------------------------------- + +IMPL_LINK_INLINE_START( SfxNewFileDialog_Impl, LoadFile, PushButton *, EMPTYARG ) +{ + pAntiImpl->EndDialog(RET_TEMPLATE_LOAD); + return 0; +} +IMPL_LINK_INLINE_END( SfxNewFileDialog_Impl, LoadFile, PushButton *, EMPTYARG ) +//------------------------------------------------------------------------- + +USHORT SfxNewFileDialog_Impl::GetSelectedTemplatePos() const +{ + USHORT nEntry=aTemplateLb.GetSelectEntryPos(); + String aSel=aRegionLb.GetSelectEntry().Copy(); + USHORT nc=aSel.Search('('); + if (nc-1&&nc!=STRING_NOTFOUND) + aSel.Erase(nc-1); + if (aSel.CompareIgnoreCaseToAscii(String(SfxResId(STR_STANDARD)))!=COMPARE_EQUAL) + nEntry++; + if (!aTemplateLb.GetSelectEntryCount()) + nEntry=0; + return nEntry; +} + +//------------------------------------------------------------------------- + +BOOL SfxNewFileDialog_Impl::IsTemplate() const +{ + return GetSelectedTemplatePos()!=0; + +} + +//------------------------------------------------------------------------- + +String SfxNewFileDialog_Impl::GetTemplateFileName() const +{ + if(!IsTemplate() || !aTemplates.GetRegionCount()) + return String(); + return aTemplates.GetPath(aRegionLb.GetSelectEntryPos(), + GetSelectedTemplatePos()-1); +} + +//------------------------------------------------------------------------- + +String SfxNewFileDialog_Impl::GetTemplateRegion() const +{ + if(!IsTemplate() || !aTemplates.GetRegionCount()) + return String(); + return aRegionLb.GetSelectEntry(); +} + +//------------------------------------------------------------------------- + +String SfxNewFileDialog_Impl::GetTemplateName() const +{ + if(!IsTemplate() || !aTemplates.GetRegionCount()) + return String(); + return aTemplateLb.GetSelectEntry(); +} + +//------------------------------------------------------------------------- + +void AdjustPosSize_Impl(Window *pWin, short nMoveOffset, short nSizeOffset) +{ + Point aPos(pWin->GetPosPixel()); + Size aSize(pWin->GetSizePixel()); + aPos.X() -= nMoveOffset; + aSize.Width() += nSizeOffset; + pWin->SetPosSizePixel(aPos, aSize); +} +//------------------------------------------------------------------------- +USHORT SfxNewFileDialog_Impl::GetTemplateFlags()const +{ + USHORT nRet = aTextStyleCB.IsChecked() ? SFX_LOAD_TEXT_STYLES : 0; + if(aFrameStyleCB.IsChecked()) + nRet |= SFX_LOAD_FRAME_STYLES; + if(aPageStyleCB.IsChecked()) + nRet |= SFX_LOAD_PAGE_STYLES; + if(aNumStyleCB.IsChecked()) + nRet |= SFX_LOAD_NUM_STYLES; + if(aMergeStyleCB.IsChecked()) + nRet |= SFX_MERGE_STYLES; + return nRet; +} +//------------------------------------------------------------------------- +void SfxNewFileDialog_Impl::SetTemplateFlags(USHORT nSet) +{ + aTextStyleCB.Check( 0 != (nSet&SFX_LOAD_TEXT_STYLES )); + aFrameStyleCB.Check( 0 != (nSet&SFX_LOAD_FRAME_STYLES)); + aPageStyleCB.Check( 0 != (nSet&SFX_LOAD_PAGE_STYLES )); + aNumStyleCB.Check( 0 != (nSet&SFX_LOAD_NUM_STYLES )); + aMergeStyleCB.Check( 0 != (nSet&SFX_MERGE_STYLES )); +} + +//------------------------------------------------------------------------- + +SfxNewFileDialog_Impl::SfxNewFileDialog_Impl( + SfxNewFileDialog* pAntiImplP, USHORT nFl) + : aRegionFt( pAntiImplP, SfxResId( FT_REGION ) ), + aRegionLb( pAntiImplP, SfxResId( LB_REGION ) ), + aTemplateFt( pAntiImplP, SfxResId( FT_TEMPLATE ) ), + aTemplateLb( pAntiImplP, SfxResId( LB_TEMPLATE ) ), + aPreviewBtn( pAntiImplP, SfxResId( BTN_PREVIEW ) ), + aPreviewWin( pAntiImplP, SfxResId( WIN_PREVIEW ) ), + aTitleFt( pAntiImplP, SfxResId( FT_TITLE ) ), + aTitleEd( pAntiImplP, SfxResId( ED_TITLE ) ), + aThemaFt( pAntiImplP, SfxResId( FT_THEMA ) ), + aThemaEd( pAntiImplP, SfxResId( ED_THEMA ) ), + aKeywordsFt( pAntiImplP, SfxResId( FT_KEYWORDS ) ), + aKeywordsEd( pAntiImplP, SfxResId( ED_KEYWORDS ) ), + aDescFt( pAntiImplP, SfxResId( FT_DESC ) ), + aDescEd( pAntiImplP, SfxResId( ED_DESC ) ), + aDocinfoGb( pAntiImplP, SfxResId( GB_DOCINFO ) ), + aTextStyleCB( pAntiImplP, SfxResId( CB_TEXT_STYLE )), + aFrameStyleCB( pAntiImplP, SfxResId( CB_FRAME_STYLE )), + aPageStyleCB( pAntiImplP, SfxResId( CB_PAGE_STYLE )), + aNumStyleCB( pAntiImplP, SfxResId( CB_NUM_STYLE )), + aMergeStyleCB( pAntiImplP, SfxResId( CB_MERGE_STYLE )), + aLoadFilePB( pAntiImplP, SfxResId( PB_LOAD_FILE )), + aOkBt( pAntiImplP, SfxResId( BT_OK ) ), + aCancelBt( pAntiImplP, SfxResId( BT_CANCEL ) ), + aHelpBt( pAntiImplP, SfxResId( BT_HELP ) ), + pMoreBt( new MoreButton( pAntiImplP, SfxResId( BT_MORE ) ) ), + aNone( SfxResId(STR_NONE) ), + sLoadTemplate( SfxResId(STR_LOAD_TEMPLATE)), + nFlags(nFl), + pAntiImpl( pAntiImplP ) +{ + short nMoveOffset = *(short *)pAntiImplP->GetClassRes(); + pAntiImplP->IncrementRes(sizeof(short)); + short nExpandSize= *(short *)pAntiImplP->GetClassRes(); + pAntiImplP->IncrementRes(sizeof(short)); + pAntiImplP->FreeResource(); + + if (!nFlags) + MORE_BTN(Hide()); + else if(SFXWB_LOAD_TEMPLATE == nFlags) + { + aLoadFilePB.SetClickHdl(LINK(this, SfxNewFileDialog_Impl, LoadFile)); + aLoadFilePB.Show(); + aTextStyleCB.Show(); + aFrameStyleCB.Show(); + aPageStyleCB.Show(); + aNumStyleCB.Show(); + aMergeStyleCB.Show(); + Size aSize(pAntiImplP->GetOutputSizePixel()); + Size aTmp(pAntiImplP->LogicToPixel(Size(16, 16), MAP_APPFONT)); + aSize.Height() += aTmp.Height(); + pAntiImplP->SetOutputSizePixel(aSize); + pMoreBt->Hide(); + aTextStyleCB.Check(); + pAntiImplP->SetText(sLoadTemplate); + } + else + { + MORE_BTN(SetClickHdl(LINK(this, SfxNewFileDialog_Impl, Expand))); + if((nFlags & SFXWB_PREVIEW) == SFXWB_PREVIEW) + { + MORE_BTN(AddWindow(&aPreviewBtn)); + MORE_BTN(AddWindow(&aPreviewWin)); + aPreviewBtn.SetClickHdl(LINK(this, SfxNewFileDialog_Impl, PreviewClick)); + } + else + { + aPreviewBtn.Hide(); + aPreviewWin.Hide(); + nMoveOffset = (short)pAntiImplP->LogicToPixel( + Size(nMoveOffset, nMoveOffset), MAP_APPFONT).Width(); + nExpandSize = (short)pAntiImplP->LogicToPixel( + Size(nExpandSize, nExpandSize), MAP_APPFONT).Width(); + AdjustPosSize_Impl(&aTitleFt, nMoveOffset, 0); + AdjustPosSize_Impl(&aTitleEd, nMoveOffset, nExpandSize); + AdjustPosSize_Impl(&aThemaFt, nMoveOffset, 0); + AdjustPosSize_Impl(&aThemaEd, nMoveOffset, nExpandSize); + AdjustPosSize_Impl(&aKeywordsFt, nMoveOffset, 0); + AdjustPosSize_Impl(&aKeywordsEd, nMoveOffset, nExpandSize); + AdjustPosSize_Impl(&aDescFt , nMoveOffset, 0); + AdjustPosSize_Impl(&aDescEd , nMoveOffset, nExpandSize); + AdjustPosSize_Impl(&aDocinfoGb, nMoveOffset, nExpandSize); + } + } + + String &rExtra = pAntiImplP->GetExtraData(); + USHORT nTokCount = rExtra.GetTokenCount( '|' ); + if( nTokCount > 0 && nFlags ) + MORE_BTN(SetState( rExtra.GetToken( 0, '|' ) == 'Y' )); + if( nTokCount > 1 && nFlags ) + aPreviewBtn.Check( rExtra.GetToken( 1 ,'|' ) == 'Y' ); + + aTemplateLb.SetDoubleClickHdl(LINK(this, SfxNewFileDialog_Impl, DoubleClick)); + + // update the template configuration if necessary + { + WaitObject aWaitCursor( pAntiImplP->GetParent() ); + aTemplates.Update( sal_True /* be smart */ ); + } + // fill the list boxes + const USHORT nCount = aTemplates.GetRegionCount(); + if (nCount) + { + for(USHORT i = 0; i < nCount; ++i) + aRegionLb.InsertEntry(aTemplates.GetFullRegionName(i)); + aRegionLb.SetSelectHdl(LINK(this, SfxNewFileDialog_Impl, RegionSelect)); + } + + aPrevTimer.SetTimeout( 500 ); + aPrevTimer.SetTimeoutHdl( LINK( this, SfxNewFileDialog_Impl, Update)); + +// else +// aRegionLb.InsertEntry(String(SfxResId(STR_STANDARD))); + aRegionLb.SelectEntryPos(0); + RegionSelect(&aRegionLb); +} + +//------------------------------------------------------------------------- + +SfxNewFileDialog_Impl::~SfxNewFileDialog_Impl() +{ + String &rExtra = pAntiImpl->GetExtraData(); + rExtra = MORE_BTN(GetState()) ? 'Y' : 'N'; + rExtra += '|'; + rExtra += aPreviewBtn.IsChecked() ? 'Y' : 'N'; + + delete pMoreBt; +} +//------------------------------------------------------------------------- +SfxNewFileDialog::SfxNewFileDialog(Window *pParent, USHORT nFlags) + : SfxModalDialog( pParent, SfxResId( DLG_NEW_FILE ) ) +{ + pImpl = new SfxNewFileDialog_Impl( this, nFlags ); +} +//------------------------------------------------------------------------- +SfxNewFileDialog::~SfxNewFileDialog() +{ + delete pImpl; +} +//------------------------------------------------------------------------- +BOOL SfxNewFileDialog::IsTemplate() const +{ + return pImpl->IsTemplate(); +} +//------------------------------------------------------------------------- +String SfxNewFileDialog::GetTemplateRegion() const +{ + return pImpl->GetTemplateRegion(); +} +//------------------------------------------------------------------------- +String SfxNewFileDialog::GetTemplateName() const +{ + return pImpl->GetTemplateName(); +} +//------------------------------------------------------------------------- +String SfxNewFileDialog::GetTemplateFileName() const +{ + return pImpl->GetTemplateFileName(); +} +//------------------------------------------------------------------------- +USHORT SfxNewFileDialog::GetTemplateFlags()const +{ + return pImpl->GetTemplateFlags(); + +} +//------------------------------------------------------------------------- +void SfxNewFileDialog::SetTemplateFlags(USHORT nSet) +{ + pImpl->SetTemplateFlags(nSet); +} + diff --git a/sfx2/source/doc/new.hrc b/sfx2/source/doc/new.hrc new file mode 100644 index 000000000000..dd8878bf0177 --- /dev/null +++ b/sfx2/source/doc/new.hrc @@ -0,0 +1,57 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#define BTN_PREVIEW 51 +#define WIN_PREVIEW 50 +#define GB_DOCCLASS 1 +#define LB_DOCCLASS 2 +#define GB_DESC 10 +#define FT_DESC 11 +#define FT_STYLESHEETS 19 +#define FT_REGION 20 +#define ED_TITLE 56 +#define ED_KEYWORDS 61 +#define FT_KEYWORDS 60 +#define FT_TITLE 55 +#define ED_DESC 71 +#define FT_DOCINFO 70 +#define LB_REGION 21 +#define BT_OK 30 +#define BT_CANCEL 31 +#define BT_HELP 32 +#define GB_DOCINFO 70 +#define ED_THEMA 55 +#define FT_THEMA 54 +#define FT_TEMPLATE 53 +#define LB_TEMPLATE 52 +#define BT_MORE 32 +#define CB_TEXT_STYLE 33 +#define CB_FRAME_STYLE 34 +#define CB_PAGE_STYLE 35 +#define CB_NUM_STYLE 36 +#define CB_MERGE_STYLE 37 +#define PB_LOAD_FILE 38 +#define STR_LOAD_TEMPLATE 39 diff --git a/sfx2/source/doc/new.src b/sfx2/source/doc/new.src new file mode 100644 index 000000000000..146f9f630570 --- /dev/null +++ b/sfx2/source/doc/new.src @@ -0,0 +1,259 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + // include --------------------------------------------------------------- +#include <sfx2/sfx.hrc> +#include "doc.hrc" +#include "new.hrc" + // pragma ---------------------------------------------------------------- + + // DLG_NEW_FILE ---------------------------------------------------------- +ModalDialog DLG_NEW_FILE +{ + HelpId = SID_NEWDOC ; + OutputSize = TRUE ; + SVLook = TRUE ; + Size = MAP_APPFONT ( 336 , 96 ) ; + Text [ en-US ] = "New" ; + Moveable = TRUE ; + OKButton BT_OK + { + Pos = MAP_APPFONT ( 274 , 6 ) ; + Size = MAP_APPFONT ( 56 , 14 ) ; + DefButton = TRUE ; + }; + CancelButton BT_CANCEL + { + Pos = MAP_APPFONT ( 274 , 23 ) ; + Size = MAP_APPFONT ( 56 , 14 ) ; + }; + HelpButton BT_HELP + { + Pos = MAP_APPFONT ( 274 , 43 ) ; + Size = MAP_APPFONT ( 56 , 14 ) ; + }; + ListBox LB_REGION + { + Border = TRUE ; + Pos = MAP_APPFONT ( 6 , 18 ) ; + Size = MAP_APPFONT ( 127 , 72 ) ; + CurPos = 0 ; + }; + FixedText FT_REGION + { + Pos = MAP_APPFONT ( 6 , 6 ) ; + Size = MAP_APPFONT ( 97 , 10 ) ; + Text [ en-US ] = "~Categories" ; + Left = TRUE ; + }; + FixedText FT_TEMPLATE + { + Pos = MAP_APPFONT ( 139 , 6 ) ; + Size = MAP_APPFONT ( 97 , 10 ) ; + Text [ en-US ] = "T~emplates" ; + Left = TRUE ; + }; + ListBox LB_TEMPLATE + { + Border = TRUE ; + Pos = MAP_APPFONT ( 139 , 18 ) ; + Size = MAP_APPFONT ( 127 , 72 ) ; + CurPos = 0 ; + }; + MoreButton BT_MORE + { + Pos = MAP_APPFONT ( 274 , 70 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + Text [ en-US ] = "~More" ; + Delta = 148 ; + MapUnit = MAP_APPFONT ; + }; + Window WIN_PREVIEW + { + Border = TRUE ; + Pos = MAP_APPFONT ( 6 , 110 ) ; + Size = MAP_APPFONT ( 127 , 129 ) ; + Hide = TRUE ; + SVLook = FALSE ; + }; + CheckBox BTN_PREVIEW + { + Pos = MAP_APPFONT ( 6 , 96 ) ; + Size = MAP_APPFONT ( 97 , 10 ) ; + Text [ en-US ] = "Pre~view" ; + Hide = TRUE ; + }; + FixedLine GB_DOCINFO + { + Pos = MAP_APPFONT ( 139 , 97 ) ; + Size = MAP_APPFONT ( 186 , 8 ) ; + Hide = TRUE ; + Text [ en-US ] = "Description" ; + }; + CheckBox CB_TEXT_STYLE + { + Pos = MAP_APPFONT ( 6 , 94 ) ; + Size = MAP_APPFONT ( 50 , 10 ) ; + Hide = TRUE; + Text [ en-US ] = "Te~xt" ; + }; + CheckBox CB_FRAME_STYLE + { + Pos = MAP_APPFONT ( 60 , 94 ) ; + Size = MAP_APPFONT ( 50 , 10 ) ; + Hide = TRUE; + Text [ en-US ] = "~Frame" ; + }; + CheckBox CB_PAGE_STYLE + { + Pos = MAP_APPFONT ( 114 , 94 ) ; + Size = MAP_APPFONT ( 50 , 10 ) ; + Hide = TRUE; + Text [ en-US ] = "~Pages" ; + }; + CheckBox CB_NUM_STYLE + { + Pos = MAP_APPFONT ( 168 , 94 ) ; + Size = MAP_APPFONT ( 50 , 10 ) ; + Hide = TRUE; + Text [ en-US ] = "N~umbering" ; + }; + CheckBox CB_MERGE_STYLE + { + Pos = MAP_APPFONT ( 222 , 94 ) ; + Size = MAP_APPFONT ( 50 , 10 ) ; + Hide = TRUE; + Text [ en-US ] = "~Overwrite" ; + }; + PushButton PB_LOAD_FILE + { + Pos = MAP_APPFONT ( 274 , 92 ) ; + Size = MAP_APPFONT ( 56 , 14 ) ; + Hide = TRUE; + Text [ en-US ] = "From File..."; + }; + String STR_LOAD_TEMPLATE + { + Text [ en-US ] = "Load Styles" ; + }; + FixedText FT_TITLE + { + Pos = MAP_APPFONT ( 145 , 108 ) ; + Size = MAP_APPFONT ( 175 , 10 ) ; + Text [ en-US ] = "~Title" ; + Hide = TRUE ; + }; + Edit ED_TITLE + { + Border = TRUE ; + Pos = MAP_APPFONT ( 145 , 121 ) ; + Size = MAP_APPFONT ( 175 , 12 ) ; + ReadOnly = TRUE ; + Hide = TRUE ; + }; + FixedText FT_THEMA + { + Pos = MAP_APPFONT ( 145 , 135 ) ; + Size = MAP_APPFONT ( 175 , 10 ) ; + Text [ en-US ] = "Subject" ; + Hide = TRUE ; + }; + Edit ED_THEMA + { + Border = TRUE ; + Pos = MAP_APPFONT ( 145 , 148 ) ; + Size = MAP_APPFONT ( 175 , 12 ) ; + ReadOnly = TRUE ; + Hide = TRUE ; + }; + FixedText FT_KEYWORDS + { + Pos = MAP_APPFONT ( 145 , 162 ) ; + Size = MAP_APPFONT ( 175 , 10 ) ; + Text [ en-US ] = "~Key words" ; + Hide = TRUE ; + }; + Edit ED_KEYWORDS + { + Border = TRUE ; + Pos = MAP_APPFONT ( 145 , 175 ) ; + Size = MAP_APPFONT ( 175 , 12 ) ; + ReadOnly = TRUE ; + Hide = TRUE ; + }; + FixedText FT_DESC + { + Pos = MAP_APPFONT ( 145 , 189 ) ; + Size = MAP_APPFONT ( 175 , 10 ) ; + Text [ en-US ] = "~Description" ; + Hide = TRUE ; + }; + MultiLineEdit ED_DESC + { + Border = TRUE ; + Pos = MAP_APPFONT ( 144 , 202 ) ; + Size = MAP_APPFONT ( 175 , 32 ) ; + IgnoreTab = TRUE ; + ReadOnly = TRUE ; + Hide = TRUE ; + }; + ExtraData = + { + 103; + 44; + }; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sfx2/source/doc/objcont.cxx b/sfx2/source/doc/objcont.cxx new file mode 100644 index 000000000000..451e33084c07 --- /dev/null +++ b/sfx2/source/doc/objcont.cxx @@ -0,0 +1,1292 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include <com/sun/star/uno/Reference.hxx> + +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/UpdateDocMode.hpp> +#include <com/sun/star/frame/XLayoutManager.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/document/XStandaloneDocumentInfo.hpp> +#include <com/sun/star/beans/XFastPropertySet.hpp> +#include <tools/cachestr.hxx> +#include <vcl/msgbox.hxx> +#include <svl/style.hxx> +#include <vcl/wrkwin.hxx> + +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <svl/rectitem.hxx> +#include <svl/eitem.hxx> +#include <svl/urihelper.hxx> +#include <svl/ctloptions.hxx> +#include <comphelper/storagehelper.hxx> +#include <comphelper/processfactory.hxx> +#include <unotools/securityoptions.hxx> +#include <svtools/sfxecode.hxx> +#include <svtools/ehdl.hxx> +#include <tools/datetime.hxx> +#include <math.h> + +#include <unotools/saveopt.hxx> +#include <unotools/useroptions.hxx> +#include <unotools/localfilehelper.hxx> +#include <vcl/virdev.hxx> +#include <vcl/oldprintadaptor.hxx> + +#include <sfx2/app.hxx> +#include "sfxresid.hxx" +#include "appdata.hxx" +#include <sfx2/dinfdlg.hxx> +#include "fltfnc.hxx" +#include <sfx2/docfac.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/objsh.hxx> +#include "objshimp.hxx" +#include <sfx2/evntconf.hxx> +#include "sfxhelp.hxx" +#include <sfx2/dispatch.hxx> +#include <sfx2/printer.hxx> +#include <sfx2/viewfrm.hxx> +#include "basmgr.hxx" +#include <sfx2/doctempl.hxx> +#include "doc.hrc" +#include <sfx2/sfxbasemodel.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/request.hxx> +#include "openflag.hxx" +#include "querytemplate.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +//==================================================================== + +//==================================================================== + +static +bool operator> (const util::DateTime& i_rLeft, const util::DateTime& i_rRight) +{ + if ( i_rLeft.Year != i_rRight.Year ) + return i_rLeft.Year > i_rRight.Year; + + if ( i_rLeft.Month != i_rRight.Month ) + return i_rLeft.Month > i_rRight.Month; + + if ( i_rLeft.Day != i_rRight.Day ) + return i_rLeft.Day > i_rRight.Day; + + if ( i_rLeft.Hours != i_rRight.Hours ) + return i_rLeft.Hours > i_rRight.Hours; + + if ( i_rLeft.Minutes != i_rRight.Minutes ) + return i_rLeft.Minutes > i_rRight.Minutes; + + if ( i_rLeft.Seconds != i_rRight.Seconds ) + return i_rLeft.Seconds > i_rRight.Seconds; + + if ( i_rLeft.HundredthSeconds != i_rRight.HundredthSeconds ) + return i_rLeft.HundredthSeconds > i_rRight.HundredthSeconds; + + return sal_False; +} + + +::boost::shared_ptr<GDIMetaFile> +SfxObjectShell::GetPreviewMetaFile( sal_Bool bFullContent ) const +{ + return CreatePreviewMetaFile_Impl( bFullContent, sal_False ); +} + + +::boost::shared_ptr<GDIMetaFile> +SfxObjectShell::CreatePreviewMetaFile_Impl( sal_Bool bFullContent, sal_Bool bHighContrast ) const +{ + // Nur wenn gerade nicht gedruckt wird, darf DoDraw aufgerufen + // werden, sonst wird u.U. der Printer abgeschossen ! + SfxViewFrame *pFrame = SfxViewFrame::GetFirst( this ); + if ( pFrame && pFrame->GetViewShell() && + pFrame->GetViewShell()->GetPrinter() && + pFrame->GetViewShell()->GetPrinter()->IsPrinting() ) + return ::boost::shared_ptr<GDIMetaFile>(); + + ::boost::shared_ptr<GDIMetaFile> pFile(new GDIMetaFile); + + VirtualDevice aDevice; + aDevice.EnableOutput( FALSE ); + + // adjust the output device if HC-metafile is requested + if ( bHighContrast ) + aDevice.SetDrawMode( aDevice.GetDrawMode() | DRAWMODE_SETTINGSLINE | DRAWMODE_SETTINGSFILL | DRAWMODE_SETTINGSTEXT | DRAWMODE_SETTINGSGRADIENT ); + + MapMode aMode( ((SfxObjectShell*)this)->GetMapUnit() ); + aDevice.SetMapMode( aMode ); + pFile->SetPrefMapMode( aMode ); + + Size aTmpSize; + sal_Int8 nAspect; + if ( bFullContent ) + { + nAspect = ASPECT_CONTENT; + aTmpSize = GetVisArea( nAspect ).GetSize(); + } + else + { + nAspect = ASPECT_THUMBNAIL; + aTmpSize = ((SfxObjectShell*)this)->GetFirstPageSize(); + } + + pFile->SetPrefSize( aTmpSize ); + DBG_ASSERT( aTmpSize.Height()*aTmpSize.Width(), + "size of first page is 0, overload GetFirstPageSize or set vis-area!" ); + + pFile->Record( &aDevice ); + + LanguageType eLang; + SvtCTLOptions* pCTLOptions = new SvtCTLOptions; + if ( SvtCTLOptions::NUMERALS_HINDI == pCTLOptions->GetCTLTextNumerals() ) + eLang = LANGUAGE_ARABIC_SAUDI_ARABIA; + else if ( SvtCTLOptions::NUMERALS_ARABIC == pCTLOptions->GetCTLTextNumerals() ) + eLang = LANGUAGE_ENGLISH; + else + eLang = (LanguageType) Application::GetSettings().GetLanguage(); + + aDevice.SetDigitLanguage( eLang ); + + ((SfxObjectShell*)this)->DoDraw( &aDevice, Point(0,0), aTmpSize, JobSetup(), nAspect ); + pFile->Stop(); + + return pFile; +} + +//==================================================================== + +void SfxObjectShell::UpdateDocInfoForSave() +{ + uno::Reference<document::XDocumentProperties> xDocProps(getDocProperties()); + + // clear user data if recommend (see 'Tools - Options - Open/StarOffice - Security') + if ( SvtSecurityOptions().IsOptionSet( + SvtSecurityOptions::E_DOCWARN_REMOVEPERSONALINFO ) ) + { + xDocProps->resetUserData( ::rtl::OUString() ); + } + else if ( IsModified() ) + { + String aUserName = SvtUserOptions().GetFullName(); + if ( !IsUseUserData() ) + { + // remove all data pointing to the current user + if (xDocProps->getAuthor().equals(aUserName)) { + xDocProps->setAuthor( ::rtl::OUString() ); + } + xDocProps->setModifiedBy( ::rtl::OUString() ); + if (xDocProps->getPrintedBy().equals(aUserName)) { + xDocProps->setPrintedBy( ::rtl::OUString() ); + } + } + else + { + // update ModificationAuthor, revision and editing time + ::DateTime now; + xDocProps->setModificationDate( util::DateTime( + now.Get100Sec(), now.GetSec(), now.GetMin(), + now.GetHour(), now.GetDay(), now.GetMonth(), + now.GetYear() ) ); + xDocProps->setModifiedBy( aUserName ); + if ( !HasName() || pImp->bIsSaving ) + // QUESTION: not in case of "real" SaveAs as this is meant to create a new document + UpdateTime_Impl( xDocProps ); + } + } +} + +//-------------------------------------------------------------------- + +static void +lcl_add(util::Duration & rDur, Time const& rTime) +{ + // here we don't care about overflow: rDur is converted back to seconds + // anyway, and Time cannot store more than ~4000 hours + rDur.Hours += rTime.GetHour(); + rDur.Minutes += rTime.GetMin(); + rDur.Seconds += rTime.GetSec(); +} + +// Bearbeitungszeit aktualisieren +void SfxObjectShell::UpdateTime_Impl( + const uno::Reference<document::XDocumentProperties> & i_xDocProps) +{ + // Get old time from documentinfo + const sal_Int32 secs = i_xDocProps->getEditingDuration(); + util::Duration editDuration(sal_False, 0, 0, 0, + secs/3600, (secs%3600)/60, secs%60, 0); + + // Initialize some local member! Its neccessary for wollow operations! + DateTime aNow ; // Date and time at current moment + Time n24Time (24,0,0,0) ; // Time-value for 24 hours - see follow calculation + ULONG nDays = 0 ; // Count of days between now and last editing + Time nAddTime (0) ; // Value to add on aOldTime + + // Safe impossible cases! + // User has changed time to the past between last editing and now ... its not possible!!! + DBG_ASSERT( !(aNow.GetDate()<pImp->nTime.GetDate()), "Timestamp of last change is in the past ?!..." ); + + // Do the follow only, if user has NOT changed time to the past. + // Else add a time of 0 to aOldTime ... !!! + if (aNow.GetDate()>=pImp->nTime.GetDate()) + { + // Get count of days last editing. + nDays = aNow.GetSecFromDateTime(pImp->nTime.GetDate())/86400 ; + + if (nDays==0) + { + // If no day between now and last editing - calculate time directly. + nAddTime = (const Time&)aNow - (const Time&)pImp->nTime ; + } + else + // If time of working without save greater then 1 month (!) .... + // we add 0 to aOldTime! + if (nDays<=31) + { + // If 1 or up to 31 days between now and last editing - calculate time indirectly. + // nAddTime = (24h - nTime) + (nDays * 24h) + aNow + --nDays; + nAddTime = nDays*n24Time.GetTime() ; + nAddTime += n24Time-(const Time&)pImp->nTime ; + nAddTime += aNow ; + } + + lcl_add(editDuration, nAddTime); + } + + pImp->nTime = aNow; + try { + const sal_Int32 newSecs( (editDuration.Hours*3600) + + (editDuration.Minutes*60) + editDuration.Seconds); + i_xDocProps->setEditingDuration(newSecs); + i_xDocProps->setEditingCycles(i_xDocProps->getEditingCycles() + 1); + } + catch (lang::IllegalArgumentException &) + { + // ignore overflow + } +} + +//-------------------------------------------------------------------- + +SfxDocumentInfoDialog* SfxObjectShell::CreateDocumentInfoDialog +( + Window* pParent, + const SfxItemSet& rSet +) +{ + return new SfxDocumentInfoDialog(pParent, rSet); +} + +//-------------------------------------------------------------------- + +SfxStyleSheetBasePool* SfxObjectShell::GetStyleSheetPool() +{ + return 0; +} + +void SfxObjectShell::SetOrganizerSearchMask( + SfxStyleSheetBasePool* pStylePool) const +{ + pStylePool->SetSearchMask( + SFX_STYLE_FAMILY_ALL, + SFXSTYLEBIT_USERDEF | SFXSTYLEBIT_USED); +} + +//-------------------------------------------------------------------- + +USHORT SfxObjectShell::GetContentCount( + USHORT nIdx1, + USHORT /*nIdx2*/) +{ + switch(nIdx1) + { + case INDEX_IGNORE: + return DEF_CONTENT_COUNT; + case CONTENT_STYLE: + { + SfxStyleSheetBasePool *pStylePool = GetStyleSheetPool(); + if(!pStylePool) + return 0; + SetOrganizerSearchMask(pStylePool); + return pStylePool->Count(); + } + case CONTENT_MACRO: + break; +/* + case CONTENT_CONFIG: + return ( GetConfigManager() ) ? + GetConfigManager()->GetItemCount() : 0; + break; + */ + } + return 0; +} + + +//-------------------------------------------------------------------- +//TODO/CLEANUP: remove this method (it's virtual) +void SfxObjectShell::TriggerHelpPI(USHORT nIdx1, USHORT nIdx2, USHORT) +{ + if(nIdx1==CONTENT_STYLE && nIdx2 != INDEX_IGNORE) //StyleSheets + { + SfxStyleSheetBasePool *pStylePool = GetStyleSheetPool(); + SetOrganizerSearchMask(pStylePool); +#ifdef WIR_KOENNEN_WIEDER_HILFE_FUER_STYLESHEETS + SfxStyleSheetBase *pStyle = (*pStylePool)[nIdx2]; + if(pStyle) + { + String aHelpFile; + ULONG nHelpId=pStyle->GetHelpId(aHelpFile); + SfxHelpPI* pHelpPI = SFX_APP()->GetHelpPI(); + if ( pHelpPI && nHelpId ) + pHelpPI->LoadTopic( nHelpId ); + } +#endif + } +} + +BOOL SfxObjectShell::CanHaveChilds(USHORT nIdx1, + USHORT nIdx2) +{ + switch(nIdx1) { + case INDEX_IGNORE: + return TRUE; + case CONTENT_STYLE: + return INDEX_IGNORE == nIdx2 || !GetStyleSheetPool()? FALSE: TRUE; + case CONTENT_MACRO: +//!! return INDEX_IGNORE == nIdx2? FALSE: TRUE; + return FALSE; +/* + case CONTENT_CONFIG: + return INDEX_IGNORE == nIdx2 ? FALSE : TRUE; + */ + } + return FALSE; +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::GetContent(String &rText, + Bitmap &rClosedBitmap, + Bitmap &rOpenedBitmap, + BOOL &bCanDel, + USHORT i, + USHORT nIdx1, + USHORT nIdx2 ) +{ + DBG_ERRORFILE( "Non high contrast method called. Please update calling code!" ); + SfxObjectShell::GetContent( rText, rClosedBitmap, rOpenedBitmap, BMP_COLOR_NORMAL, bCanDel, i, nIdx1, nIdx2 ); +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::GetContent(String &rText, + Bitmap &rClosedBitmap, + Bitmap &rOpenedBitmap, + BmpColorMode eColorMode, + BOOL &bCanDel, + USHORT i, + USHORT nIdx1, + USHORT /*nIdx2*/ ) +{ + bCanDel=TRUE; + + switch(nIdx1) + { + case INDEX_IGNORE: + { + USHORT nTextResId = 0; + USHORT nClosedBitmapResId = 0; // evtl. sp"ater mal unterschiedliche + USHORT nOpenedBitmapResId = 0; // " " " " + switch(i) + { + case CONTENT_STYLE: + nTextResId = STR_STYLES; + if ( eColorMode == BMP_COLOR_NORMAL ) + { + nClosedBitmapResId= BMP_STYLES_CLOSED; + nOpenedBitmapResId= BMP_STYLES_OPENED; + } + else + { + nClosedBitmapResId= BMP_STYLES_CLOSED_HC; + nOpenedBitmapResId= BMP_STYLES_OPENED_HC; + } + break; + case CONTENT_MACRO: + nTextResId = STR_MACROS; + if ( eColorMode == BMP_COLOR_NORMAL ) + { + nClosedBitmapResId= BMP_STYLES_CLOSED; + nOpenedBitmapResId= BMP_STYLES_OPENED; + } + else + { + nClosedBitmapResId= BMP_STYLES_CLOSED_HC; + nOpenedBitmapResId= BMP_STYLES_OPENED_HC; + } + break; +/* + case CONTENT_CONFIG: + nTextResId = STR_CONFIG; + nClosedBitmapResId= BMP_STYLES_CLOSED; + nOpenedBitmapResId= BMP_STYLES_OPENED; + break; + */ + } + + if ( nTextResId ) + { + rText = String(SfxResId(nTextResId)); + rClosedBitmap = Bitmap(SfxResId(nClosedBitmapResId)); + rOpenedBitmap = Bitmap(SfxResId(nOpenedBitmapResId)); + } + break; + } + + case CONTENT_STYLE: + { + SfxStyleSheetBasePool *pStylePool = GetStyleSheetPool(); + SetOrganizerSearchMask(pStylePool); + SfxStyleSheetBase *pStyle = (*pStylePool)[i]; + rText = pStyle->GetName(); + bCanDel=((pStyle->GetMask() & SFXSTYLEBIT_USERDEF) + == SFXSTYLEBIT_USERDEF); + rClosedBitmap = rOpenedBitmap = + GetStyleFamilyBitmap(pStyle->GetFamily(), eColorMode ); + } + break; + case CONTENT_MACRO: + break; +/* + case CONTENT_CONFIG: + if ( GetConfigManager() ) + { + rText = GetConfigManager()->GetItem(i); + bCanDel = GetConfigManager()->CanDelete(i); + } + else + rText = String(); + rClosedBitmap = Bitmap(SfxResId(BMP_STYLES_CLOSED)); + rOpenedBitmap = Bitmap(SfxResId(BMP_STYLES_OPENED)); + break; +*/ + } +} + +//-------------------------------------------------------------------- +Bitmap SfxObjectShell::GetStyleFamilyBitmap( SfxStyleFamily eFamily ) +{ + DBG_ERRORFILE( "Non high contrast method called. Please update calling code!" ); + return SfxObjectShell::GetStyleFamilyBitmap( eFamily, BMP_COLOR_NORMAL ); +} + +//-------------------------------------------------------------------- + +Bitmap SfxObjectShell::GetStyleFamilyBitmap(SfxStyleFamily eFamily, BmpColorMode eColorMode ) +{ + USHORT nResId = 0; + switch(eFamily) + { + case SFX_STYLE_FAMILY_CHAR: + nResId = ( eColorMode == BMP_COLOR_NORMAL ) ? BMP_STYLES_FAMILY1 : BMP_STYLES_FAMILY1_HC; + break; + case SFX_STYLE_FAMILY_PARA: + nResId = ( eColorMode == BMP_COLOR_NORMAL ) ? BMP_STYLES_FAMILY2 : BMP_STYLES_FAMILY2_HC; + break; + case SFX_STYLE_FAMILY_FRAME: + nResId = ( eColorMode == BMP_COLOR_NORMAL ) ? BMP_STYLES_FAMILY3 : BMP_STYLES_FAMILY3_HC; + break; + case SFX_STYLE_FAMILY_PAGE : + nResId = ( eColorMode == BMP_COLOR_NORMAL ) ? BMP_STYLES_FAMILY4 : BMP_STYLES_FAMILY4_HC; + break; + case SFX_STYLE_FAMILY_PSEUDO: + case SFX_STYLE_FAMILY_ALL: + break; + } + + if ( nResId ) + return Bitmap(SfxResId(nResId)); + else + return Bitmap(); +} + + +//-------------------------------------------------------------------- + +BOOL SfxObjectShell::Insert(SfxObjectShell &rSource, + USHORT nSourceIdx1, + USHORT nSourceIdx2, + USHORT /*nSourceIdx3*/, + USHORT &nIdx1, + USHORT &nIdx2, + USHORT &/*nIdx3*/, + USHORT &/*nDeleted*/) +{ + BOOL bRet = FALSE; + + if (INDEX_IGNORE == nIdx1 && CONTENT_STYLE == nSourceIdx1) + nIdx1 = CONTENT_STYLE; + + if (CONTENT_STYLE == nSourceIdx1 && CONTENT_STYLE == nIdx1) + { + SfxStyleSheetBasePool* pHisPool = rSource.GetStyleSheetPool(); + SfxStyleSheetBasePool* pMyPool = GetStyleSheetPool(); + SetOrganizerSearchMask(pHisPool); + SetOrganizerSearchMask(pMyPool); + SfxStyleSheetBase* pHisSheet = NULL; + + if ( pHisPool && pHisPool->Count() > nSourceIdx2 ) + pHisSheet = (*pHisPool)[nSourceIdx2]; + + // Einfuegen ist nur dann noetig, wenn ein StyleSheet + // zwischen unterschiedlichen(!) Pools bewegt wird + + if ( pHisSheet && pMyPool != pHisPool ) + { + if (INDEX_IGNORE == nIdx2) + { + nIdx2 = pMyPool->Count(); + } + + // wenn so eine Vorlage schon existiert: loeschen! + String aOldName(pHisSheet->GetName()); + SfxStyleFamily eOldFamily = pHisSheet->GetFamily(); + + SfxStyleSheetBase* pExist = pMyPool->Find(aOldName, eOldFamily); + // USHORT nOldHelpId = pExist->GetHelpId(??? VB ueberlegt sich was); + BOOL bUsedOrUserDefined; + if( pExist ) + { + bUsedOrUserDefined = + pExist->IsUsed() || pExist->IsUserDefined(); + if( ErrorHandler::HandleError( + *new MessageInfo( ERRCODE_SFXMSG_STYLEREPLACE, aOldName ) ) + != ERRCODE_BUTTON_OK ) + return FALSE; + else + { + pMyPool->Replace( *pHisSheet, *pExist ); + SetModified( TRUE ); + nIdx2 = nIdx1 = INDEX_IGNORE; + return TRUE; + } + } + + SfxStyleSheetBase& rNewSheet = pMyPool->Make( + aOldName, eOldFamily, + pHisSheet->GetMask(), nIdx2); + + // ItemSet der neuen Vorlage fuellen + rNewSheet.GetItemSet().Set(pHisSheet->GetItemSet()); + + // wer bekommt den Neuen als Parent? wer benutzt den Neuen als Follow? + SfxStyleSheetBase* pTestSheet = pMyPool->First(); + while (pTestSheet) + { + if (pTestSheet->GetFamily() == eOldFamily && + pTestSheet->HasParentSupport() && + pTestSheet->GetParent() == aOldName) + { + pTestSheet->SetParent(aOldName); + // Verknuepfung neu aufbauen + } + + if (pTestSheet->GetFamily() == eOldFamily && + pTestSheet->HasFollowSupport() && + pTestSheet->GetFollow() == aOldName) + { + pTestSheet->SetFollow(aOldName); + // Verknuepfung neu aufbauen + } + + pTestSheet = pMyPool->Next(); + } + bUsedOrUserDefined = + rNewSheet.IsUsed() || rNewSheet.IsUserDefined(); + + + // hat der Neue einen Parent? wenn ja, mit gleichem Namen bei uns suchen + if (pHisSheet->HasParentSupport()) + { + const String& rParentName = pHisSheet->GetParent(); + if (0 != rParentName.Len()) + { + SfxStyleSheetBase* pParentOfNew = + pMyPool->Find(rParentName, eOldFamily); + if (pParentOfNew) + rNewSheet.SetParent(rParentName); + } + } + + // hat der Neue einen Follow? wenn ja, mit gleichem + // Namen bei uns suchen + if (pHisSheet->HasFollowSupport()) + { + const String& rFollowName = pHisSheet->GetFollow(); + if (0 != rFollowName.Len()) + { + SfxStyleSheetBase* pFollowOfNew = + pMyPool->Find(rFollowName, eOldFamily); + if (pFollowOfNew) + rNewSheet.SetFollow(rFollowName); + } + } + + SetModified( TRUE ); + if( !bUsedOrUserDefined ) nIdx2 = nIdx1 = INDEX_IGNORE; + + bRet = TRUE; + } + else + bRet = FALSE; + } +/* + else if (nSourceIdx1 == CONTENT_CONFIG) + { + nIdx1 = CONTENT_CONFIG; + + SfxConfigManager *pCfgMgr = SFX_CFGMANAGER(); + if ( !GetConfigManager() ) + { + SetConfigManager(new SfxConfigManager(0, pCfgMgr)); + SetTemplateConfig(FALSE); + if (this == Current()) + GetConfigManager()->Activate(pCfgMgr); + } + + if (GetConfigManager()->CopyItem( + nSourceIdx2, nIdx2, rSource.GetConfigManager())) + { + SetModified(TRUE); + bRet = TRUE; + SFX_APP()->GetDispatcher_Impl()->Update_Impl(TRUE); + } + } +*/ + return bRet; +} + +//-------------------------------------------------------------------- + +BOOL SfxObjectShell::Remove +( + USHORT nIdx1, + USHORT nIdx2, + USHORT /*nIdx3*/ +) +{ + BOOL bRet = FALSE; + + if (CONTENT_STYLE == nIdx1) + { + SfxStyleSheetBasePool* pMyPool = GetStyleSheetPool(); + + SetOrganizerSearchMask(pMyPool); + + SfxStyleSheetBase* pMySheet = (*pMyPool)[nIdx2]; + String aName(pMySheet->GetName()); + String aEmpty; + SfxStyleFamily eFamily = pMySheet->GetFamily(); + pMyPool->Remove(pMySheet); + bRet = TRUE; + + SfxStyleSheetBase* pTestSheet = pMyPool->First(); + while (pTestSheet) + { + if (pTestSheet->GetFamily() == eFamily && + pTestSheet->HasParentSupport() && + pTestSheet->GetParent() == aName) + { + pTestSheet->SetParent(aEmpty); // Verknuepfung aufloesen + } + + if (pTestSheet->GetFamily() == eFamily && + pTestSheet->HasFollowSupport() && + pTestSheet->GetFollow() == aName) + { + pTestSheet->SetFollow(aEmpty); // Verknuepfung aufloesen + } + + pTestSheet = pMyPool->Next(); + } + + SetModified( TRUE ); + } + + return bRet; +} + +//-------------------------------------------------------------------- + +BOOL SfxObjectShell::Print +( + Printer& rPrt, + USHORT nIdx1, + USHORT /*nIdx2*/, + USHORT /*nIdx3*/, + const String* pObjectName +) + +/* [Beschreibung] +*/ + +{ + switch(nIdx1) + { + case CONTENT_STYLE: + { + SfxStyleSheetBasePool *pStylePool = GetStyleSheetPool(); + SetOrganizerSearchMask(pStylePool); + SfxStyleSheetIterator* pIter = pStylePool->CreateIterator( + pStylePool->GetSearchFamily(), pStylePool->GetSearchMask() ); + USHORT nStyles = pIter->Count(); + SfxStyleSheetBase *pStyle = pIter->First(); + if ( !pStyle ) + return TRUE; + + // pepare adaptor for old style StartPage/EndPage printing + boost::shared_ptr< Printer > pPrinter( new Printer( rPrt.GetJobSetup() ) ); + vcl::OldStylePrintAdaptor* pAdaptor = new vcl::OldStylePrintAdaptor( pPrinter ); + boost::shared_ptr< vcl::PrinterController > pController( pAdaptor ); + + pAdaptor->StartPage(); + + pPrinter->SetMapMode(MapMode(MAP_10TH_MM)); + Font aFont( DEFINE_CONST_UNICODE( "Arial" ), Size(0, 64)); // 18pt + aFont.SetWeight(WEIGHT_BOLD); + pPrinter->SetFont(aFont); + const Size aPageSize(pPrinter->GetOutputSize()); + const USHORT nXIndent = 200; + USHORT nYIndent = 200; + Point aOutPos(nXIndent, nYIndent); + String aHeader(SfxResId(STR_PRINT_STYLES_HEADER)); + if ( pObjectName ) + aHeader += *pObjectName; + else + aHeader += GetTitle(); + long nTextHeight( pPrinter->GetTextHeight() ); + pPrinter->DrawText(aOutPos, aHeader); + aOutPos.Y() += nTextHeight; + aOutPos.Y() += nTextHeight/2; + aFont.SetSize(Size(0, 35)); // 10pt + nStyles = 1; + while(pStyle) + { + // print template name + String aStr(pStyle->GetName()); + aFont.SetWeight(WEIGHT_BOLD); + pPrinter->SetFont(aFont); + nTextHeight = pPrinter->GetTextHeight(); + // check for new page + if ( aOutPos.Y() + nTextHeight*2 > + aPageSize.Height() - (long) nYIndent ) + { + pAdaptor->EndPage(); + pAdaptor->StartPage(); + aOutPos.Y() = nYIndent; + } + pPrinter->DrawText(aOutPos, aStr); + aOutPos.Y() += nTextHeight; + + // print template description + aFont.SetWeight(WEIGHT_NORMAL); + pPrinter->SetFont(aFont); + aStr = pStyle->GetDescription(); + const char cDelim = ' '; + USHORT nStart = 0, nIdx = 0; + + nTextHeight = pPrinter->GetTextHeight(); + // break text into lines + while(nIdx < aStr.Len()) + { + USHORT nOld = nIdx; + long nTextWidth; + nIdx = aStr.Search(cDelim, nStart); + nTextWidth = pPrinter->GetTextWidth(aStr, nStart, nIdx-nStart); + while(nIdx != STRING_NOTFOUND && + aOutPos.X() + nTextWidth < + aPageSize.Width() - (long) nXIndent) + { + nOld = nIdx; + nIdx = aStr.Search(cDelim, nIdx+1); + nTextWidth = pPrinter->GetTextWidth(aStr, nStart, nIdx-nStart); + } + String aTmp(aStr, nStart, nIdx == STRING_NOTFOUND? + STRING_LEN : + nOld-nStart); + if ( aTmp.Len() ) + { + nStart = nOld+1; // trailing space + } + else + { + USHORT nChar = 1; + while( + nStart + nChar < aStr.Len() && + aOutPos.X() + pPrinter->GetTextWidth( + aStr, nStart, nChar) < + aPageSize.Width() - nXIndent) + ++nChar; + aTmp = String(aStr, nStart, nChar-1); + nIdx = nStart + nChar; + nStart = nIdx; + } + if ( aOutPos.Y() + nTextHeight*2 > + aPageSize.Height() - nYIndent ) + { + pAdaptor->EndPage(); + pAdaptor->StartPage(); + aOutPos.Y() = nYIndent; + } + pPrinter->DrawText(aOutPos, aTmp); + aOutPos.Y() += pPrinter->GetTextHeight(); + } + pStyle = pIter->Next(); + } + pAdaptor->EndPage(); + + Printer::PrintJob( pController, rPrt.GetJobSetup() ); + + delete pIter; + break; + } + default: + return FALSE; + } + return TRUE; +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::LoadStyles +( + SfxObjectShell &rSource /* die Dokument-Vorlage, aus der + die Styles geladen werden sollen */ +) + +/* [Beschreibung] + + Diese Methode wird vom SFx gerufen, wenn aus einer Dokument-Vorlage + Styles nachgeladen werden sollen. Bestehende Styles soll dabei + "uberschrieben werden. Das Dokument mu"s daher neu formatiert werden. + Daher werden die Applikationen in der Regel diese Methode "uberladen + und in ihrer Implementierung die Implementierung der Basisklasse + rufen. +*/ + +{ + struct Styles_Impl + { + SfxStyleSheetBase *pSource; + SfxStyleSheetBase *pDest; +// Styles_Impl () : pSource(0), pDest(0) {} + }; + + SfxStyleSheetBasePool *pSourcePool = rSource.GetStyleSheetPool(); + DBG_ASSERT(pSourcePool, "Source-DocumentShell ohne StyleSheetPool"); + SfxStyleSheetBasePool *pMyPool = GetStyleSheetPool(); + DBG_ASSERT(pMyPool, "Dest-DocumentShell ohne StyleSheetPool"); + pSourcePool->SetSearchMask(SFX_STYLE_FAMILY_ALL, 0xffff); + Styles_Impl *pFound = new Styles_Impl[pSourcePool->Count()]; + USHORT nFound = 0; + + SfxStyleSheetBase *pSource = pSourcePool->First(); + while ( pSource ) + { + SfxStyleSheetBase *pDest = + pMyPool->Find( pSource->GetName(), pSource->GetFamily() ); + if ( !pDest ) + { + pDest = &pMyPool->Make( pSource->GetName(), + pSource->GetFamily(), pSource->GetMask()); + // Setzen des Parents, der Folgevorlage + } + pFound[nFound].pSource = pSource; + pFound[nFound].pDest = pDest; + ++nFound; + pSource = pSourcePool->Next(); + } + + for ( USHORT i = 0; i < nFound; ++i ) + { + pFound[i].pDest->GetItemSet().PutExtended(pFound[i].pSource->GetItemSet(), SFX_ITEM_DONTCARE, SFX_ITEM_DEFAULT); +// pFound[i].pDest->SetHelpId(pFound[i].pSource->GetHelpId()); + if(pFound[i].pSource->HasParentSupport()) + pFound[i].pDest->SetParent(pFound[i].pSource->GetParent()); + if(pFound[i].pSource->HasFollowSupport()) + pFound[i].pDest->SetFollow(pFound[i].pSource->GetParent()); + } + delete [] pFound; +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::UpdateFromTemplate_Impl( ) + +/* [Beschreibung] + + Diese interne Methode pr"uft, ob das Dokument aus einem Template + erzeugt wurde, und ob dieses neuer ist als das Dokument. Ist dies + der Fall, wird der Benutzer gefragt, ob die Vorlagen (StyleSheets) + updated werden sollen. Wird dies positiv beantwortet, werden die + StyleSheets updated. +*/ + +{ + // Storage-medium? + SfxMedium *pFile = GetMedium(); + DBG_ASSERT( pFile, "cannot UpdateFromTemplate without medium" ); + if ( !pFile ) + return; + + if ( !::utl::LocalFileHelper::IsLocalFile( pFile->GetName() ) ) + // update only for documents loaded from the local file system + return; + + // only for own storage formats + uno::Reference< embed::XStorage > xDocStor = pFile->GetStorage(); + if ( !pFile->GetFilter() || !pFile->GetFilter()->IsOwnFormat() ) + return; + + SFX_ITEMSET_ARG( pFile->GetItemSet(), pUpdateDocItem, SfxUInt16Item, SID_UPDATEDOCMODE, sal_False); + sal_Int16 bCanUpdateFromTemplate = pUpdateDocItem ? pUpdateDocItem->GetValue() : document::UpdateDocMode::NO_UPDATE; + + // created from template? + uno::Reference<document::XDocumentProperties> xDocProps(getDocProperties()); + ::rtl::OUString aTemplName( xDocProps->getTemplateName() ); + ::rtl::OUString aTemplURL( xDocProps->getTemplateURL() ); + String aFoundName; + + if ( aTemplName.getLength() || (aTemplURL.getLength() && !IsReadOnly()) ) + { + // try to locate template, first using filename + // this must be done because writer global document uses this "great" idea to manage the templates of all parts + // in the master document + // but it is NOT an error if the template filename points not to a valid file + SfxDocumentTemplates aTempl; + aTempl.Construct(); + if ( aTemplURL.getLength() ) + { + String aURL; + if( ::utl::LocalFileHelper::ConvertSystemPathToURL( aTemplURL, GetMedium()->GetName(), aURL ) ) + aFoundName = aURL; + } + + if( !aFoundName.Len() && aTemplName.getLength() ) + // if the template filename did not lead to success, try to get a file name for the logical template name + aTempl.GetFull( String(), aTemplName, aFoundName ); + } + + if ( aFoundName.Len() ) + { + // check existence of template storage + aTemplURL = aFoundName; + BOOL bLoad = FALSE; + + // should the document checked against changes in the template ? + if ( IsQueryLoadTemplate() ) + { + // load document info of template + BOOL bOK = FALSE; + util::DateTime aTemplDate; + try + { + Reference < document::XStandaloneDocumentInfo > xDocInfo ( + ::comphelper::getProcessServiceFactory()->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.document.StandaloneDocumentInfo") ) ), + UNO_QUERY_THROW ); + Reference < beans::XFastPropertySet > xSet( xDocInfo, + UNO_QUERY_THROW ); + xDocInfo->loadFromURL( aTemplURL ); + Any aAny = xSet->getFastPropertyValue( WID_DATE_MODIFIED ); + ::com::sun::star::util::DateTime aTmp; + if ( aAny >>= aTemplDate ) + { + // get modify date from document info + bOK = TRUE; + } + } + catch ( Exception& ) + { + } + + // if modify date was read successfully + if ( bOK ) + { + // compare modify data of template with the last check date of the document + const util::DateTime aInfoDate( xDocProps->getTemplateDate() ); + if ( aTemplDate > aInfoDate ) + { + // ask user + if( bCanUpdateFromTemplate == document::UpdateDocMode::QUIET_UPDATE + || bCanUpdateFromTemplate == document::UpdateDocMode::FULL_UPDATE ) + bLoad = TRUE; + else if ( bCanUpdateFromTemplate == document::UpdateDocMode::ACCORDING_TO_CONFIG ) + { + String sMessage( SfxResId( STR_QRYTEMPL_MESSAGE ) ); + sMessage.SearchAndReplace( String::CreateFromAscii("$(ARG1)"), aTemplName ); + sfx2::QueryTemplateBox aBox( GetDialogParent(), sMessage ); + if ( RET_YES == aBox.Execute() ) + bLoad = TRUE; + } + + if( !bLoad ) + { + // user refuses, so don't ask again for this document + SetQueryLoadTemplate(FALSE); + SetModified( TRUE ); + } + } + } + + if ( bLoad ) + { + // styles should be updated, create document in organizer mode to read in the styles + //TODO: testen! + SfxObjectShellLock xTemplDoc = CreateObjectByFactoryName( GetFactory().GetFactoryName(), SFX_CREATE_MODE_ORGANIZER ); + xTemplDoc->DoInitNew(0); + + // TODO/MBA: do we need a BaseURL? Then LoadFrom must be extended! + //xTemplDoc->SetBaseURL( aFoundName ); + + // TODO/LATER: make sure that we don't use binary templates! + SfxMedium aMedium( aFoundName, STREAM_STD_READ ); + if ( xTemplDoc->LoadFrom( aMedium ) ) + { + // transfer styles from xTemplDoc to this document + // TODO/MBA: make sure that no BaseURL is needed in *this* document + LoadStyles(*xTemplDoc); + + // remember date/time of check + xDocProps->setTemplateDate(aTemplDate); + // TODO/LATER: new functionality to store document info is required ( didn't work for SO7 XML format ) +//REPLACE pInfo->Save(xDocStor); + } + } +/* + SfxConfigManager *pCfgMgr = SFX_CFGMANAGER(); + { + SfxConfigManager *pTemplCfg = new SfxConfigManager(aTemplStor, pCfgMgr); + SetConfigManager(pTemplCfg); + SetTemplateConfig(TRUE); + + // Falls der gerade zerst"orte CfgMgr des Dokuments der + // aktive war, pCfgMgr lieber neu holen + pCfgMgr = SFX_CFGMANAGER(); + + // ggf. den neuen ConfigManager aktivieren + if ( this == SfxObjectShell::Current() ) + pTemplCfg->Activate(pCfgMgr); + } +*/ + // Template und Template-DocInfo werden nicht mehr gebraucht +// delete pTemplInfo; + } + } +} + +SfxObjectShellRef MakeObjectShellForOrganizer_Impl( const String& aTargetURL, BOOL bForWriting ) +{ + // check for own format + SfxObjectShellRef xDoc; + StreamMode nMode = bForWriting ? SFX_STREAM_READWRITE : SFX_STREAM_READONLY; + SfxMedium *pMed = new SfxMedium( aTargetURL, nMode, FALSE, 0 ); + const SfxFilter* pFilter = NULL; + pMed->UseInteractionHandler(TRUE); + if( SFX_APP()->GetFilterMatcher().GuessFilter( *pMed, &pFilter ) == ERRCODE_NONE && pFilter && pFilter->IsOwnFormat() ) + { + // create document + xDoc = SfxObjectShell::CreateObject( pFilter->GetServiceName(), SFX_CREATE_MODE_ORGANIZER ); + if ( xDoc.Is() ) + { + // partially load, so don't use DoLoad! + xDoc->DoInitNew(0); + // TODO/LATER: make sure that we don't use binary templates! + if( xDoc->LoadFrom( *pMed ) ) + { + // connect to storage, abandon temp. storage + xDoc->DoSaveCompleted( pMed ); + } + else + xDoc.Clear(); + } + } + else + delete pMed; + + return xDoc; +} + +sal_Bool SfxObjectShell::IsHelpDocument() const +{ + const SfxFilter* pFilter = GetMedium()->GetFilter(); + return ( pFilter && pFilter->GetFilterName().CompareToAscii("writer_web_HTML_help") == COMPARE_EQUAL ); +} + +void SfxObjectShell::ResetFromTemplate( const String& rTemplateName, const String& rFileName ) +{ + // only care about reseting this data for openoffice formats otherwise + if ( IsOwnStorageFormat_Impl( *GetMedium()) ) + { + uno::Reference<document::XDocumentProperties> xDocProps(getDocProperties()); + xDocProps->setTemplateURL( ::rtl::OUString() ); + xDocProps->setTemplateName( ::rtl::OUString() ); + xDocProps->setTemplateDate( util::DateTime() ); + xDocProps->resetUserData( ::rtl::OUString() ); + + // TODO/REFACTOR: + // Title? + + if( ::utl::LocalFileHelper::IsLocalFile( rFileName ) ) + { + String aFoundName; + if( SFX_APP()->Get_Impl()->GetDocumentTemplates()->GetFull( String(), rTemplateName, aFoundName ) ) + { + INetURLObject aObj( rFileName ); + xDocProps->setTemplateURL( aObj.GetMainURL(INetURLObject::DECODE_TO_IURI) ); + xDocProps->setTemplateName( rTemplateName ); + + ::DateTime now; + xDocProps->setTemplateDate( util::DateTime( + now.Get100Sec(), now.GetSec(), now.GetMin(), + now.GetHour(), now.GetDay(), now.GetMonth(), + now.GetYear() ) ); + + SetQueryLoadTemplate( sal_True ); + } + } + } +} + +sal_Bool SfxObjectShell::IsQueryLoadTemplate() const +{ + return pImp->bQueryLoadTemplate; +} + +sal_Bool SfxObjectShell::IsUseUserData() const +{ + return pImp->bUseUserData; +} + +void SfxObjectShell::SetQueryLoadTemplate( sal_Bool bNew ) +{ + if ( pImp->bQueryLoadTemplate != bNew ) + SetModified( TRUE ); + pImp->bQueryLoadTemplate = bNew; +} + +void SfxObjectShell::SetUseUserData( sal_Bool bNew ) +{ + if ( pImp->bUseUserData != bNew ) + SetModified( TRUE ); + pImp->bUseUserData = bNew; +} + +sal_Bool SfxObjectShell::IsLoadReadonly() const +{ + return pImp->bLoadReadonly; +} + +sal_Bool SfxObjectShell::IsSaveVersionOnClose() const +{ + return pImp->bSaveVersionOnClose; +} + +void SfxObjectShell::SetLoadReadonly( sal_Bool bNew ) +{ + if ( pImp->bLoadReadonly != bNew ) + SetModified( TRUE ); + pImp->bLoadReadonly = bNew; +} + +void SfxObjectShell::SetSaveVersionOnClose( sal_Bool bNew ) +{ + if ( pImp->bSaveVersionOnClose != bNew ) + SetModified( TRUE ); + pImp->bSaveVersionOnClose = bNew; +} + +sal_uInt32 SfxObjectShell::GetModifyPasswordHash() const +{ + return pImp->m_nModifyPasswordHash; +} + +sal_Bool SfxObjectShell::SetModifyPasswordHash( sal_uInt32 nHash ) +{ + if ( ( !IsReadOnly() && !IsReadOnlyUI() ) + || !(pImp->nFlagsInProgress & SFX_LOADED_MAINDOCUMENT ) ) + { + // the hash can be changed only in editable documents, + // or during loading of document + pImp->m_nModifyPasswordHash = nHash; + return sal_True; + } + + return sal_False; +} + +uno::Sequence< beans::PropertyValue > SfxObjectShell::GetModifyPasswordInfo() const +{ + return pImp->m_aModifyPasswordInfo; +} + +sal_Bool SfxObjectShell::SetModifyPasswordInfo( const uno::Sequence< beans::PropertyValue >& aInfo ) +{ + if ( ( !IsReadOnly() && !IsReadOnlyUI() ) + || !(pImp->nFlagsInProgress & SFX_LOADED_MAINDOCUMENT ) ) + { + // the hash can be changed only in editable documents, + // or during loading of document + pImp->m_aModifyPasswordInfo = aInfo; + return sal_True; + } + + return sal_False; +} + +void SfxObjectShell::SetModifyPasswordEntered( sal_Bool bEntered ) +{ + pImp->m_bModifyPasswordEntered = bEntered; +} + +sal_Bool SfxObjectShell::IsModifyPasswordEntered() +{ + return pImp->m_bModifyPasswordEntered; +} + diff --git a/sfx2/source/doc/objembed.cxx b/sfx2/source/doc/objembed.cxx new file mode 100644 index 000000000000..1c2105c210b9 --- /dev/null +++ b/sfx2/source/doc/objembed.cxx @@ -0,0 +1,317 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/embed/XEmbedObjectCreator.hpp> +#include <com/sun/star/embed/XComponentSupplier.hpp> +#include <com/sun/star/embed/XEmbedPersist.hpp> +#include <com/sun/star/util/XCloseable.hpp> +#include <com/sun/star/embed/EmbedStates.hpp> + +#include <sfx2/objsh.hxx> +#include <sfx2/app.hxx> +#include "objshimp.hxx" +#include <sfx2/sfx.hrc> +#include <sfx2/event.hxx> + +#include <comphelper/seqstream.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/storagehelper.hxx> +#include <svtools/embedtransfer.hxx> +#include <vcl/outdev.hxx> +#include <vcl/gdimtf.hxx> + +using namespace ::com::sun::star; + +// ----------------------------------------------------------------------- +// TODO/LATER: this workaround must be replaced by API in future if possible +SfxObjectShell* SfxObjectShell::GetParentShellByModel_Impl() +{ + SfxObjectShell* pResult = NULL; + + try { + uno::Reference< container::XChild > xChildModel( GetModel(), uno::UNO_QUERY ); + if ( xChildModel.is() ) + { + uno::Reference< lang::XUnoTunnel > xParentTunnel( xChildModel->getParent(), uno::UNO_QUERY ); + if ( xParentTunnel.is() ) + { + SvGlobalName aSfxIdent( SFX_GLOBAL_CLASSID ); + pResult = reinterpret_cast<SfxObjectShell*>(xParentTunnel->getSomething( + uno::Sequence< sal_Int8 >( aSfxIdent.GetByteSequence() ) ) ); + } + } + } + catch( uno::Exception& ) + { + // TODO: error handling + } + + return pResult; +} + +// ----------------------------------------------------------------------- +Printer* SfxObjectShell::GetDocumentPrinter() +{ + SfxObjectShell* pParent = GetParentShellByModel_Impl(); + if ( pParent ) + return pParent->GetDocumentPrinter(); + return NULL; +} + +// ----------------------------------------------------------------------- +OutputDevice* SfxObjectShell::GetDocumentRefDev() +{ + SfxObjectShell* pParent = GetParentShellByModel_Impl(); + if ( pParent ) + return pParent->GetDocumentRefDev(); + return NULL; +} + +// ----------------------------------------------------------------------- +void SfxObjectShell::OnDocumentPrinterChanged( Printer* /*pNewPrinter*/ ) +{ + // virtual method +} + +// ----------------------------------------------------------------------- +Rectangle SfxObjectShell::GetVisArea( USHORT nAspect ) const +{ + if( nAspect == ASPECT_CONTENT ) + return pImp->m_aVisArea; + else if( nAspect == ASPECT_THUMBNAIL ) + { + Rectangle aRect; + aRect.SetSize( OutputDevice::LogicToLogic( Size( 5000, 5000 ), + MAP_100TH_MM, GetMapUnit() ) ); + return aRect; + } + return Rectangle(); +} + +// ----------------------------------------------------------------------- +const Rectangle& SfxObjectShell::GetVisArea() const +{ + pImp->m_aVisArea = GetVisArea( ASPECT_CONTENT ); + return pImp->m_aVisArea; +} + +// ----------------------------------------------------------------------- +void SfxObjectShell::SetVisArea( const Rectangle & rVisArea ) +{ + if( pImp->m_aVisArea != rVisArea ) + { + pImp->m_aVisArea = rVisArea; + if ( GetCreateMode() == SFX_CREATE_MODE_EMBEDDED ) + { + if ( IsEnableSetModified() ) + SetModified( TRUE ); + + SFX_APP()->NotifyEvent(SfxEventHint( SFX_EVENT_VISAREACHANGED, GlobalEventConfig::GetEventName(STR_EVENT_VISAREACHANGED), this)); + + /* + Size aSize (GetVisArea().GetSize()); + if ( GetIPEnv() && GetIPEnv()->GetEditWin() ) + ViewChanged( ASPECT_CONTENT ); + */ + + + // OutPlace die Gr"o\se des MDI-Fensters anpassen + // Unbedingt den Gr"o\senvergleich machen, spart nicht nur Zeit, sondern + // vermeidet auch Rundungsfehler ! + /* + // in case of ole outplace editing the frame should be found + SfxViewFrame* pFrameToResize = pFrame ? pFrame : SfxViewFrame::GetFirst( GetObjectShell() ); + + if ( pFrameToResize && !pIPF && rRect.GetSize() != aSize && + !pFrameToResize->IsAdjustPosSizePixelLocked_Impl() ) + + { + // Zuerst die logischen Koordinaten von IP-Objekt und EditWindow + // ber"ucksichtigen + SfxViewShell *pShell = pFrameToResize->GetViewShell(); + Window *pWindow = pShell->GetWindow(); + + // Da in den Applikationen bei der R"ucktransformation immer die + // Eckpunkte tranformiert werden und nicht die Size (um die Ecken + // alignen zu k"onnen), transformieren wir hier auch die Punkte, um + // m"oglichst wenig Rundungsfehler zu erhalten. + Rectangle aRect = pWindow->LogicToPixel( rRect ); + Size aSize = aRect.GetSize(); + pShell->GetWindow()->SetSizePixel( aSize ); + pFrameToResize->DoAdjustPosSizePixel( pShell, Point(), aSize ); + } + + // bei InPlace die View skalieren + if ( GetIPEnv() && GetIPEnv()->GetEditWin() && !bDisableViewScaling && pIPF ) + pIPF->GetEnv_Impl()->MakeScale( rRect.GetSize(), GetMapUnit(), + pIPF->GetViewShell()->GetWindow()->GetOutputSizePixel() ); + */ + } + } +} + +// ----------------------------------------------------------------------- +void SfxObjectShell::SetVisAreaSize( const Size & rVisSize ) +{ + SetVisArea( Rectangle( GetVisArea().TopLeft(), rVisSize ) ); +} + +// ----------------------------------------------------------------------- +ULONG SfxObjectShell::GetMiscStatus() const +{ + return 0; +} + +// ----------------------------------------------------------------------- +MapUnit SfxObjectShell::GetMapUnit() const +{ + return pImp->m_nMapUnit; +} + +// ----------------------------------------------------------------------- +void SfxObjectShell::SetMapUnit( MapUnit nMapUnit ) +{ + pImp->m_nMapUnit = nMapUnit; +} + +// ----------------------------------------------------------------------- +void SfxObjectShell::FillTransferableObjectDescriptor( TransferableObjectDescriptor& rDesc ) const +{ + sal_uInt32 nClipFormat; + String aAppName, aShortName; + FillClass( &rDesc.maClassName, &nClipFormat, &aAppName, &rDesc.maTypeName, &aShortName, SOFFICE_FILEFORMAT_CURRENT ); + + rDesc.mnViewAspect = ASPECT_CONTENT; + rDesc.mnOle2Misc = GetMiscStatus(); + rDesc.maSize = OutputDevice::LogicToLogic( GetVisArea().GetSize(), GetMapUnit(), MAP_100TH_MM ); + rDesc.maDragStartPos = Point(); + rDesc.maDisplayName = String(); + rDesc.mbCanLink = FALSE; +} + +// ----------------------------------------------------------------------- +void SfxObjectShell::DoDraw( OutputDevice* pDev, + const Point & rObjPos, + const Size & rSize, + const JobSetup & rSetup, + USHORT nAspect ) +{ + MapMode aMod = pDev->GetMapMode(); + Size aSize = GetVisArea( nAspect ).GetSize(); + MapMode aWilliMode( GetMapUnit() ); + aSize = pDev->LogicToLogic( aSize, &aWilliMode, &aMod ); + if( aSize.Width() && aSize.Height() ) + { + Fraction aXF( rSize.Width(), aSize.Width() ); + Fraction aYF( rSize.Height(), aSize.Height() ); + +//REMOVE Point aOrg = rObjPos; +//REMOVE aMod.SetMapUnit( MAP_100TH_MM ); +//REMOVE aSize = pDev->LogicToLogic( GetVisArea( nAspect ).GetSize(), &aMod, &aWilliMode ); + DoDraw_Impl( pDev, rObjPos, aXF, aYF, rSetup, nAspect ); + } +} + +// ----------------------------------------------------------------------- +void SfxObjectShell::DoDraw_Impl( OutputDevice* pDev, + const Point & rViewPos, + const Fraction & rScaleX, + const Fraction & rScaleY, + const JobSetup & rSetup, + USHORT nAspect ) +{ + Rectangle aVisArea = GetVisArea( nAspect ); + // MapUnit des Ziels + MapMode aMapMode( GetMapUnit() ); + aMapMode.SetScaleX( rScaleX ); + aMapMode.SetScaleY( rScaleY ); + + // Ziel in Pixel + Point aOrg = pDev->LogicToLogic( rViewPos, NULL, &aMapMode ); + Point aDelta = aOrg - aVisArea.TopLeft(); + + // Origin entsprechend zum sichtbaren Bereich verschieben + // Origin mit Scale setzen + aMapMode.SetOrigin( aDelta ); + + // Deviceeinstellungen sichern + pDev->Push(); + + Region aRegion; + if( pDev->IsClipRegion() && pDev->GetOutDevType() != OUTDEV_PRINTER ) + { + aRegion = pDev->GetClipRegion(); + aRegion = pDev->LogicToPixel( aRegion ); + } + pDev->SetRelativeMapMode( aMapMode ); + + GDIMetaFile * pMtf = pDev->GetConnectMetaFile(); + if( pMtf ) + { + if( pMtf->IsRecord() && pDev->GetOutDevType() != OUTDEV_PRINTER ) + pMtf->Stop(); + else + pMtf = NULL; + } +// #ifndef UNX + if( pDev->IsClipRegion() && pDev->GetOutDevType() != OUTDEV_PRINTER ) +// #endif + { + aRegion = pDev->PixelToLogic( aRegion ); + pDev->SetClipRegion( aRegion ); + } + if( pMtf ) + pMtf->Record( pDev ); + +//REMOVE SvOutPlaceObjectRef xOutRef( this ); +//REMOVE if ( xOutRef.Is() ) +//REMOVE xOutRef->DrawObject( pDev, rSetup, rSize, nAspect ); +//REMOVE else + Draw( pDev, rSetup, nAspect ); +//REMOVE DrawHatch( pDev, aVisArea.TopLeft(), aVisArea.GetSize() ); + + // Deviceeinstellungen wieder herstellen + pDev->Pop(); + +} + +comphelper::EmbeddedObjectContainer& SfxObjectShell::GetEmbeddedObjectContainer() const +{ + if ( !pImp->mpObjectContainer ) + pImp->mpObjectContainer = new comphelper::EmbeddedObjectContainer( ((SfxObjectShell*)this)->GetStorage(), GetModel() ); + return *pImp->mpObjectContainer; +} + +void SfxObjectShell::ClearEmbeddedObjects() +{ + // frees alle space taken by embedded objects + DELETEZ( pImp->mpObjectContainer ); +} + diff --git a/sfx2/source/doc/objitem.cxx b/sfx2/source/doc/objitem.cxx new file mode 100644 index 000000000000..2980d984fd78 --- /dev/null +++ b/sfx2/source/doc/objitem.cxx @@ -0,0 +1,135 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#ifndef GCC +#endif + +#include <sfx2/objsh.hxx> +//#include "objshimp.hxx" +#include <sfx2/objitem.hxx> +#include <com/sun/star/lang/XUnoTunnel.hpp> + +//==================================================================== + +TYPEINIT1_AUTOFACTORY(SfxObjectShellItem,SfxPoolItem) +TYPEINIT1_AUTOFACTORY(SfxObjectItem,SfxPoolItem) + +//========================================================================= + +int SfxObjectShellItem::operator==( const SfxPoolItem &rItem ) const +{ + return PTR_CAST(SfxObjectShellItem, &rItem)->pObjSh == pObjSh; +} + +//-------------------------------------------------------------------- + +String SfxObjectShellItem::GetValueText() const +{ + return String(); +} + +//-------------------------------------------------------------------- + +SfxPoolItem* SfxObjectShellItem::Clone( SfxItemPool *) const +{ + return new SfxObjectShellItem( Which(), pObjSh ); +} + +//-------------------------------------------------------------------- + +sal_Bool SfxObjectShellItem::QueryValue( com::sun::star::uno::Any& rVal, BYTE /*nMemberId*/ ) const +{ + if ( pObjSh ) + { + // This item MUST provide a model. Please don't change this, there are UNO-based + // implementations which need it!! + rVal <<= pObjSh->GetModel(); + } + else + { + rVal <<= ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel >(); + } + return TRUE; +} + +//-------------------------------------------------------------------- + +sal_Bool SfxObjectShellItem::PutValue( const com::sun::star::uno::Any& rVal, BYTE /*nMemberId*/ ) +{ + // This item MUST have a model. Please don't change this, there are UNO-based + // implementations which need it!! + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel > xModel; + + if ( rVal >>= xModel ) + { + if ( xModel.is() ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XUnoTunnel > xTunnel( + xModel, ::com::sun::star::uno::UNO_QUERY ); + if ( xTunnel.is() ) + { + ::com::sun::star::uno::Sequence < sal_Int8 > aSeq( (sal_Int8*) SvGlobalName( SFX_GLOBAL_CLASSID ).GetBytes(), 16 ); + sal_Int64 nHandle = xTunnel->getSomething( aSeq ); + if ( nHandle ) + { + pObjSh = reinterpret_cast< SfxObjectShell* >(sal::static_int_cast<sal_IntPtr>( nHandle )); + return TRUE; + } + } + } + + pObjSh = 0; + return TRUE; + } + + return FALSE; +} + +//========================================================================= + +SfxObjectItem::SfxObjectItem( USHORT nWhichId, SfxShell *pSh ) +: SfxPoolItem( nWhichId ), + _pSh( pSh ) +{} + +//-------------------------------------------------------------------- + +int SfxObjectItem::operator==( const SfxPoolItem &rItem ) const +{ + SfxObjectItem *pOther = PTR_CAST(SfxObjectItem, &rItem); + return pOther->_pSh == _pSh; +} + +//-------------------------------------------------------------------- + +SfxPoolItem* SfxObjectItem::Clone( SfxItemPool *) const +{ + return new SfxObjectItem( Which(), _pSh ); +} diff --git a/sfx2/source/doc/objmisc.cxx b/sfx2/source/doc/objmisc.cxx new file mode 100644 index 000000000000..e386b2382acf --- /dev/null +++ b/sfx2/source/doc/objmisc.cxx @@ -0,0 +1,2590 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#ifndef _INETMSG_HXX //autogen +#include <svl/inetmsg.hxx> +#endif +#include <tools/diagnose_ex.h> +#include <svl/eitem.hxx> +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <svtools/svparser.hxx> // SvKeyValue +#include <vos/mutex.hxx> +#include <cppuhelper/exc_hlp.hxx> + +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/UpdateDocMode.hpp> +#include <com/sun/star/script/XTypeConverter.hpp> +#include <com/sun/star/script/provider/XScriptProviderFactory.hpp> +#include <com/sun/star/script/FinishEngineEvent.hpp> +#include <com/sun/star/script/InterruptReason.hpp> +#include <com/sun/star/script/XEngineListener.hpp> +#include <com/sun/star/script/XDebugging.hpp> +#ifndef _COM_SUN_STAR_SCRIPT_XINVOKATION_HPP_ +#include <com/sun/star/script/XInvocation.hpp> +#endif +#include <com/sun/star/script/ContextInformation.hpp> +#include <com/sun/star/script/FinishReason.hpp> +#include <com/sun/star/script/XEngine.hpp> +#include <com/sun/star/script/InterruptEngineEvent.hpp> +#include <com/sun/star/script/XLibraryAccess.hpp> +#include <com/sun/star/document/MacroExecMode.hpp> +#include <com/sun/star/document/XScriptInvocationContext.hpp> +#include <com/sun/star/embed/EmbedStates.hpp> +#include <com/sun/star/embed/XEmbedPersist.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> + + +#include <com/sun/star/script/provider/XScript.hpp> +#include <com/sun/star/script/provider/XScriptProvider.hpp> +#include <com/sun/star/script/provider/XScriptProviderSupplier.hpp> + +#ifndef _TOOLKIT_HELPER_VCLUNOHELPER_HXX_ +#include <toolkit/unohlp.hxx> +#endif + +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/Any.h> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/task/ErrorCodeRequest.hpp> +#include <unotools/securityoptions.hxx> + +#include <comphelper/processfactory.hxx> +#include <comphelper/componentcontext.hxx> +#include <comphelper/configurationhelper.hxx> + +#include <com/sun/star/security/XDocumentDigitalSignatures.hpp> +#include <com/sun/star/task/DocumentMacroConfirmationRequest.hpp> +#include <com/sun/star/task/InteractionClassification.hpp> +#include <com/sun/star/frame/XModel.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::script; +using namespace ::com::sun::star::script::provider; +using namespace ::com::sun::star::container; +#include <basic/sbuno.hxx> +#include <basic/sbstar.hxx> +#ifndef _SB_BASMGR_HXX +#include <basic/basmgr.hxx> +#endif +#ifndef _VCL_MSGBOX_HXX +#include <vcl/msgbox.hxx> +#endif +#include <basic/sbx.hxx> +#include <svtools/sfxecode.hxx> +#include <svtools/ehdl.hxx> + +#include <unotools/pathoptions.hxx> +#include <unotools/ucbhelper.hxx> +#include <tools/inetmime.hxx> +#include <tools/urlobj.hxx> +#include <svl/inettype.hxx> +#include <svl/sharecontrolfile.hxx> +#include <osl/file.hxx> +#include <rtl/bootstrap.hxx> +#include <vcl/svapp.hxx> +#include <framework/interaction.hxx> +#include <comphelper/storagehelper.hxx> +#include <comphelper/documentconstants.hxx> + +#include <sfx2/signaturestate.hxx> +#include <sfx2/app.hxx> +#include "appdata.hxx" +#include <sfx2/request.hxx> +#include <sfx2/bindings.hxx> +#include "sfxresid.hxx" +#include <sfx2/docfile.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/objsh.hxx> +#include "objshimp.hxx" +#include <sfx2/event.hxx> +#include "fltfnc.hxx" +#include <sfx2/sfx.hrc> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/ctrlitem.hxx> +#include "arrdecl.hxx" +#include <sfx2/module.hxx> +#include <sfx2/macrconf.hxx> +#include <sfx2/docfac.hxx> +#include "helper.hxx" +#include "doc.hrc" +#include "workwin.hxx" +#include "helpid.hrc" +#include "../appl/app.hrc" +#include <sfx2/sfxdlg.hxx> +#include "appbaslib.hxx" +#include <openflag.hxx> // SFX_STREAM_READWRITE + +using namespace ::com::sun::star; + +// class SfxHeaderAttributes_Impl ---------------------------------------- + +class SfxHeaderAttributes_Impl : public SvKeyValueIterator +{ +private: + SfxObjectShell* pDoc; + SvKeyValueIteratorRef xIter; + sal_Bool bAlert; + +public: + SfxHeaderAttributes_Impl( SfxObjectShell* pSh ) : + SvKeyValueIterator(), pDoc( pSh ), + xIter( pSh->GetMedium()->GetHeaderAttributes_Impl() ), + bAlert( sal_False ) {} + + virtual sal_Bool GetFirst( SvKeyValue& rKV ) { return xIter->GetFirst( rKV ); } + virtual sal_Bool GetNext( SvKeyValue& rKV ) { return xIter->GetNext( rKV ); } + virtual void Append( const SvKeyValue& rKV ); + + void ClearForSourceView() { xIter = new SvKeyValueIterator; bAlert = sal_False; } + void SetAttributes(); + void SetAttribute( const SvKeyValue& rKV ); +}; + +//========================================================================= + +sal_uInt16 __READONLY_DATA aTitleMap_Impl[3][2] = +{ + // local remote + /* SFX_TITLE_CAPTION */ { SFX_TITLE_FILENAME, SFX_TITLE_TITLE }, + /* SFX_TITLE_PICKLIST */ { 32, SFX_TITLE_FULLNAME }, + /* SFX_TITLE_HISTORY */ { 32, SFX_TITLE_FULLNAME } +}; + +//========================================================================= + +void SfxObjectShell::AbortImport() +{ + pImp->bIsAbortingImport = sal_True; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::IsAbortingImport() const +{ + return pImp->bIsAbortingImport; +} + +//------------------------------------------------------------------------- + +uno::Reference<document::XDocumentProperties> +SfxObjectShell::getDocProperties() +{ + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps( + xDPS->getDocumentProperties()); + DBG_ASSERT(xDocProps.is(), + "SfxObjectShell: model has no DocumentProperties"); + return xDocProps; +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::DoFlushDocInfo() +{ +} + +//------------------------------------------------------------------------- + +// Note: the only thing that calls this is the modification event handler +// that is installed at the XDocumentProperties +void SfxObjectShell::FlushDocInfo() +{ + if ( IsLoading() ) + return; + + SetModified(sal_True); + uno::Reference<document::XDocumentProperties> xDocProps(getDocProperties()); + DoFlushDocInfo(); // call template method + ::rtl::OUString url(xDocProps->getAutoloadURL()); + sal_Int32 delay(xDocProps->getAutoloadSecs()); + SetAutoLoad( INetURLObject(url), delay * 1000, + (delay > 0) || url.getLength() ); +/* + // bitte beachten: + // 1. Titel in DocInfo aber nicht am Doc (nach HTML-Import) + // => auch am Doc setzen + // 2. Titel in DocInfo leer (Briefumschlagsdruck) + // => nicht am Doc setzen, da sonst "unbenanntX" daraus wird + String aDocInfoTitle = GetDocInfo().GetTitle(); + if ( aDocInfoTitle.Len() ) + SetTitle( aDocInfoTitle ); + else + { + pImp->aTitle.Erase(); + SetNamedVisibility_Impl(); + if ( GetMedium() ) + { + SfxShell::SetName( GetTitle(SFX_TITLE_APINAME) ); + Broadcast( SfxSimpleHint(SFX_HINT_TITLECHANGED) ); + } + }*/ +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::SetError( sal_uInt32 lErr, const ::rtl::OUString& aLogMessage ) +{ + if(pImp->lErr==ERRCODE_NONE) + { + pImp->lErr=lErr; + + if( lErr != ERRCODE_NONE && aLogMessage.getLength() ) + AddLog( aLogMessage ); + } +} + +//------------------------------------------------------------------------- + +sal_uInt32 SfxObjectShell::GetError() const +{ + return ERRCODE_TOERROR(GetErrorCode()); +} + +//------------------------------------------------------------------------- + +sal_uInt32 SfxObjectShell::GetErrorCode() const +{ + sal_uInt32 lError=pImp->lErr; + if(!lError && GetMedium()) + lError=GetMedium()->GetErrorCode(); + return lError; +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::ResetError() +{ + if( pImp->lErr != ERRCODE_NONE ) + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Resetting Error." ) ) ); + + pImp->lErr=0; + SfxMedium * pMed = GetMedium(); + if( pMed ) + pMed->ResetError(); +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::IsTemplate() const +{ + return pImp->bIsTemplate; +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::SetTemplate(sal_Bool bIs) +{ + pImp->bIsTemplate=bIs; + SfxFilterMatcher aMatcher( GetFactory().GetFactoryName() ); + SfxFilterMatcherIter aIter( &aMatcher, SFX_FILTER_TEMPLATEPATH ); + SfxMedium* pMed = GetMedium(); + if( pMed ) pMed->SetFilter( aIter.First() ); +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::EnableSetModified( sal_Bool bEnable ) +{ +#ifdef DBG_UTIL + if ( bEnable == pImp->m_bEnableSetModified ) + DBG_WARNING( "SFX_PERSIST: EnableSetModified 2x mit dem gleichen Wert gerufen" ); +#endif + pImp->m_bEnableSetModified = bEnable; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::IsEnableSetModified() const +{ + return pImp->m_bEnableSetModified && !IsReadOnly(); +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::IsModified() +{ + if ( pImp->m_bIsModified ) + return sal_True; + + if ( !pImp->m_xDocStorage.is() || IsReadOnly() ) + { + // if the document still has no storage and is not set to be modified explicitly it is not modified + // a readonly document is also not modified + + return sal_False; + } + + uno::Sequence < ::rtl::OUString > aNames = GetEmbeddedObjectContainer().GetObjectNames(); + for ( sal_Int32 n=0; n<aNames.getLength(); n++ ) + { + uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObjectContainer().GetEmbeddedObject( aNames[n] ); + OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" ); + if ( xObj.is() ) + { + try + { + sal_Int32 nState = xObj->getCurrentState(); + if ( nState != embed::EmbedStates::LOADED ) + { + uno::Reference< util::XModifiable > xModifiable( xObj->getComponent(), uno::UNO_QUERY ); + if ( xModifiable.is() && xModifiable->isModified() ) + return sal_True; + } + } + catch( uno::Exception& ) + {} + } + } + + return sal_False; +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::SetModified( sal_Bool bModifiedP ) +{ +#ifdef DBG_UTIL + if ( !bModifiedP && !IsEnableSetModified() ) + DBG_WARNING( "SFX_PERSIST: SetModified( sal_False ), obwohl IsEnableSetModified() == sal_False" ); +#endif + + if( !IsEnableSetModified() ) + return; + + if( pImp->m_bIsModified != bModifiedP ) + { + pImp->m_bIsModified = bModifiedP; + ModifyChanged(); + } +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::ModifyChanged() +{ + if ( pImp->bClosing ) + // SetModified aus dem dispose des Models! + return; + + {DBG_CHKTHIS(SfxObjectShell, 0);} + + SfxViewFrame* pViewFrame = SfxViewFrame::Current(); + if ( pViewFrame ) + pViewFrame->GetBindings().Invalidate( SID_SAVEDOCS ); + + Invalidate( SID_SIGNATURE ); + Invalidate( SID_MACRO_SIGNATURE ); + Broadcast( SfxSimpleHint( SFX_HINT_TITLECHANGED ) ); // xmlsec05, signed state might change in title... + + SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_MODIFYCHANGED, GlobalEventConfig::GetEventName(STR_EVENT_MODIFYCHANGED), this ) ); +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::IsReadOnlyUI() const + +/* [Beschreibung] + + Liefert sal_True, wenn das Dokument fuer die UI wie r/o behandelt werden + soll. Dieses ist unabhaengig vom tatsaechlichen r/o, welches per + <IsReadOnly()> erfragbar ist. +*/ + +{ + return pImp->bReadOnlyUI; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::IsReadOnlyMedium() const + +/* [Beschreibung] + + Liefert sal_True, wenn das Medium r/o ist bzw. r/o geoeffnet wurde. +*/ + +{ + if ( !pMedium ) + return sal_True; + return pMedium->IsReadOnly(); +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::SetReadOnlyUI( sal_Bool bReadOnly ) + +/* [Beschreibung] + + Schaltet das Dokument in einen r/o bzw. r/w Zustand ohne es neu + zu laden und ohne die Open-Modi des Mediums zu aendern. +*/ + +{ + sal_Bool bWasRO = IsReadOnly(); + pImp->bReadOnlyUI = bReadOnly; + if ( bWasRO != IsReadOnly() ) + { + Broadcast( SfxSimpleHint(SFX_HINT_MODECHANGED) ); + //if ( pImp->pDocInfo ) + // pImp->pDocInfo->SetReadOnly( IsReadOnly() ); + } +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::SetReadOnly() +{ + // Let the document be completely readonly, means that the + // medium open mode is adjusted accordingly, and the write lock + // on the file is removed. + + if ( pMedium && !IsReadOnlyMedium() ) + { + sal_Bool bWasROUI = IsReadOnly(); + + pMedium->UnlockFile( sal_False ); + + // the storage-based mediums are already based on the temporary file + // so UnlockFile has already closed the locking stream + if ( !pMedium->HasStorage_Impl() && IsLoadingFinished() ) + pMedium->CloseInStream(); + + pMedium->SetOpenMode( SFX_STREAM_READONLY, pMedium->IsDirect(), sal_True ); + pMedium->GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, sal_True ) ); + + if ( !bWasROUI ) + Broadcast( SfxSimpleHint(SFX_HINT_MODECHANGED) ); + } +} +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::IsReadOnly() const +{ + return pImp->bReadOnlyUI || IsReadOnlyMedium(); +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::IsInModalMode() const +{ + return pImp->bModalMode || pImp->bRunningMacro; +} + +//<!--Added by PengYunQuan for Validity Cell Range Picker +sal_Bool SfxObjectShell::AcceptStateUpdate() const +{ + return !IsInModalMode(); +} +//-->Added by PengYunQuan for Validity Cell Range Picker + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::HasModalViews() const +{ + SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this ); + while( pFrame ) + { + if ( pFrame->IsInModalMode() ) + return sal_True; + + pFrame = SfxViewFrame::GetNext( *pFrame, this ); + } + + return sal_False; +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::SetMacroMode_Impl( sal_Bool bModal ) +{ + if ( !pImp->bRunningMacro != !bModal ) + { + pImp->bRunningMacro = bModal; + Broadcast( SfxSimpleHint( SFX_HINT_MODECHANGED ) ); + } +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::SetModalMode_Impl( sal_Bool bModal ) +{ + // nur Broadcasten wenn modifiziert, sonst ggf. Endlosrekursion + if ( !pImp->bModalMode != !bModal ) + { + // zentral mitz"ahlen + sal_uInt16 &rDocModalCount = SFX_APP()->Get_Impl()->nDocModalMode; + if ( bModal ) + ++rDocModalCount; + else + --rDocModalCount; + + // umschalten + pImp->bModalMode = bModal; + Broadcast( SfxSimpleHint( SFX_HINT_MODECHANGED ) ); + } +} + +//-------------------------------------------------------------------- +sal_Bool SfxObjectShell::SwitchToShared( sal_Bool bShared, sal_Bool bSave ) +{ + sal_Bool bResult = sal_True; + + if ( bShared != IsDocShared() ) + { + ::rtl::OUString aOrigURL = GetMedium()->GetURLObject().GetMainURL( INetURLObject::NO_DECODE ); + + if ( !aOrigURL.getLength() && bSave ) + { + // this is a new document, let it be stored before switching to the shared mode; + // the storing should be done without shared flag, since it is possible that the + // target location does not allow to create sharing control file; + // the shared flag will be set later after creation of sharing control file + SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst( this ); + + if ( pViewFrame ) + { + // TODO/LATER: currently the application guards against the reentrance problem + const SfxPoolItem* pItem = pViewFrame->GetBindings().ExecuteSynchron( HasName() ? SID_SAVEDOC : SID_SAVEASDOC ); + SfxBoolItem* pResult = PTR_CAST( SfxBoolItem, pItem ); + bResult = ( pResult && pResult->GetValue() ); + if ( bResult ) + aOrigURL = GetMedium()->GetURLObject().GetMainURL( INetURLObject::NO_DECODE ); + } + } + + sal_Bool bOldValue = HasSharedXMLFlagSet(); + SetSharedXMLFlag( bShared ); + + sal_Bool bRemoveEntryOnError = sal_False; + if ( bResult && bShared ) + { + try + { + ::svt::ShareControlFile aControlFile( aOrigURL ); + aControlFile.InsertOwnEntry(); + bRemoveEntryOnError = sal_True; + } + catch( uno::Exception& ) + { + bResult = sal_False; + } + } + + if ( bResult && bSave ) + { + SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst( this ); + + if ( pViewFrame ) + { + // TODO/LATER: currently the application guards against the reentrance problem + SetModified( sal_True ); // the modified flag has to be set to let the document be stored with the shared flag + const SfxPoolItem* pItem = pViewFrame->GetBindings().ExecuteSynchron( HasName() ? SID_SAVEDOC : SID_SAVEASDOC ); + SfxBoolItem* pResult = PTR_CAST( SfxBoolItem, pItem ); + bResult = ( pResult && pResult->GetValue() ); + } + } + + if ( bResult ) + { + // TODO/LATER: Is it possible that the following calls fail? + if ( bShared ) + { + pImp->m_aSharedFileURL = aOrigURL; + GetMedium()->SwitchDocumentToTempFile(); + } + else + { + ::rtl::OUString aTempFileURL = pMedium->GetURLObject().GetMainURL( INetURLObject::NO_DECODE ); + GetMedium()->SwitchDocumentToFile( GetSharedFileURL() ); + pImp->m_aSharedFileURL = ::rtl::OUString(); + + // now remove the temporary file the document was based on + ::utl::UCBContentHelper::Kill( aTempFileURL ); + + try + { + // aOrigURL can not be used since it contains an old value + ::svt::ShareControlFile aControlFile( GetMedium()->GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ); + aControlFile.RemoveFile(); + } + catch( uno::Exception& ) + { + } + } + } + else + { + // the saving has failed! + if ( bRemoveEntryOnError ) + { + try + { + ::svt::ShareControlFile aControlFile( aOrigURL ); + aControlFile.RemoveEntry(); + } + catch( uno::Exception& ) + {} + } + + SetSharedXMLFlag( bOldValue ); + } + } + else + bResult = sal_False; // the second switch to the same mode + + if ( bResult ) + SetTitle( String() ); + + return bResult; +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::DisconnectFromShared() +{ + if ( IsDocShared() ) + { + if ( pMedium && pMedium->GetStorage().is() ) + { + // set medium to noname + pMedium->SetName( String(), sal_True ); + pMedium->Init_Impl(); + + // drop resource + SetNoName(); + InvalidateName(); + + // untitled document must be based on temporary storage + // the medium should not dispose the storage in this case + if ( pMedium->GetStorage() == GetStorage() ) + ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ); + + pMedium->Close(); + FreeSharedFile(); + + SfxMedium* pTmpMedium = pMedium; + ForgetMedium(); + if( !DoSaveCompleted( pTmpMedium ) ) + SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + else + { + // the medium should not dispose the storage, DoSaveCompleted() has let it to do so + pMedium->CanDisposeStorage_Impl( sal_False ); + } + + pMedium->GetItemSet()->ClearItem( SID_DOC_READONLY ); + pMedium->SetOpenMode( SFX_STREAM_READWRITE, sal_True, sal_True ); + + SetTitle( String() ); + } + } +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::FreeSharedFile() +{ + if ( pMedium ) + FreeSharedFile( pMedium->GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ); +} + +//-------------------------------------------------------------------- +void SfxObjectShell::FreeSharedFile( const ::rtl::OUString& aTempFileURL ) +{ + SetSharedXMLFlag( sal_False ); + + if ( IsDocShared() && aTempFileURL.getLength() + && !::utl::UCBContentHelper::EqualURLs( aTempFileURL, GetSharedFileURL() ) ) + { + if ( pImp->m_bAllowShareControlFileClean ) + { + try + { + ::svt::ShareControlFile aControlFile( GetSharedFileURL() ); + aControlFile.RemoveEntry(); + } + catch( uno::Exception& ) + { + } + } + + // the cleaning is forbidden only once + pImp->m_bAllowShareControlFileClean = sal_True; + + // now remove the temporary file the document is based currently on + ::utl::UCBContentHelper::Kill( aTempFileURL ); + + pImp->m_aSharedFileURL = ::rtl::OUString(); + } +} + +//-------------------------------------------------------------------- +void SfxObjectShell::DoNotCleanShareControlFile() +{ + pImp->m_bAllowShareControlFileClean = sal_False; +} + +//-------------------------------------------------------------------- +void SfxObjectShell::SetSharedXMLFlag( sal_Bool bFlag ) const +{ + pImp->m_bSharedXMLFlag = bFlag; +} + +//-------------------------------------------------------------------- +sal_Bool SfxObjectShell::HasSharedXMLFlagSet() const +{ + return pImp->m_bSharedXMLFlag; +} + +//-------------------------------------------------------------------- + +sal_Bool SfxObjectShell::IsDocShared() const +{ + return ( pImp->m_aSharedFileURL.getLength() > 0 ); +} + +//-------------------------------------------------------------------- + +::rtl::OUString SfxObjectShell::GetSharedFileURL() const +{ + return pImp->m_aSharedFileURL; +} + +//-------------------------------------------------------------------- + +Size SfxObjectShell::GetFirstPageSize() +{ + return GetVisArea(ASPECT_THUMBNAIL).GetSize(); +} + + +//-------------------------------------------------------------------- + +IndexBitSet& SfxObjectShell::GetNoSet_Impl() +{ + return pImp->aBitSet; +} + +//-------------------------------------------------------------------- +// changes the title of the document + +void SfxObjectShell::SetTitle +( + const String& rTitle // der neue Titel des Dokuments +) + +/* [Beschreibung] + + Mit dieser Methode kann der Titel des Dokuments gesetzt werden. + Dieser entspricht initial dem kompletten Dateinamen. Ein Setzen + des Titels wirkt jedoch nicht zu"uck auf den Dateinamen; er wird + jedoch in den Caption-Bars der MDI-Fenster angezeigt. +*/ + +{ + DBG_CHKTHIS(SfxObjectShell, 0); + + // nix zu tun? + if ( ( ( HasName() && pImp->aTitle == rTitle ) + || ( !HasName() && GetTitle() == rTitle ) ) + && !IsDocShared() ) + return; + + SfxApplication *pSfxApp = SFX_APP(); +#if 0 + // wird 'unbenannt#' als Titel gesetzt + String aNoName(SfxResId(STR_NONAME)); + if ( rTitle.Match(aNoName) <= aNoName.Len() ) + { + // er ist es selbst => ignorieren + pSfxApp->ReleaseIndex(pImp->nVisualDocumentNumber); + pImp->bIsNamedVisible=0; + } +#endif + + // ggf. die unbenannt-Nummer freigeben + if ( pImp->bIsNamedVisible && USHRT_MAX != pImp->nVisualDocumentNumber ) + { + pSfxApp->ReleaseIndex(pImp->nVisualDocumentNumber); + pImp->bIsNamedVisible = 0; + } + + // Title setzen + pImp->aTitle = rTitle; +// Wieso denn in der DocInfo? +// GetDocInfo().SetTitle( rTitle ); +// FlushDocInfo(); + + // Benachrichtigungen + if ( GetMedium() ) + { + SfxShell::SetName( GetTitle(SFX_TITLE_APINAME) ); + Broadcast( SfxSimpleHint(SFX_HINT_TITLECHANGED) ); + } +} + +//-------------------------------------------------------------------- + +#if OSL_DEBUG_LEVEL > 1 +String X(const String &rRet) +{ + if ( !rRet.Len() ) + return DEFINE_CONST_UNICODE( "-empty-" ); + return rRet; +} +#else +#define X(ret) ret +#endif + +//-------------------------------------------------------------------- +//-------------------------------------------------------------------- +String SfxObjectShell::GetTitle +( + sal_uInt16 nMaxLength /* 0 (default) + der Titel selbst, so wie er ist + + 1 (==SFX_TITLE_FILENAME) + liefert den logischen Dateinamen ohne Pfad + (unter WNT je nach Systemeinstellung ohne + Extension) + + 2 (==SFX_TITLE_FULLNAME) + liefert den mit komplettem logischen Dateinamen + mit Pfad (remote => ::com::sun::star::util::URL) + + 3 (==SFX_TITLE_APINAME) + liefert den logischen Dateinamen ohne Pfad + und Extension + + 4 (==SFX_TITLE_DETECT) + liefert den kompletten Titel, falls noch + nicht gesetzt wird aber aus DocInfo oder + dem Namen des Medium erzeugt + + 5 (==SFX_TITLE_CAPTION) + liefert den Titel so, wie MB ihn heute in + der CaptionBar anzeigen m"ochte + + 6 (==SFX_TITLE_PICKLIST) + liefert den Titel so, wie MB ihn heute in + der PickList anzeigen m"ochte + + 7 (==SFX_TITLE_HISTORY) + liefert den Titel so, wie MB ihn heute in + der History anzeigen m"ochte + + 10 bis USHRT_MAX + liefert maximal 'nMaxLength' Zeichen vom logischen + Dateinamen inkl. Pfad (remote => ::com::sun::star::util::URL) + */ +) const + +/* [Beschreibung] + + Liefert den Titel bzw. logischen Dateinamen des Dokuments, je nach + 'nMaxLength'. + + Falls der Dateiname mit Pfad verwendet wird, wird die Namensk"urzung durch + Ersetzung eines oder mehrerer Directory-Namen durch "..." durchgef"uhrt, + URLs werden z.Zt. immer komplett geliefert. +*/ + +{ +// if ( GetCreateMode() == SFX_CREATE_MODE_EMBEDDED ) +// return String(); + SfxMedium *pMed = GetMedium(); + if ( IsLoading() ) + return String(); + +/* if ( !nMaxLength && pImp->pDocInfo ) + { + String aTitle = pImp->pDocInfo->GetTitle(); + if ( aTitle.Len() ) + return aTitle; + } */ + + // Titel erzeugen? + if ( SFX_TITLE_DETECT == nMaxLength && !pImp->aTitle.Len() ) + { + static sal_Bool bRecur = sal_False; + if ( bRecur ) + return DEFINE_CONST_UNICODE( "-not available-" ); + bRecur = sal_True; + + String aTitle; + SfxObjectShell *pThis = (SfxObjectShell*) this; + + if ( pMed ) + { + SFX_ITEMSET_ARG( pMed->GetItemSet(), pNameItem, SfxStringItem, SID_DOCINFO_TITLE, sal_False ); + if ( pNameItem ) + aTitle = pNameItem->GetValue(); + } + + if ( !aTitle.Len() ) + aTitle = GetTitle( SFX_TITLE_FILENAME ); + + if ( IsTemplate() ) + pThis->SetTitle( aTitle ); + bRecur = sal_False; + return X(aTitle); + } + else if (SFX_TITLE_APINAME == nMaxLength ) + return X(GetAPIName()); + + // Sonderfall Vorlagen: + if( IsTemplate() && pImp->aTitle.Len() && + ( nMaxLength == SFX_TITLE_CAPTION || nMaxLength == SFX_TITLE_PICKLIST ) ) + return X(pImp->aTitle); + + // Picklist/Caption wird gemappt + if ( pMed && ( nMaxLength == SFX_TITLE_CAPTION || nMaxLength == SFX_TITLE_PICKLIST ) ) + { + // Wenn ein spezieller Titel beim "Offnen mitgegeben wurde; + // wichtig bei URLs, die INET_PROT_FILE verwenden, denn bei denen + // wird der gesetzte Titel nicht beachtet. + // (s.u., Auswertung von aTitleMap_Impl) + SFX_ITEMSET_ARG( pMed->GetItemSet(), pNameItem, SfxStringItem, SID_DOCINFO_TITLE, sal_False ); + if ( pNameItem ) + return X( pNameItem->GetValue() ); + } + + // noch unbenannt? + DBG_ASSERT( !HasName() || pMed, "HasName() aber kein Medium?!?" ); + if ( !HasName() || !pMed ) + { + // schon Titel gesezt? + if ( pImp->aTitle.Len() ) + return X(pImp->aTitle); + + // mu\s es durchnumeriert werden? + String aNoName( SfxResId( STR_NONAME ) ); + if ( pImp->bIsNamedVisible ) + // Nummer hintenanh"angen + aNoName += String::CreateFromInt32( pImp->nVisualDocumentNumber ); + + // Dokument hei\st vorerst 'unbenannt#' + return X(aNoName); + } + + const INetURLObject aURL( IsDocShared() ? GetSharedFileURL() : ::rtl::OUString( GetMedium()->GetName() ) ); + if ( nMaxLength > SFX_TITLE_CAPTION && nMaxLength <= SFX_TITLE_HISTORY ) + { + sal_uInt16 nRemote; + if( !pMed || aURL.GetProtocol() == INET_PROT_FILE ) + nRemote = 0; + else + nRemote = 1; + nMaxLength = aTitleMap_Impl[nMaxLength-SFX_TITLE_CAPTION][nRemote]; + } + + // lokale Datei? + if ( aURL.GetProtocol() == INET_PROT_FILE ) + { + String aName( aURL.HasMark() ? INetURLObject( aURL.GetURLNoMark() ).PathToFileName() : aURL.PathToFileName() ); + if ( nMaxLength == SFX_TITLE_FULLNAME ) + return X( aName ); + else if ( nMaxLength == SFX_TITLE_FILENAME ) + return X( aURL.getName( INetURLObject::LAST_SEGMENT, + true, INetURLObject::DECODE_WITH_CHARSET ) ); + else if ( !pImp->aTitle.Len() ) + pImp->aTitle = aURL.getBase( INetURLObject::LAST_SEGMENT, + true, INetURLObject::DECODE_WITH_CHARSET ); + } + else + { + // ::com::sun::star::util::URL-Versionen + if ( nMaxLength >= SFX_TITLE_MAXLEN ) + { + String aComplete( aURL.GetMainURL( INetURLObject::NO_DECODE ) ); + if( aComplete.Len() > nMaxLength ) + { + String aRet( DEFINE_CONST_UNICODE( "..." ) ); + aRet += aComplete.Copy( aComplete.Len() - nMaxLength + 3, nMaxLength - 3 ); + return X( aRet ); + } + else + return X( aComplete ); + } + else if ( nMaxLength == SFX_TITLE_FILENAME ) + { + String aName( aURL.GetBase() ); + aName = INetURLObject::decode( aName, INET_HEX_ESCAPE, INetURLObject::DECODE_WITH_CHARSET ); + if( !aName.Len() ) + aName = aURL.GetURLNoPass(); + return X(aName); + } + else if ( nMaxLength == SFX_TITLE_FULLNAME ) + return X(aURL.GetMainURL( INetURLObject::DECODE_TO_IURI )); + + // ggf. Titel aus Dateiname generieren + if ( !pImp->aTitle.Len() ) + pImp->aTitle = aURL.GetBase(); + + // workaround for the case when the name can not be retrieved from URL by INetURLObject + if ( !pImp->aTitle.Len() ) + pImp->aTitle = aURL.GetMainURL( INetURLObject::DECODE_WITH_CHARSET ); + } + + // ganzer Titel + return X(pImp->aTitle); +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::InvalidateName() + +/* [Beschreibung] + + Ermittelt den Titel des Dokuments neu aus 'unbenannt', DocInfo-Titel + bzw. Dateinamen. Wird nach Laden aus Template oder SaveAs ben"otigt. +*/ + +{ + // Title neu erzeugen + pImp->aTitle.Erase(); +// pImp->nVisualDocumentNumber = USHRT_MAX; + //GetTitle( SFX_TITLE_DETECT ); + SetName( GetTitle( SFX_TITLE_APINAME ) ); + + // Benachrichtigungen + Broadcast( SfxSimpleHint(SFX_HINT_TITLECHANGED) ); +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::SetNamedVisibility_Impl() +{ + if ( !pImp->bIsNamedVisible ) + { + // Nummer verpassen + pImp->bIsNamedVisible = sal_True; + // ggf. neue Nummer verpassen + if ( !HasName() && USHRT_MAX == pImp->nVisualDocumentNumber && !pImp->aTitle.Len() ) + { + pImp->nVisualDocumentNumber = SFX_APP()->GetFreeIndex(); + Broadcast( SfxSimpleHint(SFX_HINT_TITLECHANGED) ); + } + } + + SetName( GetTitle(SFX_TITLE_APINAME) ); +} + +void SfxObjectShell::SetNoName() +{ + bHasName = 0; + bIsTmp = sal_True; + GetModel()->attachResource( ::rtl::OUString(), GetModel()->getArgs() ); +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::MemoryError() +{ +} + +//-------------------------------------------------------------------- + +SfxProgress* SfxObjectShell::GetProgress() const +{ + return pImp->pProgress; +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::SetProgress_Impl +( + SfxProgress *pProgress /* zu startender <SfxProgress> oder 0, falls + der Progress zur"uckgesetzt werden soll */ +) + +/* [Beschreibung] + + Interne Methode zum setzen oder zur"ucksetzen des Progress-Modes + f"ur diese SfxObjectShell. +*/ + +{ + DBG_ASSERT( ( !pImp->pProgress && pProgress ) || + ( pImp->pProgress && !pProgress ), + "Progress activation/deacitivation mismatch" ); + pImp->pProgress = pProgress; +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::PostActivateEvent_Impl( SfxViewFrame* pFrame ) +{ + SfxApplication* pSfxApp = SFX_APP(); + if ( !pSfxApp->IsDowning() && !IsLoading() && pFrame && !pFrame->GetFrame().IsClosing_Impl() ) + { + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pHiddenItem, SfxBoolItem, SID_HIDDEN, sal_False ); + if ( !pHiddenItem || !pHiddenItem->GetValue() ) + { + sal_uInt16 nId = pImp->nEventId; + pImp->nEventId = 0; + if ( nId == SFX_EVENT_OPENDOC ) + pSfxApp->NotifyEvent(SfxEventHint( nId, GlobalEventConfig::GetEventName(STR_EVENT_OPENDOC), this ), sal_False); + else if (nId == SFX_EVENT_CREATEDOC ) + pSfxApp->NotifyEvent(SfxEventHint( nId, GlobalEventConfig::GetEventName(STR_EVENT_CREATEDOC), this ), sal_False); + } + } +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::SetActivateEvent_Impl(sal_uInt16 nId ) +{ + if ( GetFactory().GetFlags() & SFXOBJECTSHELL_HASOPENDOC ) + pImp->nEventId = nId; +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::RegisterTransfer( SfxMedium& rMedium ) +/* [Beschreibung ] + Alle Medien, die aufgesetzt werden, um Teile eines Dokumentes zu + laden, muessen an der zugehoerigen SfxObjectShell angemeldet + werden. So kann dokumentweise abgebrochen werden. */ +{ + rMedium.SetReferer( GetMedium()->GetName() ); +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::PrepareReload( ) +/* [Beschreibung ] + Wird vor dem Reload gerufen und gibt die Moeglichkeit, + etwaige Caches zu leeren. */ +{ +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::LockAutoLoad( sal_Bool bLock ) + +/* Verhindert ein evtl. eintreffendes AutoLoad. Wird auch vor AutoLoad + eines umgebenden FrameSet beruecksichtigt. +*/ + +{ + if ( bLock ) + ++pImp->nAutoLoadLocks; + else + --pImp->nAutoLoadLocks; +} + +//------------------------------------------------------------------------- + +// kann nach frame.cxx gemoved werden, wenn 358+36x-Stand gemerged sind + +sal_Bool SfxFrame::IsAutoLoadLocked_Impl() const +{ + // sein einges Doc gelockt? + const SfxObjectShell* pObjSh = GetCurrentDocument(); + if ( !pObjSh || !pObjSh->IsAutoLoadLocked() ) + return sal_False; + + // seine Childs gelockt? + for ( sal_uInt16 n = GetChildFrameCount(); n--; ) + if ( !GetChildFrame(n)->IsAutoLoadLocked_Impl() ) + return sal_False; + + // sonst ist AutoLoad erlaubt + return sal_True; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::IsAutoLoadLocked() const + +/* Liefert, ob ein eintreffendes AutoLoad ausgefuehrt werden darf. Wird auch + vor AutoLoad eines umgebenden FrameSet beruecksichtigt. +*/ + +{ + return !IsReadOnly() || pImp->nAutoLoadLocks > 0; +} + +//------------------------------------------------------------------------- +void SfxObjectShell::BreakMacroSign_Impl( sal_Bool bBreakMacroSign ) +{ + pImp->m_bMacroSignBroken = bBreakMacroSign; +} + +//------------------------------------------------------------------------- +void SfxObjectShell::CheckSecurityOnLoading_Impl() +{ + uno::Reference< task::XInteractionHandler > xInteraction; + if ( GetMedium() ) + xInteraction = GetMedium()->GetInteractionHandler(); + + // check if there is a broken signature... + CheckForBrokenDocSignatures_Impl( xInteraction ); + + CheckEncryption_Impl( xInteraction ); + + // check macro security + pImp->aMacroMode.checkMacrosOnLoading( xInteraction ); +} + +//------------------------------------------------------------------------- +void SfxObjectShell::CheckEncryption_Impl( const uno::Reference< task::XInteractionHandler >& xHandler ) +{ + ::rtl::OUString aVersion; + sal_Bool bIsEncrypted = sal_False; + sal_Bool bHasNonEncrypted = sal_False; + + try + { + uno::Reference < beans::XPropertySet > xPropSet( GetStorage(), uno::UNO_QUERY_THROW ); + xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ) ) >>= aVersion; + xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "HasEncryptedEntries" ) ) ) >>= bIsEncrypted; + xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "HasNonEncryptedEntries" ) ) ) >>= bHasNonEncrypted; + } + catch( uno::Exception& ) + { + } + + if ( aVersion.compareTo( ODFVER_012_TEXT ) >= 0 ) + { + // this is ODF1.2 or later + if ( bIsEncrypted && bHasNonEncrypted ) + { + if ( !pImp->m_bIncomplEncrWarnShown ) + { + // this is an encrypted document with nonencrypted streams inside, show the warning + ::com::sun::star::task::ErrorCodeRequest aErrorCode; + aErrorCode.ErrCode = ERRCODE_SFX_INCOMPLETE_ENCRYPTION; + + SfxMedium::CallApproveHandler( xHandler, uno::makeAny( aErrorCode ), sal_False ); + pImp->m_bIncomplEncrWarnShown = sal_True; + } + + // broken signatures imply no macro execution at all + pImp->aMacroMode.disallowMacroExecution(); + } + } +} + +//------------------------------------------------------------------------- +void SfxObjectShell::CheckForBrokenDocSignatures_Impl( const uno::Reference< task::XInteractionHandler >& xHandler ) +{ + sal_Int16 nSignatureState = GetDocumentSignatureState(); + bool bSignatureBroken = ( nSignatureState == SIGNATURESTATE_SIGNATURES_BROKEN ); + if ( !bSignatureBroken ) + return; + + pImp->showBrokenSignatureWarning( xHandler ); + + // broken signatures imply no macro execution at all + pImp->aMacroMode.disallowMacroExecution(); +} + +//------------------------------------------------------------------------- +void SfxObjectShell::SetAutoLoad( + const INetURLObject& rUrl, sal_uInt32 nTime, sal_Bool bReload ) +{ + if ( pImp->pReloadTimer ) + DELETEZ(pImp->pReloadTimer); + if ( bReload ) + { + pImp->pReloadTimer = new AutoReloadTimer_Impl( + rUrl.GetMainURL( INetURLObject::DECODE_TO_IURI ), + nTime, bReload, this ); + pImp->pReloadTimer->Start(); + } +} + +sal_Bool SfxObjectShell::IsLoadingFinished() const +{ + return ( pImp->nLoadedFlags == SFX_LOADED_ALL ); +} + +void impl_addToModelCollection(const com::sun::star::uno::Reference< com::sun::star::frame::XModel >& xModel); +void SfxObjectShell::InitOwnModel_Impl() +{ + if ( !pImp->bModelInitialized ) + { + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False); + if ( pSalvageItem ) + { + pImp->aTempName = pMedium->GetPhysicalName(); + pMedium->GetItemSet()->ClearItem( SID_DOC_SALVAGE ); + pMedium->GetItemSet()->ClearItem( SID_FILE_NAME ); + pMedium->GetItemSet()->Put( SfxStringItem( SID_FILE_NAME, pMedium->GetOrigURL() ) ); + } + else + { + pMedium->GetItemSet()->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL ); + pMedium->GetItemSet()->ClearItem( SID_DOCUMENT ); + } + + pMedium->GetItemSet()->ClearItem( SID_REFERER ); + uno::Reference< frame::XModel > xModel ( GetModel(), uno::UNO_QUERY ); + if ( xModel.is() ) + { + ::rtl::OUString aURL = GetMedium()->GetOrigURL(); + SfxItemSet *pSet = GetMedium()->GetItemSet(); + if ( !GetMedium()->IsReadOnly() ) + pSet->ClearItem( SID_INPUTSTREAM ); + uno::Sequence< beans::PropertyValue > aArgs; + TransformItems( SID_OPENDOC, *pSet, aArgs ); + xModel->attachResource( aURL, aArgs ); + impl_addToModelCollection(xModel); + } + + pImp->bModelInitialized = sal_True; + } +} + +void SfxObjectShell::FinishedLoading( sal_uInt16 nFlags ) +{ + sal_Bool bSetModifiedTRUE = sal_False; + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False ); + if( ( nFlags & SFX_LOADED_MAINDOCUMENT ) && !(pImp->nLoadedFlags & SFX_LOADED_MAINDOCUMENT ) + && !(pImp->nFlagsInProgress & SFX_LOADED_MAINDOCUMENT )) + { + pImp->nFlagsInProgress |= SFX_LOADED_MAINDOCUMENT; + ((SfxHeaderAttributes_Impl*)GetHeaderAttributes())->SetAttributes(); + pImp->bImportDone = sal_True; + if( !IsAbortingImport() ) + PositionView_Impl(); + + if ( ( GetModifyPasswordHash() || GetModifyPasswordInfo().getLength() ) && !IsModifyPasswordEntered() ) + SetReadOnly(); + + // Salvage + if ( pSalvageItem ) + bSetModifiedTRUE = sal_True; + + if ( !IsEnableSetModified() ) + EnableSetModified( sal_True ); + + if( !bSetModifiedTRUE && IsEnableSetModified() ) + SetModified( sal_False ); + + CheckSecurityOnLoading_Impl(); + + bHasName = sal_True; // the document is loaded, so the name should already available + GetTitle( SFX_TITLE_DETECT ); + InitOwnModel_Impl(); + pImp->nFlagsInProgress &= ~SFX_LOADED_MAINDOCUMENT; + } + + if( ( nFlags & SFX_LOADED_IMAGES ) && !(pImp->nLoadedFlags & SFX_LOADED_IMAGES ) + && !(pImp->nFlagsInProgress & SFX_LOADED_IMAGES )) + { + pImp->nFlagsInProgress |= SFX_LOADED_IMAGES; + uno::Reference<document::XDocumentProperties> xDocProps( + getDocProperties()); + ::rtl::OUString url(xDocProps->getAutoloadURL()); + sal_Int32 delay(xDocProps->getAutoloadSecs()); + SetAutoLoad( INetURLObject(url), delay * 1000, + (delay > 0) || url.getLength() ); + if( !bSetModifiedTRUE && IsEnableSetModified() ) + SetModified( sal_False ); + Invalidate( SID_SAVEASDOC ); + pImp->nFlagsInProgress &= ~SFX_LOADED_IMAGES; + } + + pImp->nLoadedFlags |= nFlags; + + if ( !pImp->nFlagsInProgress ) + { + // in case of reentrance calls the first called FinishedLoading() call on the stack + // should do the notification, in result the notification is done when all the FinishedLoading() calls are finished + + if ( bSetModifiedTRUE ) + SetModified( sal_True ); + else + SetModified( sal_False ); + + if ( (pImp->nLoadedFlags & SFX_LOADED_MAINDOCUMENT ) && (pImp->nLoadedFlags & SFX_LOADED_IMAGES ) ) + { + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pTemplateItem, SfxBoolItem, SID_TEMPLATE, sal_False); + sal_Bool bTemplate = pTemplateItem && pTemplateItem->GetValue(); + + // closing the streams on loading should be under control of SFX! + DBG_ASSERT( pMedium->IsOpen(), "Don't close the medium when loading documents!" ); + + if ( bTemplate ) + { + TemplateDisconnectionAfterLoad(); + } + else + { + // if a readonly medium has storage then it's stream is already based on temporary file + if( !(pMedium->GetOpenMode() & STREAM_WRITE) && !pMedium->HasStorage_Impl() ) + // don't lock file opened read only + pMedium->CloseInStream(); + } + } + + SetInitialized_Impl( false ); + + // Title is not available until loading has finished + Broadcast( SfxSimpleHint( SFX_HINT_TITLECHANGED ) ); + if ( pImp->nEventId ) + PostActivateEvent_Impl(SfxViewFrame::GetFirst(this)); + } +} + +//------------------------------------------------------------------------- +extern void SetTemplate_Impl( const String&, const String&, SfxObjectShell* ); + +void SfxObjectShell::TemplateDisconnectionAfterLoad() +{ + // document is created from a template + //TODO/LATER: should the templates always be XML docs! + + SfxMedium* pTmpMedium = pMedium; + if ( pTmpMedium ) + { + String aName( pTmpMedium->GetName() ); + SFX_ITEMSET_ARG( pTmpMedium->GetItemSet(), pTemplNamItem, SfxStringItem, SID_TEMPLATE_NAME, sal_False); + String aTemplateName; + if ( pTemplNamItem ) + aTemplateName = pTemplNamItem->GetValue(); + else + { + // !TODO/LATER: what's this?! + // Interaktiv ( DClick, Contextmenu ) kommt kein Langname mit + aTemplateName = getDocProperties()->getTitle(); + if ( !aTemplateName.Len() ) + { + INetURLObject aURL( aName ); + aURL.CutExtension(); + aTemplateName = aURL.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + } + } + + // set medium to noname + pTmpMedium->SetName( String(), sal_True ); + pTmpMedium->Init_Impl(); + + // drop resource + SetNoName(); + InvalidateName(); + + if( IsPackageStorageFormat_Impl( *pTmpMedium ) ) + { + // untitled document must be based on temporary storage + // the medium should not dispose the storage in this case + uno::Reference < embed::XStorage > xTmpStor = ::comphelper::OStorageHelper::GetTemporaryStorage(); + GetStorage()->copyToStorage( xTmpStor ); + + // the medium should disconnect from the original location + // the storage should not be disposed since the document is still + // based on it, but in DoSaveCompleted it will be disposed + pTmpMedium->CanDisposeStorage_Impl( sal_False ); + pTmpMedium->Close(); + + // setting the new storage the medium will be based on + pTmpMedium->SetStorage_Impl( xTmpStor ); + + ForgetMedium(); + if( !DoSaveCompleted( pTmpMedium ) ) + SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + else + { + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False ); + sal_Bool bSalvage = pSalvageItem ? sal_True : sal_False; + + if ( !bSalvage ) + { + // some further initializations for templates + SetTemplate_Impl( aName, aTemplateName, this ); + } + + // the medium should not dispose the storage, DoSaveCompleted() has let it to do so + pTmpMedium->CanDisposeStorage_Impl( sal_False ); + } + } + else + { + // some further initializations for templates + SetTemplate_Impl( aName, aTemplateName, this ); + pTmpMedium->CreateTempFile( sal_True ); + } + + // templates are never readonly + pTmpMedium->GetItemSet()->ClearItem( SID_DOC_READONLY ); + pTmpMedium->SetOpenMode( SFX_STREAM_READWRITE, sal_True, sal_True ); + + // notifications about possible changes in readonly state and document info + Broadcast( SfxSimpleHint(SFX_HINT_MODECHANGED) ); + + // created untitled document can't be modified + SetModified( sal_False ); + } +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::PositionView_Impl() +{ + MarkData_Impl *pMark = Get_Impl()->pMarkData; + if( pMark ) + { + SfxViewShell* pSh = pMark->pFrame->GetViewShell(); + if( pMark->aUserData.Len() ) + pSh->ReadUserData( pMark->aUserData, sal_True ); + else if( pMark->aMark.Len() ) + pSh->JumpToMark( pMark->aMark ); + DELETEZ( Get_Impl()->pMarkData ); + } +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::IsLoading() const +/* [Beschreibung ] + Has FinishedLoading been called? */ +{ + return !( pImp->nLoadedFlags & SFX_LOADED_MAINDOCUMENT ); +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::CancelTransfers() +/* [Beschreibung ] + Hier koennen Transfers gecanceled werden, die nicht mit + RegisterTransfer registiert wurden */ +{ + if( ( pImp->nLoadedFlags & SFX_LOADED_ALL ) != SFX_LOADED_ALL ) + { + AbortImport(); + if( IsLoading() ) + FinishedLoading( SFX_LOADED_ALL ); + +/* + SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this ); + while( pFrame ) + { + pFrame->CancelTransfers(); + pFrame = SfxViewFrame::GetNext( *pFrame, this ); + }*/ + } +} + +//------------------------------------------------------------------------- + +AutoReloadTimer_Impl::AutoReloadTimer_Impl( + const String& rURL, sal_uInt32 nTime, sal_Bool bReloadP, SfxObjectShell* pSh ) + : aUrl( rURL ), bReload( bReloadP ), pObjSh( pSh ) +{ + SetTimeout( nTime ); +} + +//------------------------------------------------------------------------- + +void AutoReloadTimer_Impl::Timeout() +{ + SfxViewFrame *pFrame = SfxViewFrame::GetFirst( pObjSh ); + + if ( pFrame ) + { + // momentan nicht m"oglich/sinnvoll? + if ( !pObjSh->CanReload_Impl() || pObjSh->IsAutoLoadLocked() || Application::IsUICaptured() ) + { + // erneuten Versuch erlauben + Start(); + return; + } + + SfxAllItemSet aSet( SFX_APP()->GetPool() ); + aSet.Put( SfxBoolItem( SID_AUTOLOAD, sal_True ) ); + if ( aUrl.Len() ) + aSet.Put( SfxStringItem( SID_FILE_NAME, aUrl ) ); + SfxRequest aReq( SID_RELOAD, 0, aSet ); + pObjSh->Get_Impl()->pReloadTimer = 0; + delete this; + pFrame->ExecReload_Impl( aReq ); + return; + } + + pObjSh->Get_Impl()->pReloadTimer = 0; + delete this; +} + +SfxModule* SfxObjectShell::GetModule() const +{ + return GetFactory().GetModule(); +} + +sal_Bool SfxObjectShell::IsBasic( + const String & rCode, SbxObject * pVCtrl ) +{ + if( !rCode.Len() ) return sal_False; + return SfxMacroConfig::IsBasic( pVCtrl, rCode, GetBasicManager() ); +} + +ErrCode SfxObjectShell::CallBasic( const String& rMacro, + const String& rBasic, SbxObject* pVCtrl, SbxArray* pArgs, + SbxValue* pRet ) +{ + SfxApplication* pApp = SFX_APP(); + if( pApp->GetName() != rBasic ) + { + if ( !AdjustMacroMode( String() ) ) + return ERRCODE_IO_ACCESSDENIED; + } + + pApp->EnterBasicCall(); + BasicManager *pMgr = GetBasicManager(); + if( pApp->GetName() == rBasic ) + pMgr = pApp->GetBasicManager(); + ErrCode nRet = SfxMacroConfig::Call( pVCtrl, rMacro, pMgr, pArgs, pRet ); + pApp->LeaveBasicCall(); + return nRet; +} + +ErrCode SfxObjectShell::Call( const String & rCode, sal_Bool bIsBasicReturn, SbxObject * pVCtrl ) +{ + ErrCode nErr = ERRCODE_NONE; + if ( bIsBasicReturn ) + CallBasic( rCode, String(), pVCtrl ); + return nErr; +} + +namespace +{ + static bool lcl_isScriptAccessAllowed_nothrow( const Reference< XInterface >& _rxScriptContext ) + { + try + { + Reference< XEmbeddedScripts > xScripts( _rxScriptContext, UNO_QUERY ); + if ( !xScripts.is() ) + { + Reference< XScriptInvocationContext > xContext( _rxScriptContext, UNO_QUERY_THROW ); + xScripts.set( xContext->getScriptContainer(), UNO_SET_THROW ); + } + + return xScripts->getAllowMacroExecution(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return false; + } +} + +ErrCode SfxObjectShell::CallXScript( const Reference< XInterface >& _rxScriptContext, const ::rtl::OUString& _rScriptURL, + const Sequence< Any >& aParams, Any& aRet, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam, bool bRaiseError ) +{ + OSL_TRACE( "in CallXScript" ); + ErrCode nErr = ERRCODE_NONE; + + bool bIsDocumentScript = ( _rScriptURL.indexOfAsciiL( RTL_CONSTASCII_STRINGPARAM( "location=document" ) ) >= 0 ); + // TODO: we should parse the URL, and check whether there is a parameter with this name. + // Otherwise, we might find too much. + if ( bIsDocumentScript && !lcl_isScriptAccessAllowed_nothrow( _rxScriptContext ) ) + return ERRCODE_IO_ACCESSDENIED; + + bool bCaughtException = false; + Any aException; + try + { + // obtain/create a script provider + Reference< provider::XScriptProvider > xScriptProvider; + Reference< provider::XScriptProviderSupplier > xSPS( _rxScriptContext, UNO_QUERY ); + if ( xSPS.is() ) + xScriptProvider.set( xSPS->getScriptProvider() ); + + if ( !xScriptProvider.is() ) + { + ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); + Reference< provider::XScriptProviderFactory > xScriptProviderFactory( + aContext.getSingleton( "com.sun.star.script.provider.theMasterScriptProviderFactory" ), UNO_QUERY_THROW ); + xScriptProvider.set( xScriptProviderFactory->createScriptProvider( makeAny( _rxScriptContext ) ), UNO_SET_THROW ); + } + + // obtain the script, and execute it + Reference< provider::XScript > xScript( xScriptProvider->getScript( _rScriptURL ), UNO_QUERY_THROW ); + + aRet = xScript->invoke( aParams, aOutParamIndex, aOutParam ); + } + catch ( const uno::Exception& ) + { + aException = ::cppu::getCaughtException(); + bCaughtException = TRUE; + nErr = ERRCODE_BASIC_INTERNAL_ERROR; + } + + if ( bCaughtException && bRaiseError ) + { + ::std::auto_ptr< VclAbstractDialog > pScriptErrDlg; + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + if ( pFact ) + pScriptErrDlg.reset( pFact->CreateScriptErrorDialog( NULL, aException ) ); + OSL_ENSURE( pScriptErrDlg.get(), "SfxObjectShell::CallXScript: no script error dialog!" ); + + if ( pScriptErrDlg.get() ) + pScriptErrDlg->Execute(); + } + + OSL_TRACE( "leaving CallXScript" ); + return nErr; +} + +// perhaps rename to CallScript once we get rid of the existing CallScript +// and Call, CallBasic, CallStarBasic methods +ErrCode SfxObjectShell::CallXScript( const String& rScriptURL, + const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& + aParams, + ::com::sun::star::uno::Any& aRet, + ::com::sun::star::uno::Sequence< sal_Int16 >& aOutParamIndex, + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aOutParam + , bool bRaiseError ) +{ + return CallXScript( GetModel(), rScriptURL, aParams, aRet, aOutParamIndex, aOutParam, bRaiseError ); +} + +//------------------------------------------------------------------------- +namespace { + using namespace ::com::sun::star::uno; + + //..................................................................... + static SbxArrayRef lcl_translateUno2Basic( const void* _pAnySequence ) + { + SbxArrayRef xReturn; + if ( _pAnySequence ) + { + // in real it's a sequence of Any (by convention) + const Sequence< Any >* pArguments = static_cast< const Sequence< Any >* >( _pAnySequence ); + + // do we have arguments ? + if ( pArguments->getLength() ) + { + // yep + xReturn = new SbxArray; + String sEmptyName; + + // loop through the sequence + const Any* pArg = pArguments->getConstArray(); + const Any* pArgEnd = pArg + pArguments->getLength(); + + for ( sal_uInt16 nArgPos=1; pArg != pArgEnd; ++pArg, ++nArgPos ) + // and create a Sb object for every Any + xReturn->Put( GetSbUnoObject( sEmptyName, *pArg ), nArgPos ); + } + } + return xReturn; + } + //..................................................................... + void lcl_translateBasic2Uno( const SbxVariableRef& _rBasicValue, void* _pAny ) + { + if ( _pAny ) + *static_cast< Any* >( _pAny ) = sbxToUnoValue( _rBasicValue ); + } +} +//------------------------------------------------------------------------- +ErrCode SfxObjectShell::CallStarBasicScript( const String& _rMacroName, const String& _rLocation, + const void* _pArguments, void* _pReturn ) +{ + OSL_TRACE("in CallSBS"); + ::vos::OClearableGuard aGuard( Application::GetSolarMutex() ); + + // the arguments for the call + SbxArrayRef xMacroArguments = lcl_translateUno2Basic( _pArguments ); + + // the return value + SbxVariableRef xReturn = _pReturn ? new SbxVariable : NULL; + + // the location (document or application) + String sMacroLocation; + if ( _rLocation.EqualsAscii( "application" ) ) + sMacroLocation = SFX_APP()->GetName(); +#ifdef DBG_UTIL + else + DBG_ASSERT( _rLocation.EqualsAscii( "document" ), + "SfxObjectShell::CallStarBasicScript: invalid (unknown) location!" ); +#endif + + // call the script + ErrCode eError = CallBasic( _rMacroName, sMacroLocation, NULL, xMacroArguments, xReturn ); + + // translate the return value + lcl_translateBasic2Uno( xReturn, _pReturn ); + + // outta here + return eError; +} + +//------------------------------------------------------------------------- +ErrCode SfxObjectShell::CallScript( + const String & rScriptType, + const String & rCode, + const void *pArgs, + void *pRet +) +{ + ::vos::OClearableGuard aGuard( Application::GetSolarMutex() ); + ErrCode nErr = ERRCODE_NONE; + if( rScriptType.EqualsAscii( "StarBasic" ) ) + { + // the arguments for the call + SbxArrayRef xMacroArguments = lcl_translateUno2Basic( pArgs ); + + // the return value + SbxVariableRef xReturn = pRet ? new SbxVariable : NULL; + + // call the script + nErr = CallBasic( rCode, String(), NULL, xMacroArguments, xReturn ); + + // translate the return value + lcl_translateBasic2Uno( xReturn, pRet ); + + // did this fail because the method was not found? + if ( nErr == ERRCODE_BASIC_PROC_UNDEFINED ) + { // yep-> look in the application BASIC module + nErr = CallBasic( rCode, SFX_APP()->GetName(), NULL, xMacroArguments, xReturn ); + } + } + else if( rScriptType.EqualsAscii( "JavaScript" ) ) + { + DBG_ERROR( "JavaScript not allowed" ); + return 0; + } + else + { + DBG_ERROR( "StarScript not allowed" ); + } + return nErr; +} + +SfxFrame* SfxObjectShell::GetSmartSelf( SfxFrame* pSelf, SfxMedium& /*rMedium*/ ) +{ + return pSelf; +} + +SfxObjectShellFlags SfxObjectShell::GetFlags() const +{ + if( pImp->eFlags == SFXOBJECTSHELL_UNDEFINED ) + pImp->eFlags = GetFactory().GetFlags(); + return pImp->eFlags; +} + +void SfxObjectShell::SetFlags( SfxObjectShellFlags eFlags ) +{ + pImp->eFlags = eFlags; +} + +/* +void SfxObjectShell::SetBaseURL( const String& rURL ) +{ + pImp->aBaseURL = rURL; + pImp->bNoBaseURL = FALSE; +} + +const String& SfxObjectShell::GetBaseURLForSaving() const +{ + if ( pImp->bNoBaseURL ) + return String(); + return GetBaseURL(); +} + +const String& SfxObjectShell::GetBaseURL() const +{ + if ( pImp->aBaseURL.Len() ) + return pImp->aBaseURL; + return pMedium->GetBaseURL(); +} + +void SfxObjectShell::SetEmptyBaseURL() +{ + pImp->bNoBaseURL = TRUE; +} +*/ +String SfxObjectShell::QueryTitle( SfxTitleQuery eType ) const +{ + String aRet; + + switch( eType ) + { + case SFX_TITLE_QUERY_SAVE_NAME_PROPOSAL: + { + SfxMedium* pMed = GetMedium(); + const INetURLObject aObj( pMed->GetName() ); + aRet = aObj.GetMainURL( INetURLObject::DECODE_TO_IURI ); + if ( !aRet.Len() ) + aRet = GetTitle( SFX_TITLE_CAPTION ); + break; + } + } + return aRet; +} + +void SfxHeaderAttributes_Impl::SetAttributes() +{ + bAlert = sal_True; + SvKeyValue aPair; + for( sal_Bool bCont = xIter->GetFirst( aPair ); bCont; + bCont = xIter->GetNext( aPair ) ) + SetAttribute( aPair ); +} + +void SfxHeaderAttributes_Impl::SetAttribute( const SvKeyValue& rKV ) +{ + String aValue = rKV.GetValue(); + if( rKV.GetKey().CompareIgnoreCaseToAscii( "refresh" ) == COMPARE_EQUAL && rKV.GetValue().Len() ) + { + sal_uInt32 nTime = aValue.GetToken( 0, ';' ).ToInt32() ; + String aURL = aValue.GetToken( 1, ';' ); + aURL.EraseTrailingChars().EraseLeadingChars(); + uno::Reference<document::XDocumentProperties> xDocProps( + pDoc->getDocProperties()); + if( aURL.Copy(0, 4).CompareIgnoreCaseToAscii( "url=" ) == COMPARE_EQUAL ) + { + INetURLObject aObj; + INetURLObject( pDoc->GetMedium()->GetName() ).GetNewAbsURL( aURL.Copy( 4 ), &aObj ); + xDocProps->setAutoloadURL( + aObj.GetMainURL( INetURLObject::NO_DECODE ) ); + } + try + { + xDocProps->setAutoloadSecs( nTime ); + } + catch (lang::IllegalArgumentException &) + { + // ignore + } + } + else if( rKV.GetKey().CompareIgnoreCaseToAscii( "expires" ) == COMPARE_EQUAL ) + { + DateTime aDateTime; + if( INetRFC822Message::ParseDateField( rKV.GetValue(), aDateTime ) ) + { + aDateTime.ConvertToLocalTime(); + pDoc->GetMedium()->SetExpired_Impl( aDateTime ); + } + else + { +// DBG_ERROR( "Schlechtes ::com::sun::star::util::DateTime fuer Expired" ); + pDoc->GetMedium()->SetExpired_Impl( Date( 1, 1, 1970 ) ); + } + } + else if( rKV.GetKey().CompareIgnoreCaseToAscii( "content-type" ) == COMPARE_EQUAL ) + { + ::rtl::OString sContent = ::rtl::OUStringToOString( aValue, RTL_TEXTENCODING_ASCII_US ); + ByteString sType, sSubType; + INetContentTypeParameterList aParameters; + + if( INetContentTypes::parse( sContent, sType, sSubType, &aParameters ) ) + { + const INetContentTypeParameter * pCharset = aParameters.find("charset"); + if (pCharset != 0) + pDoc->GetMedium()->SetCharset( pCharset->m_sValue ); + } + } +} + +void SfxHeaderAttributes_Impl::Append( const SvKeyValue& rKV ) +{ + xIter->Append( rKV ); + if( bAlert ) SetAttribute( rKV ); +} + +SvKeyValueIterator* SfxObjectShell::GetHeaderAttributes() +{ + if( !pImp->xHeaderAttributes.Is() ) + { + DBG_ASSERT( pMedium, "Kein Medium" ); + pImp->xHeaderAttributes = new SfxHeaderAttributes_Impl( this ); + } + return ( SvKeyValueIterator*) &pImp->xHeaderAttributes; +} + +void SfxObjectShell::ClearHeaderAttributesForSourceViewHack() +{ + ((SfxHeaderAttributes_Impl*)GetHeaderAttributes()) + ->ClearForSourceView(); +} + + +void SfxObjectShell::SetHeaderAttributesForSourceViewHack() +{ + ((SfxHeaderAttributes_Impl*)GetHeaderAttributes()) + ->SetAttributes(); +} + +sal_Bool SfxObjectShell::IsPreview() const +{ + if ( !pMedium ) + return sal_False; + + sal_Bool bPreview = sal_False; + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pFlags, SfxStringItem, SID_OPTIONS, sal_False); + if ( pFlags ) + { + // Werte auf einzelne Items verteilen + String aFileFlags = pFlags->GetValue(); + aFileFlags.ToUpperAscii(); + if ( STRING_NOTFOUND != aFileFlags.Search( 'B' ) ) + bPreview = sal_True; + } + + if ( !bPreview ) + { + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pItem, SfxBoolItem, SID_PREVIEW, sal_False); + if ( pItem ) + bPreview = pItem->GetValue(); + } + + return bPreview; +} + +sal_Bool SfxObjectShell::IsSecure() +{ + // Wenn globale Warnung an ist, nach Secure-Referer-Liste gehen + String aReferer = GetMedium()->GetName(); + if ( !aReferer.Len() ) + { + // bei neuen Dokumenten das Template als Referer nehmen + ::rtl::OUString aTempl( getDocProperties()->getTemplateURL() ); + if ( aTempl.getLength() ) + aReferer = INetURLObject( aTempl ).GetMainURL( INetURLObject::NO_DECODE ); + } + + INetURLObject aURL( "macro:" ); + if ( !aReferer.Len() ) + // empty new or embedded document + return sal_True; + + SvtSecurityOptions aOpt; + + if( aOpt.GetBasicMode() == eALWAYS_EXECUTE ) + return sal_True; + + if( aOpt.GetBasicMode() == eNEVER_EXECUTE ) + return sal_False; + + if ( aOpt.IsSecureURL( aURL.GetMainURL( INetURLObject::NO_DECODE ), aReferer ) ) + //if ( SvtSecurityOptions().IsSecureURL( aURL.GetMainURL( INetURLObject::NO_DECODE ), aReferer ) ) + { + if ( GetMedium()->GetContent().is() ) + { + Any aAny( ::utl::UCBContentHelper::GetProperty( aURL.GetMainURL( INetURLObject::NO_DECODE ), String( RTL_CONSTASCII_USTRINGPARAM("IsProtected")) ) ); + sal_Bool bIsProtected = FALSE; + if ( ( aAny >>= bIsProtected ) && bIsProtected ) + return sal_False; + else + return sal_True; + } + else + return sal_True; + } + else + return sal_False; +} + +void SfxObjectShell::SetWaitCursor( BOOL bSet ) const +{ + for( SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this ); pFrame; pFrame = SfxViewFrame::GetNext( *pFrame, this ) ) + { + if ( bSet ) + pFrame->GetFrame().GetWindow().EnterWait(); + else + pFrame->GetFrame().GetWindow().LeaveWait(); + } +} + +String SfxObjectShell::GetAPIName() const +{ + INetURLObject aURL( IsDocShared() ? GetSharedFileURL() : ::rtl::OUString( GetMedium()->GetName() ) ); + String aName( aURL.GetBase() ); + if( !aName.Len() ) + aName = aURL.GetURLNoPass(); + if ( !aName.Len() ) + aName = GetTitle( SFX_TITLE_DETECT ); + return aName; +} + +void SfxObjectShell::Invalidate( USHORT nId ) +{ + for( SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this ); pFrame; pFrame = SfxViewFrame::GetNext( *pFrame, this ) ) + Invalidate_Impl( pFrame->GetBindings(), nId ); +} + +bool SfxObjectShell::AdjustMacroMode( const String& /*rScriptType*/, bool bSuppressUI ) +{ + uno::Reference< task::XInteractionHandler > xInteraction; + if ( pMedium && !bSuppressUI ) + xInteraction = pMedium->GetInteractionHandler(); + + CheckForBrokenDocSignatures_Impl( xInteraction ); + + CheckEncryption_Impl( xInteraction ); + + return pImp->aMacroMode.adjustMacroMode( xInteraction ); +} + +Window* SfxObjectShell::GetDialogParent( SfxMedium* pLoadingMedium ) +{ + Window* pWindow = 0; + SfxItemSet* pSet = pLoadingMedium ? pLoadingMedium->GetItemSet() : GetMedium()->GetItemSet(); + SFX_ITEMSET_ARG( pSet, pUnoItem, SfxUnoFrameItem, SID_FILLFRAME, FALSE ); + if ( pUnoItem ) + { + uno::Reference < frame::XFrame > xFrame( pUnoItem->GetFrame() ); + pWindow = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() ); + } + + if ( !pWindow ) + { + SfxFrame* pFrame = 0; + SFX_ITEMSET_ARG( pSet, pFrameItem, SfxFrameItem, SID_DOCFRAME, FALSE ); + if( pFrameItem && pFrameItem->GetFrame() ) + // get target frame from ItemSet + pFrame = pFrameItem->GetFrame(); + else + { + // try the current frame + SfxViewFrame* pView = SfxViewFrame::Current(); + if ( !pView || pView->GetObjectShell() != this ) + // get any visible frame + pView = SfxViewFrame::GetFirst(this); + if ( pView ) + pFrame = &pView->GetFrame(); + } + + if ( pFrame ) + // get topmost window + pWindow = VCLUnoHelper::GetWindow( pFrame->GetFrameInterface()->getContainerWindow() ); + } + + if ( pWindow ) + { + // this frame may be invisible, show it if it is allowed + SFX_ITEMSET_ARG( pSet, pHiddenItem, SfxBoolItem, SID_HIDDEN, sal_False ); + if ( !pHiddenItem || !pHiddenItem->GetValue() ) + { + pWindow->Show(); + pWindow->ToTop(); + } + } + + return pWindow; +} + +String SfxObjectShell::UpdateTitle( SfxMedium* pMed, USHORT nDocViewNumber ) +{ + // Titel des Fensters + String aTitle; + if ( pMed ) + { + INetURLObject aTmp( pMed->GetName() ); + aTitle = aTmp.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + } + else + { + pMed = GetMedium(); + aTitle = GetTitle(SFX_TITLE_CAPTION); + String aName(aTitle); + if ( nDocViewNumber ) + { + aName += ':'; + aName += String::CreateFromInt32( nDocViewNumber ); + } + } + + if ( pMed ) + { + SFX_ITEMSET_ARG( pMed->GetItemSet(), pRepairedDocItem, SfxBoolItem, SID_REPAIRPACKAGE, sal_False ); + if ( pRepairedDocItem && pRepairedDocItem->GetValue() ) + aTitle += String( SfxResId(STR_REPAIREDDOCUMENT) ); + } + + if ( IsReadOnlyUI() || (pMed && pMed->IsReadOnly()) ) + aTitle += String( SfxResId(STR_READONLY) ); + else if ( IsDocShared() ) + aTitle += String( SfxResId(STR_SHARED) ); + + return aTitle; +} + +void SfxObjectShell::SetCreateMode_Impl( SfxObjectCreateMode nMode ) +{ + eCreateMode = nMode; +} + +BOOL SfxObjectShell::IsInPlaceActive() +{ + if ( eCreateMode != SFX_CREATE_MODE_EMBEDDED ) + return FALSE; + + SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this ); + return pFrame && pFrame->GetFrame().IsInPlace(); +} + +BOOL SfxObjectShell::IsUIActive() +{ + if ( eCreateMode != SFX_CREATE_MODE_EMBEDDED ) + return FALSE; + + SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this ); + return pFrame && pFrame->GetFrame().IsInPlace() && pFrame->GetFrame().GetWorkWindow_Impl()->IsVisible_Impl(); +} + +void SfxObjectShell::UIActivate( BOOL ) +{ +} + +void SfxObjectShell::InPlaceActivate( BOOL ) +{ +} + +sal_Bool SfxObjectShell::UseInteractionToHandleError( + const uno::Reference< task::XInteractionHandler >& xHandler, + sal_uInt32 nError ) +{ + sal_Bool bResult = sal_False; + + if ( xHandler.is() ) + { + try + { + uno::Any aInteraction; + uno::Sequence< uno::Reference< task::XInteractionContinuation > > lContinuations(2); + ::framework::ContinuationAbort* pAbort = new ::framework::ContinuationAbort(); + ::framework::ContinuationApprove* pApprove = new ::framework::ContinuationApprove(); + lContinuations[0] = uno::Reference< task::XInteractionContinuation >( + static_cast< task::XInteractionContinuation* >( pAbort ), uno::UNO_QUERY ); + lContinuations[1] = uno::Reference< task::XInteractionContinuation >( + static_cast< task::XInteractionContinuation* >( pApprove ), uno::UNO_QUERY ); + + task::ErrorCodeRequest aErrorCode; + aErrorCode.ErrCode = nError; + aInteraction <<= aErrorCode; + + ::framework::InteractionRequest* pRequest = new ::framework::InteractionRequest(aInteraction,lContinuations); + uno::Reference< task::XInteractionRequest > xRequest( + static_cast< task::XInteractionRequest* >( pRequest ), + uno::UNO_QUERY); + + xHandler->handle(xRequest); + bResult = pAbort->isSelected(); + } + catch( uno::Exception& ) + {} + } + + return bResult; +} + +sal_Bool SfxObjectShell_Impl::NeedsOfficeUpdateDialog() +{ + // if the configuration is not available for any reason, the default behavior is to show the message + sal_Bool bResult = sal_True; + + try + { + uno::Reference< lang::XMultiServiceFactory > xServiceManager( ::comphelper::getProcessServiceFactory(), uno::UNO_SET_THROW ); + uno::Reference< uno::XInterface > xCommonConfig( + ::comphelper::ConfigurationHelper::openConfig( + xServiceManager, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common" ) ), + ::comphelper::ConfigurationHelper::E_STANDARD ), + uno::UNO_SET_THROW ); + + ::comphelper::ConfigurationHelper::readRelativeKey( + xCommonConfig, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Load/" ) ), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ShowOfficeUpdateDialog" ) ) ) >>= bResult; + } + catch( uno::Exception& ) + { + } + + return bResult; +} + +sal_Int16 SfxObjectShell_Impl::getCurrentMacroExecMode() const +{ + sal_Int16 nImposedExecMode( MacroExecMode::NEVER_EXECUTE ); + + const SfxMedium* pMedium( rDocShell.GetMedium() ); + OSL_PRECOND( pMedium, "SfxObjectShell_Impl::getCurrentMacroExecMode: no medium!" ); + if ( pMedium ) + { + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pMacroModeItem, SfxUInt16Item, SID_MACROEXECMODE, sal_False); + if ( pMacroModeItem ) + nImposedExecMode = pMacroModeItem->GetValue(); + } + return nImposedExecMode; +} + +sal_Bool SfxObjectShell_Impl::setCurrentMacroExecMode( sal_uInt16 nMacroMode ) +{ + const SfxMedium* pMedium( rDocShell.GetMedium() ); + OSL_PRECOND( pMedium, "SfxObjectShell_Impl::getCurrentMacroExecMode: no medium!" ); + if ( pMedium ) + { + pMedium->GetItemSet()->Put( SfxUInt16Item( SID_MACROEXECMODE, nMacroMode ) ); + return sal_True; + } + + return sal_False; +} + +::rtl::OUString SfxObjectShell_Impl::getDocumentLocation() const +{ + ::rtl::OUString sLocation; + + const SfxMedium* pMedium( rDocShell.GetMedium() ); + OSL_PRECOND( pMedium, "SfxObjectShell_Impl::getDocumentLocation: no medium!" ); + if ( pMedium ) + { + sLocation = pMedium->GetName(); + if ( !sLocation.getLength() ) + { + // for documents made from a template: get the name of the template + sLocation = rDocShell.getDocProperties()->getTemplateURL(); + } + } + return sLocation; +} + +uno::Reference< embed::XStorage > SfxObjectShell_Impl::getZipStorageToSign() +{ + Reference < embed::XStorage > xStore; + + SfxMedium* pMedium( rDocShell.GetMedium() ); + OSL_PRECOND( pMedium, "SfxObjectShell_Impl::getLastCommitDocumentStorage: no medium!" ); + if ( pMedium ) + xStore = pMedium->GetZipStorageToSign_Impl(); + + return xStore; +} + +sal_Bool SfxObjectShell_Impl::documentStorageHasMacros() const +{ + return ::sfx2::DocumentMacroMode::storageHasMacros( m_xDocStorage ); +} + +Reference< XEmbeddedScripts > SfxObjectShell_Impl::getEmbeddedDocumentScripts() const +{ + return Reference< XEmbeddedScripts >( rDocShell.GetModel(), UNO_QUERY ); +} + +sal_Int16 SfxObjectShell_Impl::getScriptingSignatureState() +{ + sal_Int16 nSignatureState( rDocShell.GetScriptingSignatureState() ); + + if ( nSignatureState != SIGNATURESTATE_NOSIGNATURES && m_bMacroSignBroken ) + { + // if there is a macro signature it must be handled as broken + nSignatureState = SIGNATURESTATE_SIGNATURES_BROKEN; + } + + return nSignatureState; +} + +sal_Bool SfxObjectShell_Impl::hasTrustedScriptingSignature( sal_Bool bAllowUIToAddAuthor ) +{ + sal_Bool bResult = sal_False; + + try + { + ::rtl::OUString aVersion; + try + { + uno::Reference < beans::XPropertySet > xPropSet( rDocShell.GetStorage(), uno::UNO_QUERY_THROW ); + xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ) ) >>= aVersion; + } + catch( uno::Exception& ) + { + } + uno::Sequence< uno::Any > aArgs( 1 ); + aArgs[0] <<= aVersion; + + uno::Reference< security::XDocumentDigitalSignatures > xSigner( comphelper::getProcessServiceFactory()->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.security.DocumentDigitalSignatures" ) ), aArgs ), uno::UNO_QUERY_THROW ); + + if ( nScriptingSignatureState == SIGNATURESTATE_UNKNOWN + || nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_OK + || nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED ) + { + uno::Sequence< security::DocumentSignatureInformation > aInfo = rDocShell.ImplAnalyzeSignature( sal_True, xSigner ); + + if ( aInfo.getLength() ) + { + if ( nScriptingSignatureState == SIGNATURESTATE_UNKNOWN ) + nScriptingSignatureState = rDocShell.ImplCheckSignaturesInformation( aInfo ); + + if ( nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_OK + || nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED ) + { + for ( sal_Int32 nInd = 0; !bResult && nInd < aInfo.getLength(); nInd++ ) + { + bResult = xSigner->isAuthorTrusted( aInfo[nInd].Signer ); + } + + if ( !bResult && bAllowUIToAddAuthor ) + { + uno::Reference< task::XInteractionHandler > xInteraction; + if ( rDocShell.GetMedium() ) + xInteraction = rDocShell.GetMedium()->GetInteractionHandler(); + + if ( xInteraction.is() ) + { + task::DocumentMacroConfirmationRequest aRequest; + aRequest.DocumentURL = getDocumentLocation(); + aRequest.DocumentStorage = rDocShell.GetMedium()->GetZipStorageToSign_Impl(); + aRequest.DocumentSignatureInformation = aInfo; + aRequest.DocumentVersion = aVersion; + aRequest.Classification = task::InteractionClassification_QUERY; + bResult = SfxMedium::CallApproveHandler( xInteraction, uno::makeAny( aRequest ), sal_True ); + } + } + } + } + } + } + catch( uno::Exception& ) + {} + + return bResult; +} + +void SfxObjectShell_Impl::showBrokenSignatureWarning( const uno::Reference< task::XInteractionHandler >& _rxInteraction ) const +{ + if ( !bSignatureErrorIsShown ) + { + SfxObjectShell::UseInteractionToHandleError( _rxInteraction, ERRCODE_SFX_BROKENSIGNATURE ); + const_cast< SfxObjectShell_Impl* >( this )->bSignatureErrorIsShown = sal_True; + } +} + +void SfxObjectShell::AddLog( const ::rtl::OUString& aMessage ) +{ + if ( !pImp->m_xLogRing.is() ) + { + try + { + ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); + if ( aContext.is() ) + pImp->m_xLogRing.set( aContext.getSingleton( "com.sun.star.logging.DocumentIOLogRing" ), UNO_QUERY_THROW ); + } + catch( uno::Exception& ) + {} + } + + if ( pImp->m_xLogRing.is() ) + pImp->m_xLogRing->logString( aMessage ); +} + +namespace { + +void WriteStringInStream( const uno::Reference< io::XOutputStream >& xOutStream, const ::rtl::OUString& aString ) +{ + if ( xOutStream.is() ) + { + ::rtl::OString aStrLog = ::rtl::OUStringToOString( aString, RTL_TEXTENCODING_UTF8 ); + uno::Sequence< sal_Int8 > aLogData( (const sal_Int8*)aStrLog.getStr(), aStrLog.getLength() ); + xOutStream->writeBytes( aLogData ); + + aLogData.realloc( 1 ); + aLogData[0] = '\n'; + xOutStream->writeBytes( aLogData ); + } +} + +} + +void SfxObjectShell::StoreLog() +{ + if ( !pImp->m_xLogRing.is() ) + { + try + { + ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); + if ( aContext.is() ) + pImp->m_xLogRing.set( aContext.getSingleton( "com.sun.star.logging.DocumentIOLogRing" ), UNO_QUERY_THROW ); + } + catch( uno::Exception& ) + {} + } + + if ( pImp->m_xLogRing.is() ) + { +#ifdef WNT + ::rtl::OUString aFileURL = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "${$BRAND_BASE_DIR/program/bootstrap.ini:UserInstallation}" ) ); +#else + ::rtl::OUString aFileURL = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "${$BRAND_BASE_DIR/program/bootstraprc:UserInstallation}" ) ); +#endif + + ::rtl::Bootstrap::expandMacros( aFileURL ); + +#ifdef WNT + ::rtl::OUString aBuildID = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "${$BRAND_BASE_DIR/program/setup.ini:buildid}" ) ); +#else + ::rtl::OUString aBuildID = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "${$BRAND_BASE_DIR/program/setuprc:buildid}" ) ); +#endif + + ::rtl::Bootstrap::expandMacros( aBuildID ); + + if ( aFileURL.getLength() ) + { + aFileURL += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/user/temp/document_io_logring.txt" ) ); + try + { + uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory(), uno::UNO_SET_THROW ); + uno::Reference< ucb::XSimpleFileAccess > xSimpleFileAccess( xFactory->createInstance( DEFINE_CONST_UNICODE( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY_THROW ); + uno::Reference< io::XStream > xStream( xSimpleFileAccess->openFileReadWrite( aFileURL ), uno::UNO_SET_THROW ); + uno::Reference< io::XOutputStream > xOutStream( xStream->getOutputStream(), uno::UNO_SET_THROW ); + uno::Reference< io::XTruncate > xTruncate( xOutStream, uno::UNO_QUERY_THROW ); + xTruncate->truncate(); + + if ( aBuildID.getLength() ) + WriteStringInStream( xOutStream, aBuildID ); + + uno::Sequence< ::rtl::OUString > aLogSeq = pImp->m_xLogRing->getCollectedLog(); + for ( sal_Int32 nInd = 0; nInd < aLogSeq.getLength(); nInd++ ) + WriteStringInStream( xOutStream, aLogSeq[nInd] ); + } + catch( uno::Exception& ) + {} + } + } +} + diff --git a/sfx2/source/doc/objserv.cxx b/sfx2/source/doc/objserv.cxx new file mode 100644 index 000000000000..bb0e6939ead8 --- /dev/null +++ b/sfx2/source/doc/objserv.cxx @@ -0,0 +1,1514 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include <sot/storage.hxx> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> +#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> +#include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp> +#include <com/sun/star/ui/dialogs/XControlAccess.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/task/XStatusIndicator.hpp> +#include <com/sun/star/task/XStatusIndicatorFactory.hpp> +#include <com/sun/star/frame/XDocumentTemplates.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/security/CertificateValidity.hpp> + +#include <com/sun/star/security/DocumentSignatureInformation.hpp> +#include <com/sun/star/security/XDocumentDigitalSignatures.hpp> +#include <tools/urlobj.hxx> +#include <svl/whiter.hxx> +#include <vcl/msgbox.hxx> +#include <svl/intitem.hxx> +#include <svl/eitem.hxx> +#include <vcl/wrkwin.hxx> +#include <svtools/sfxecode.hxx> +#include <svtools/ehdl.hxx> + +#include <comphelper/string.hxx> +#include <basic/sbx.hxx> +#include <unotools/pathoptions.hxx> +#include <unotools/useroptions.hxx> +#include <svtools/asynclink.hxx> +#include <unotools/saveopt.hxx> +#include <comphelper/documentconstants.hxx> + +#include <sfx2/app.hxx> +#include <sfx2/signaturestate.hxx> +#include "sfxresid.hxx" +#include <sfx2/event.hxx> +#include <sfx2/request.hxx> +#include <sfx2/printer.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/doctdlg.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/dinfdlg.hxx> +#include <sfx2/objitem.hxx> +#include <sfx2/objsh.hxx> +#include "objshimp.hxx" +#include "sfxtypes.hxx" +//#include "interno.hxx" +#include <sfx2/module.hxx> +#include <sfx2/viewfrm.hxx> +#include "versdlg.hxx" +#include "doc.hrc" +#include <sfx2/docfac.hxx> +#include <sfx2/fcontnr.hxx> +#include <sfx2/filedlghelper.hxx> +#include "sfxhelp.hxx" +#include <sfx2/msgpool.hxx> +#include <sfx2/objface.hxx> + +#include "../appl/app.hrc" +#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/util/XCloneable.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> + +#include "helpid.hrc" + +#include "guisaveas.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::task; + +//==================================================================== + +class SfxSaveAsContext_Impl +{ + String& _rNewNameVar; + String _aNewName; + +public: + SfxSaveAsContext_Impl( String &rNewNameVar, + const String &rNewName ) + : _rNewNameVar( rNewNameVar ), + _aNewName( rNewName ) + { rNewNameVar = rNewName; } + ~SfxSaveAsContext_Impl() + { _rNewNameVar.Erase(); } +}; + +//==================================================================== + +#define SfxObjectShell +#include "sfxslots.hxx" + +//========================================================================= + + + +SFX_IMPL_INTERFACE(SfxObjectShell,SfxShell,SfxResId(0)) +{ +} + +//========================================================================= + +class SfxClosePreventer_Impl : public ::cppu::WeakImplHelper1< ::com::sun::star::util::XCloseListener > +{ + sal_Bool m_bGotOwnership; + sal_Bool m_bPreventClose; + +public: + SfxClosePreventer_Impl(); + + sal_Bool HasOwnership() { return m_bGotOwnership; } + + void SetPreventClose( sal_Bool bPrevent ) { m_bPreventClose = bPrevent; } + + virtual void SAL_CALL queryClosing( const lang::EventObject& aEvent, sal_Bool bDeliverOwnership ) + throw ( uno::RuntimeException, util::CloseVetoException ); + + virtual void SAL_CALL notifyClosing( const lang::EventObject& aEvent ) throw ( uno::RuntimeException ) ; + + virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) throw ( uno::RuntimeException ) ; + +} ; + +SfxClosePreventer_Impl::SfxClosePreventer_Impl() +: m_bGotOwnership( sal_False ) +, m_bPreventClose( sal_True ) +{ +} + +void SAL_CALL SfxClosePreventer_Impl::queryClosing( const lang::EventObject&, sal_Bool bDeliverOwnership ) + throw ( uno::RuntimeException, util::CloseVetoException ) +{ + if ( m_bPreventClose ) + { + if ( !m_bGotOwnership ) + m_bGotOwnership = bDeliverOwnership; + + throw util::CloseVetoException(); + } +} + +void SAL_CALL SfxClosePreventer_Impl::notifyClosing( const lang::EventObject& ) throw ( uno::RuntimeException ) +{} + +void SAL_CALL SfxClosePreventer_Impl::disposing( const lang::EventObject& ) throw ( uno::RuntimeException ) +{} + +//========================================================================= +class SfxInstanceCloseGuard_Impl +{ + SfxClosePreventer_Impl* m_pPreventer; + uno::Reference< util::XCloseListener > m_xPreventer; + uno::Reference< util::XCloseable > m_xCloseable; + +public: + SfxInstanceCloseGuard_Impl() + : m_pPreventer( NULL ) + {} + + ~SfxInstanceCloseGuard_Impl(); + + sal_Bool Init_Impl( const uno::Reference< util::XCloseable >& xCloseable ); +}; + +sal_Bool SfxInstanceCloseGuard_Impl::Init_Impl( const uno::Reference< util::XCloseable >& xCloseable ) +{ + sal_Bool bResult = sal_False; + + // do not allow reinit after the successful init + if ( xCloseable.is() && !m_xCloseable.is() ) + { + try + { + m_pPreventer = new SfxClosePreventer_Impl(); + m_xPreventer = uno::Reference< util::XCloseListener >( m_pPreventer ); + xCloseable->addCloseListener( m_xPreventer ); + m_xCloseable = xCloseable; + bResult = sal_True; + } + catch( uno::Exception& ) + { + OSL_ENSURE( sal_False, "Could not register close listener!\n" ); + } + } + + return bResult; +} + +SfxInstanceCloseGuard_Impl::~SfxInstanceCloseGuard_Impl() +{ + if ( m_xCloseable.is() && m_xPreventer.is() ) + { + try + { + m_xCloseable->removeCloseListener( m_xPreventer ); + } + catch( uno::Exception& ) + { + } + + try + { + if ( m_pPreventer ) + { + m_pPreventer->SetPreventClose( sal_False ); + + if ( m_pPreventer->HasOwnership() ) + m_xCloseable->close( sal_True ); // TODO: do it asynchronously + } + } + catch( uno::Exception& ) + { + } + } +} + +//========================================================================= + +void SfxObjectShell::PrintExec_Impl(SfxRequest &rReq) +{ + SfxViewFrame *pFrame = SfxViewFrame::GetFirst(this); + if ( pFrame ) + { + rReq.SetSlot( SID_PRINTDOC ); + pFrame->GetViewShell()->ExecuteSlot(rReq); + } +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::PrintState_Impl(SfxItemSet &rSet) +{ + bool bPrinting = false; + SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this ); + if ( pFrame ) + { + SfxPrinter *pPrinter = pFrame->GetViewShell()->GetPrinter(); + bPrinting = pPrinter && pPrinter->IsPrinting(); + } + rSet.Put( SfxBoolItem( SID_PRINTOUT, bPrinting ) ); +} + +//-------------------------------------------------------------------- + +sal_Bool SfxObjectShell::APISaveAs_Impl +( + const String& aFileName, + SfxItemSet* aParams +) +{ + BOOL bOk = sal_False; + + {DBG_CHKTHIS(SfxObjectShell, 0);} + + if ( GetMedium() ) + { + String aFilterName; + SFX_ITEMSET_ARG( aParams, pFilterNameItem, SfxStringItem, SID_FILTER_NAME, sal_False ); + if( pFilterNameItem ) + { + aFilterName = pFilterNameItem->GetValue(); + } + else + { + SFX_ITEMSET_ARG( aParams, pContentTypeItem, SfxStringItem, SID_CONTENTTYPE, sal_False ); + if ( pContentTypeItem ) + { + const SfxFilter* pFilter = SfxFilterMatcher( String::CreateFromAscii(GetFactory().GetShortName()) ).GetFilter4Mime( pContentTypeItem->GetValue(), SFX_FILTER_EXPORT ); + if ( pFilter ) + aFilterName = pFilter->GetName(); + } + } + + // in case no filter defined use default one + if( !aFilterName.Len() ) + { + const SfxFilter* pFilt = SfxFilter::GetDefaultFilterFromFactory(GetFactory().GetFactoryName()); + + DBG_ASSERT( pFilt, "No default filter!\n" ); + if( pFilt ) + aFilterName = pFilt->GetFilterName(); + + aParams->Put(SfxStringItem( SID_FILTER_NAME, aFilterName)); + } + + + { + SfxObjectShellRef xLock( this ); // ??? + + // use the title that is provided in the media descriptor + SFX_ITEMSET_ARG( aParams, pDocTitleItem, SfxStringItem, SID_DOCINFO_TITLE, sal_False ); + if ( pDocTitleItem ) + getDocProperties()->setTitle( pDocTitleItem->GetValue() ); + + bOk = CommonSaveAs_Impl( INetURLObject(aFileName), aFilterName, + aParams ); + + } + + // prevent picklist-entry + GetMedium()->SetUpdatePickList( FALSE ); + } + + return bOk; +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq) +{ + {DBG_CHKTHIS(SfxObjectShell, 0);} + + USHORT nId = rReq.GetSlot(); + + if( SID_SIGNATURE == nId || SID_MACRO_SIGNATURE == nId ) + { + if ( QueryHiddenInformation( WhenSigning, NULL ) == RET_YES ) + ( SID_SIGNATURE == nId ) ? SignDocumentContent() : SignScriptingContent(); + return; + } + + if ( !GetMedium() && nId != SID_CLOSEDOC ) + { + rReq.Ignore(); + return; + } + + // this guard is created here to have it destruction at the end of the method + SfxInstanceCloseGuard_Impl aModelGuard; + + sal_Bool bIsPDFExport = sal_False; + switch(nId) + { + case SID_VERSION: + { + SfxViewFrame* pFrame = GetFrame(); + if ( !pFrame ) + pFrame = SfxViewFrame::GetFirst( this ); + if ( !pFrame ) + return; + + if ( pFrame->GetFrame().GetParentFrame() ) + { + pFrame->GetTopViewFrame()->GetObjectShell()->ExecuteSlot( rReq ); + return; + } + + if ( !IsOwnStorageFormat_Impl( *GetMedium() ) ) + return; + + SfxVersionDialog *pDlg = new SfxVersionDialog( pFrame, IsSaveVersionOnClose() ); + pDlg->Execute(); + SetSaveVersionOnClose( pDlg->IsSaveVersionOnClose() ); + delete pDlg; + rReq.Done(); + return; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + case SID_DOCINFO: + { + SFX_REQUEST_ARG(rReq, pDocInfItem, SfxDocumentInfoItem, SID_DOCINFO, FALSE); + if ( pDocInfItem ) + { + // parameter, e.g. from replayed macro + pDocInfItem->UpdateDocumentInfo(getDocProperties(), true); + SetUseUserData( pDocInfItem->IsUseUserData() ); + } + else + { + // no argument containing DocInfo; check optional arguments + BOOL bReadOnly = IsReadOnly(); + SFX_REQUEST_ARG(rReq, pROItem, SfxBoolItem, SID_DOC_READONLY, FALSE); + if ( pROItem ) + // override readonly attribute of document + // e.g. if a readonly document is saved elsewhere and user asks for editing DocInfo before + bReadOnly = pROItem->GetValue(); + + // collect data for dialog + String aURL, aTitle; + if ( HasName() ) + { + aURL = GetMedium()->GetName(); + aTitle = GetTitle(); + } + else + { + aURL = DEFINE_CONST_UNICODE( "private:factory/" ); + aURL += String::CreateFromAscii( GetFactory().GetShortName() ); + + aTitle = GetTitle(); + } + + SfxDocumentInfoItem aDocInfoItem( aURL, getDocProperties(), + IsUseUserData() ); + if ( !GetSlotState( SID_DOCTEMPLATE ) ) + // templates not supported + aDocInfoItem.SetTemplate(FALSE); + + SfxItemSet aSet(GetPool(), SID_DOCINFO, SID_DOCINFO, SID_DOC_READONLY, SID_DOC_READONLY, + SID_EXPLORER_PROPS_START, SID_EXPLORER_PROPS_START, SID_BASEURL, SID_BASEURL, + 0L ); + aSet.Put( aDocInfoItem ); + aSet.Put( SfxBoolItem( SID_DOC_READONLY, bReadOnly ) ); + aSet.Put( SfxStringItem( SID_EXPLORER_PROPS_START, aTitle ) ); + aSet.Put( SfxStringItem( SID_BASEURL, GetMedium()->GetBaseURL() ) ); + + // creating dialog is done via virtual method; application will add its own statistics page + SfxDocumentInfoDialog *pDlg = CreateDocumentInfoDialog(0, aSet); + if ( RET_OK == pDlg->Execute() ) + { + SFX_ITEMSET_ARG( pDlg->GetOutputItemSet(), pDocInfoItem, SfxDocumentInfoItem, SID_DOCINFO, FALSE); + if ( pDocInfoItem ) + { + // user has done some changes to DocumentInfo + pDocInfoItem->UpdateDocumentInfo(getDocProperties()); + SetUseUserData( ((const SfxDocumentInfoItem *)pDocInfoItem)->IsUseUserData() ); + + // add data from dialog for possible recording purposes + rReq.AppendItem( SfxDocumentInfoItem( GetTitle(), + getDocProperties(), IsUseUserData() ) ); + } + + rReq.Done(); + } + else + // nothing done; no recording + rReq.Ignore(); + + delete pDlg; + } + + return; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + case SID_EXPORTDOCASPDF: + case SID_DIRECTEXPORTDOCASPDF: + bIsPDFExport = sal_True; + case SID_EXPORTDOC: + case SID_SAVEASDOC: + case SID_SAVEDOC: + { + // derived class may decide to abort this + if( !QuerySlotExecutable( nId ) ) + { + rReq.SetReturnValue( SfxBoolItem( 0, FALSE ) ); + return; + } + + //!! detaillierte Auswertung eines Fehlercodes + SfxObjectShellRef xLock( this ); + + // the model can not be closed till the end of this method + // if somebody tries to close it during this time the model will be closed + // at the end of the method + aModelGuard.Init_Impl( uno::Reference< util::XCloseable >( GetModel(), uno::UNO_QUERY ) ); + + sal_Bool bDialogUsed = sal_False; + sal_uInt32 nErrorCode = ERRCODE_NONE; + + // by default versions should be preserved always except in case of an explicit + // SaveAs via GUI, so the flag must be set accordingly + pImp->bPreserveVersions = (nId == SID_SAVEDOC); + try + { + SfxErrorContext aEc( ERRCTX_SFX_SAVEASDOC, GetTitle() ); // ??? + + if ( nId == SID_SAVEASDOC ) + { + // in case of plugin mode the SaveAs operation means SaveTo + SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pViewOnlyItem, SfxBoolItem, SID_VIEWONLY, FALSE ); + if ( pViewOnlyItem && pViewOnlyItem->GetValue() ) + rReq.AppendItem( SfxBoolItem( SID_SAVETO, sal_True ) ); + } + + // TODO/LATER: do the following GUI related actions in standalown method + // ======================================================================================================== + // Introduce a status indicator for GUI operation + SFX_REQUEST_ARG( rReq, pStatusIndicatorItem, SfxUnoAnyItem, SID_PROGRESS_STATUSBAR_CONTROL, FALSE ); + if ( !pStatusIndicatorItem ) + { + // get statusindicator + uno::Reference< task::XStatusIndicator > xStatusIndicator; + SfxViewFrame *pFrame = GetFrame(); + if ( pFrame ) + { + uno::Reference< task::XStatusIndicatorFactory > xStatFactory( + pFrame->GetFrame().GetFrameInterface(), + uno::UNO_QUERY ); + if( xStatFactory.is() ) + xStatusIndicator = xStatFactory->createStatusIndicator(); + } + + + OSL_ENSURE( xStatusIndicator.is(), "Can not retrieve default status indicator!\n" ); + if ( xStatusIndicator.is() ) + { + SfxUnoAnyItem aStatIndItem( SID_PROGRESS_STATUSBAR_CONTROL, uno::makeAny( xStatusIndicator ) ); + + if ( nId == SID_SAVEDOC ) + { + // in case of saving it is not possible to transport the parameters from here + // but it is not clear here whether the saving will be done or saveAs operation + GetMedium()->GetItemSet()->Put( aStatIndItem ); + } + + rReq.AppendItem( aStatIndItem ); + } + } + else if ( nId == SID_SAVEDOC ) + { + // in case of saving it is not possible to transport the parameters from here + // but it is not clear here whether the saving will be done or saveAs operation + GetMedium()->GetItemSet()->Put( *pStatusIndicatorItem ); + } + + // Introduce an interaction handler for GUI operation + SFX_REQUEST_ARG( rReq, pInteractionHandlerItem, SfxUnoAnyItem, SID_INTERACTIONHANDLER, FALSE ); + if ( !pInteractionHandlerItem ) + { + uno::Reference< task::XInteractionHandler > xInteract; + uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory(); + if( xServiceManager.is() ) + { + xInteract = Reference< XInteractionHandler >( + xServiceManager->createInstance( DEFINE_CONST_UNICODE("com.sun.star.task.InteractionHandler") ), + UNO_QUERY ); + } + + OSL_ENSURE( xInteract.is(), "Can not retrieve default status indicator!\n" ); + if ( xInteract.is() ) + { + SfxUnoAnyItem aInteractionItem( SID_INTERACTIONHANDLER, uno::makeAny( xInteract ) ); + if ( nId == SID_SAVEDOC ) + { + // in case of saving it is not possible to transport the parameters from here + // but it is not clear here whether the saving will be done or saveAs operation + GetMedium()->GetItemSet()->Put( aInteractionItem ); + } + + rReq.AppendItem( aInteractionItem ); + } + } + else if ( nId == SID_SAVEDOC ) + { + // in case of saving it is not possible to transport the parameters from here + // but it is not clear here whether the saving will be done or saveAs operation + GetMedium()->GetItemSet()->Put( *pInteractionHandlerItem ); + } + // ======================================================================================================== + + sal_Bool bPreselectPassword = sal_False; + SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pOldPasswordItem, SfxStringItem, SID_PASSWORD, FALSE ); + if ( pOldPasswordItem ) + bPreselectPassword = sal_True; + + uno::Sequence< beans::PropertyValue > aDispatchArgs; + if ( rReq.GetArgs() ) + TransformItems( nId, + *rReq.GetArgs(), + aDispatchArgs, + NULL ); + + const SfxSlot* pSlot = GetModule()->GetSlotPool()->GetSlot( nId ); + if ( !pSlot ) + throw uno::Exception(); + + uno::Reference< lang::XMultiServiceFactory > xEmptyFactory; + SfxStoringHelper aHelper( xEmptyFactory ); + + if ( QueryHiddenInformation( bIsPDFExport ? WhenCreatingPDF : WhenSaving, NULL ) == RET_YES ) + { + bDialogUsed = aHelper.GUIStoreModel( GetModel(), + ::rtl::OUString::createFromAscii( pSlot->GetUnoName() ), + aDispatchArgs, + bPreselectPassword, + GetSharedFileURL(), + GetDocumentSignatureState() ); + } + else + { + // the user has decided not to store the document + throw task::ErrorCodeIOException( ::rtl::OUString(), + uno::Reference< uno::XInterface >(), + ERRCODE_IO_ABORT ); + } + + // merge aDispatchArgs to the request + SfxAllItemSet aResultParams( GetPool() ); + TransformParameters( nId, + aDispatchArgs, + aResultParams, + NULL ); + rReq.SetArgs( aResultParams ); + + SFX_REQUEST_ARG( rReq, pFilterNameItem, SfxStringItem, SID_FILTER_NAME, FALSE ); + ::rtl::OUString aFilterName = pFilterNameItem ? ::rtl::OUString( pFilterNameItem->GetValue() ) + : ::rtl::OUString(); + const SfxFilter* pFilt = GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName ); + + OSL_ENSURE( nId == SID_SAVEDOC || pFilt, "The filter can not be zero since it was used for storing!\n" ); + if ( bDialogUsed && pFilt + && pFilt->IsOwnFormat() + && pFilt->UsesStorage() + && pFilt->GetVersion() >= SOFFICE_FILEFORMAT_60 ) + { + SfxViewFrame* pDocViewFrame = SfxViewFrame::GetFirst( this ); + if ( pDocViewFrame ) + SfxHelp::OpenHelpAgent( &pDocViewFrame->GetFrame(), HID_DID_SAVE_PACKED_XML ); + } + + // the StoreAsURL/StoreToURL method have called this method with false + // so it has to be restored to true here since it is a call from GUI + GetMedium()->SetUpdatePickList( sal_True ); + + // TODO: in future it must be done in followind way + // if document is opened from GUI it is immediatelly appeares in the picklist + // if the document is a new one then it appeares in the picklist immediatelly + // after SaveAs operation triggered from GUI + } + catch( task::ErrorCodeIOException& aErrorEx ) + { + nErrorCode = (sal_uInt32)aErrorEx.ErrCode; + } + catch( Exception& ) + { + nErrorCode = ERRCODE_IO_GENERAL; + } + + // by default versions should be preserved always except in case of an explicit + // SaveAs via GUI, so the flag must be reset to guarantee this + pImp->bPreserveVersions = sal_True; + ULONG lErr=GetErrorCode(); + + if ( !lErr && nErrorCode ) + lErr = nErrorCode; + + if ( lErr && nErrorCode == ERRCODE_NONE ) + { + SFX_REQUEST_ARG( rReq, pWarnItem, SfxBoolItem, SID_FAIL_ON_WARNING, FALSE ); + if ( pWarnItem && pWarnItem->GetValue() ) + nErrorCode = lErr; + } + + // may be nErrorCode should be shown in future + if ( lErr != ERRCODE_IO_ABORT ) + { + SfxErrorContext aEc(ERRCTX_SFX_SAVEASDOC,GetTitle()); + ErrorHandler::HandleError( lErr ); + } + + if ( nId == SID_EXPORTDOCASPDF ) + { + // This function is used by the SendMail function that needs information if a export + // file was written or not. This could be due to cancellation of the export + // or due to an error. So IO abort must be handled like an error! + nErrorCode = ( lErr != ERRCODE_IO_ABORT ) && ( nErrorCode == ERRCODE_NONE ) ? nErrorCode : lErr; + } + + rReq.SetReturnValue( SfxBoolItem(0, nErrorCode == ERRCODE_NONE ) ); + + ResetError(); + + Invalidate(); + break; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + case SID_CLOSEDOC: + { + SfxViewFrame *pFrame = GetFrame(); + if ( pFrame && pFrame->GetFrame().GetParentFrame() ) + { + // Wenn SID_CLOSEDOC "uber Menue etc. ausgef"uhrt wird, das + // aktuelle Dokument aber in einem Frame liegt, soll eigentlich + // das FrameSetDocument geclosed werden + pFrame->GetTopViewFrame()->GetObjectShell()->ExecuteSlot( rReq ); + rReq.Done(); + return; + } + + BOOL bInFrameSet = FALSE; + USHORT nFrames=0; + pFrame = SfxViewFrame::GetFirst( this ); + while ( pFrame ) + { + if ( pFrame->GetFrame().GetParentFrame() ) + { + // Auf dieses Dokument existiert noch eine Sicht, die + // in einem FrameSet liegt; diese darf nat"urlich nicht + // geclosed werden + bInFrameSet = TRUE; + } + else + nFrames++; + + pFrame = SfxViewFrame::GetNext( *pFrame, this ); + } + + if ( bInFrameSet ) + { + // Alle Sichten, die nicht in einem FrameSet liegen, closen + pFrame = SfxViewFrame::GetFirst( this ); + while ( pFrame ) + { + if ( !pFrame->GetFrame().GetParentFrame() ) + pFrame->GetFrame().DoClose(); + pFrame = SfxViewFrame::GetNext( *pFrame, this ); + } + } + + // Parameter auswerten + SFX_REQUEST_ARG(rReq, pSaveItem, SfxBoolItem, SID_CLOSEDOC_SAVE, FALSE); + SFX_REQUEST_ARG(rReq, pNameItem, SfxStringItem, SID_CLOSEDOC_FILENAME, FALSE); + if ( pSaveItem ) + { + if ( pSaveItem->GetValue() ) + { + if ( !pNameItem ) + { + SbxBase::SetError( SbxERR_WRONG_ARGS ); + rReq.Ignore(); + return; + } + SfxAllItemSet aArgs( GetPool() ); + SfxStringItem aTmpItem( SID_FILE_NAME, pNameItem->GetValue() ); + aArgs.Put( aTmpItem, aTmpItem.Which() ); + SfxRequest aSaveAsReq( SID_SAVEASDOC, SFX_CALLMODE_API, aArgs ); + ExecFile_Impl( aSaveAsReq ); + if ( !aSaveAsReq.IsDone() ) + { + rReq.Ignore(); + return; + } + } + else + SetModified(FALSE); + } + + // Benutzer bricht ab? + if ( !PrepareClose( 2 ) ) + { + rReq.SetReturnValue( SfxBoolItem(0, FALSE) ); + rReq.Done(); + return; + } + + SetModified( FALSE ); + ULONG lErr = GetErrorCode(); + ErrorHandler::HandleError(lErr); + + rReq.SetReturnValue( SfxBoolItem(0, TRUE) ); + rReq.Done(); + rReq.ReleaseArgs(); // da der Pool in Close zerst"ort wird + DoClose(); + return; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + case SID_DOCTEMPLATE: + { + // speichern als Dokumentvorlagen + SfxDocumentTemplateDlg *pDlg = 0; + SfxErrorContext aEc(ERRCTX_SFX_DOCTEMPLATE,GetTitle()); + SfxDocumentTemplates *pTemplates = new SfxDocumentTemplates; + + if ( !rReq.GetArgs() ) + { + pDlg = new SfxDocumentTemplateDlg(0, pTemplates); + if ( RET_OK == pDlg->Execute() && pDlg->GetTemplateName().Len()) + { + rReq.AppendItem(SfxStringItem( + SID_TEMPLATE_NAME, pDlg->GetTemplateName())); + rReq.AppendItem(SfxStringItem( + SID_TEMPLATE_REGIONNAME, pDlg->GetRegionName())); + } + else + { + delete pDlg; + rReq.Ignore(); + return; + } + } + + SFX_REQUEST_ARG(rReq, pRegionItem, SfxStringItem, SID_TEMPLATE_REGIONNAME, FALSE); + SFX_REQUEST_ARG(rReq, pNameItem, SfxStringItem, SID_TEMPLATE_NAME, FALSE); + SFX_REQUEST_ARG(rReq, pRegionNrItem, SfxUInt16Item, SID_TEMPLATE_REGION, FALSE); + if ( (!pRegionItem && !pRegionNrItem ) || !pNameItem ) + { + DBG_ASSERT( rReq.IsAPI(), "non-API call without Arguments" ); + SbxBase::SetError( SbxERR_WRONG_ARGS ); + rReq.Ignore(); + return; + } + + ::rtl::OUString aTemplateName = pNameItem->GetValue(); + ::rtl::OUString aTemplateGroup; + if ( pRegionItem ) + aTemplateGroup = pRegionItem->GetValue(); + else + // pRegionNrItem must not be NULL, it was just checked + aTemplateGroup = pTemplates->GetFullRegionName( pRegionNrItem->GetValue() ); + // check Group and Name + delete pTemplates; + + sal_Bool bOk = sal_False; + try + { + uno::Reference< frame::XStorable > xStorable( GetModel(), uno::UNO_QUERY_THROW ); + ::rtl::OUString aService( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.DocumentTemplates" ) ); + uno::Reference< frame::XDocumentTemplates > xTemplates( + comphelper::getProcessServiceFactory()->createInstance( aService ), + uno::UNO_QUERY_THROW ); + + bOk = xTemplates->storeTemplate( aTemplateGroup, aTemplateName, xStorable ); + } + catch( uno::Exception& ) + { + } + + DELETEX(pDlg); + + rReq.SetReturnValue( SfxBoolItem( 0, bOk ) ); + if ( bOk ) + { + // update the Organizer runtime cache from the template component if the cache has already been created + // TODO/LATER: get rid of this cache duplication + SfxDocumentTemplates aTemplates; + aTemplates.ReInitFromComponent(); + } + else + { + ErrorHandler::HandleError( ERRCODE_IO_GENERAL ); + return; + } + + break; + } + } + + // Picklisten-Eintrag verhindern + if ( rReq.IsAPI() ) + GetMedium()->SetUpdatePickList( FALSE ); + else if ( rReq.GetArgs() ) + { + SFX_ITEMSET_GET( *rReq.GetArgs(), pPicklistItem, SfxBoolItem, SID_PICKLIST, FALSE ); + if ( pPicklistItem ) + GetMedium()->SetUpdatePickList( pPicklistItem->GetValue() ); + } + + // Ignore()-Zweige haben schon returnt + rReq.Done(); +} + +//------------------------------------------------------------------------- + +void SfxObjectShell::GetState_Impl(SfxItemSet &rSet) +{ + DBG_CHKTHIS(SfxObjectShell, 0); + SfxWhichIter aIter( rSet ); + + for ( USHORT nWhich = aIter.FirstWhich(); nWhich; nWhich = aIter.NextWhich() ) + { + switch ( nWhich ) + { + case SID_DOCTEMPLATE : + { + if ( !GetFactory().GetTemplateFilter() ) + rSet.DisableItem( nWhich ); + break; + } + + case SID_VERSION: + { + SfxObjectShell *pDoc = this; + SfxViewFrame* pFrame = GetFrame(); + if ( !pFrame ) + pFrame = SfxViewFrame::GetFirst( this ); + if ( pFrame ) + { + if ( pFrame->GetFrame().GetParentFrame() ) + { + pFrame = pFrame->GetTopViewFrame(); + pDoc = pFrame->GetObjectShell(); + } + } + + if ( !pFrame || !pDoc->HasName() || + !IsOwnStorageFormat_Impl( *pDoc->GetMedium() ) ) +//REMOVE || pDoc->GetMedium()->GetStorage()->GetVersion() < SOFFICE_FILEFORMAT_50 ) + rSet.DisableItem( nWhich ); + break; + } + case SID_SAVEDOC: + { + BOOL bMediumRO = IsReadOnlyMedium(); + if ( !bMediumRO && GetMedium() && IsModified() ) + rSet.Put(SfxStringItem( + nWhich, String(SfxResId(STR_SAVEDOC)))); + else + rSet.DisableItem(nWhich); + } + break; + + case SID_DOCINFO: + if ( 0 != ( pImp->eFlags & SFXOBJECTSHELL_NODOCINFO ) ) + rSet.DisableItem( nWhich ); + break; + + case SID_CLOSEDOC: + { + SfxObjectShell *pDoc = this; + SfxViewFrame *pFrame = GetFrame(); + if ( pFrame && pFrame->GetFrame().GetParentFrame() ) + { + // Wenn SID_CLOSEDOC "uber Menue etc. ausgef"uhrt wird, das + // aktuelle Dokument aber in einem Frame liegt, soll eigentlich + // das FrameSetDocument geclosed werden + pDoc = pFrame->GetTopViewFrame()->GetObjectShell(); + } + + if ( pDoc->GetFlags() & SFXOBJECTSHELL_DONTCLOSE ) + rSet.DisableItem(nWhich); + else + rSet.Put(SfxStringItem(nWhich, String(SfxResId(STR_CLOSEDOC)))); + break; + } + + case SID_SAVEASDOC: + { + if( ( pImp->nLoadedFlags & SFX_LOADED_MAINDOCUMENT ) != SFX_LOADED_MAINDOCUMENT ) + { + rSet.DisableItem( nWhich ); + break; + } +/* + const SfxFilter* pCombinedFilters = NULL; + SfxFilterContainer* pFilterContainer = GetFactory().GetFilterContainer(); + + if ( pFilterContainer ) + { + SfxFilterFlags nMust = SFX_FILTER_IMPORT | SFX_FILTER_EXPORT; + SfxFilterFlags nDont = SFX_FILTER_NOTINSTALLED | SFX_FILTER_INTERNAL; + + pCombinedFilters = pFilterContainer->GetAnyFilter( nMust, nDont ); + } +*/ + if ( /*!pCombinedFilters ||*/ !GetMedium() ) + rSet.DisableItem( nWhich ); + else + rSet.Put( SfxStringItem( nWhich, String( SfxResId( STR_SAVEASDOC ) ) ) ); + break; + } + + case SID_EXPORTDOCASPDF: + case SID_DIRECTEXPORTDOCASPDF: + { + /* + + search for filter cant work correctly ... + Because it's not clear, which export filter for which office module + must be searched. On the other side it can be very expensive doing so. + The best solution would be: on installation time we should know if pdf feature + was installed or not!!! (e.g. by writing a bool inside cfg) + + SfxFilterContainer* pFilterContainer = GetFactory().GetFilterContainer(); + if ( pFilterContainer ) + { + String aPDFExtension = String::CreateFromAscii( "pdf" ); + const SfxFilter* pFilter = pFilterContainer->GetFilter4Extension( aPDFExtension, SFX_FILTER_EXPORT ); + if ( pFilter != NULL ) + break; + } + + rSet.DisableItem( nWhich ); + */ + break; + } + + case SID_DOC_MODIFIED: + { + rSet.Put( SfxStringItem( SID_DOC_MODIFIED, IsModified() ? '*' : ' ' ) ); + break; + } + + case SID_MODIFIED: + { + rSet.Put( SfxBoolItem( SID_MODIFIED, IsModified() ) ); + break; + } + + case SID_DOCINFO_TITLE: + { + rSet.Put( SfxStringItem( + SID_DOCINFO_TITLE, getDocProperties()->getTitle() ) ); + break; + } + case SID_FILE_NAME: + { + if( GetMedium() && HasName() ) + rSet.Put( SfxStringItem( + SID_FILE_NAME, GetMedium()->GetName() ) ); + break; + } + case SID_SIGNATURE: + { + rSet.Put( SfxUInt16Item( SID_SIGNATURE, GetDocumentSignatureState() ) ); + break; + } + case SID_MACRO_SIGNATURE: + { + // the slot makes sense only if there is a macro in the document + if ( pImp->documentStorageHasMacros() || pImp->aMacroMode.hasMacroLibrary() ) + rSet.Put( SfxUInt16Item( SID_MACRO_SIGNATURE, GetScriptingSignatureState() ) ); + else + rSet.DisableItem( nWhich ); + break; + } + } + } +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::ExecProps_Impl(SfxRequest &rReq) +{ + switch ( rReq.GetSlot() ) + { + case SID_MODIFIED: + { + SetModified( ( (SfxBoolItem&) rReq.GetArgs()->Get(SID_MODIFIED)).GetValue() ); + rReq.Done(); + break; + } + + case SID_DOCTITLE: + SetTitle( ( (SfxStringItem&) rReq.GetArgs()->Get(SID_DOCTITLE)).GetValue() ); + rReq.Done(); + break; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + case SID_PLAYMACRO: + { + SFX_APP()->PlayMacro_Impl( rReq, GetBasic() ); + break; + } + + case SID_DOCINFO_AUTHOR : + { + ::rtl::OUString aStr = ( (SfxStringItem&)rReq.GetArgs()->Get(rReq.GetSlot())).GetValue(); + getDocProperties()->setAuthor( aStr ); + break; + } + + case SID_DOCINFO_COMMENTS : + { + ::rtl::OUString aStr = ( (SfxStringItem&)rReq.GetArgs()->Get(rReq.GetSlot())).GetValue(); + getDocProperties()->setDescription( aStr ); + break; + } + + case SID_DOCINFO_KEYWORDS : + { + ::rtl::OUString aStr = ( (SfxStringItem&)rReq.GetArgs()->Get(rReq.GetSlot())).GetValue(); + getDocProperties()->setKeywords( + ::comphelper::string::convertCommaSeparated(aStr) ); + break; + } + } +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::StateProps_Impl(SfxItemSet &rSet) +{ + SfxWhichIter aIter(rSet); + for ( USHORT nSID = aIter.FirstWhich(); nSID; nSID = aIter.NextWhich() ) + { + switch ( nSID ) + { + case SID_DOCINFO_AUTHOR : + { + rSet.Put( SfxStringItem( nSID, + getDocProperties()->getAuthor() ) ); + break; + } + + case SID_DOCINFO_COMMENTS : + { + rSet.Put( SfxStringItem( nSID, + getDocProperties()->getDescription()) ); + break; + } + + case SID_DOCINFO_KEYWORDS : + { + rSet.Put( SfxStringItem( nSID, ::comphelper::string:: + convertCommaSeparated(getDocProperties()->getKeywords())) ); + break; + } + + case SID_DOCPATH: + { + DBG_ERROR( "Not supported anymore!" ); + break; + } + + case SID_DOCFULLNAME: + { + rSet.Put( SfxStringItem( SID_DOCFULLNAME, GetTitle(SFX_TITLE_FULLNAME) ) ); + break; + } + + case SID_DOCTITLE: + { + rSet.Put( SfxStringItem( SID_DOCTITLE, GetTitle() ) ); + break; + } + + case SID_DOC_READONLY: + { + rSet.Put( SfxBoolItem( SID_DOC_READONLY, IsReadOnly() ) ); + break; + } + + case SID_DOC_SAVED: + { + rSet.Put( SfxBoolItem( SID_DOC_SAVED, !IsModified() ) ); + break; + } + + case SID_CLOSING: + { + rSet.Put( SfxBoolItem( SID_CLOSING, false ) ); + break; + } + + case SID_DOC_LOADING: + rSet.Put( SfxBoolItem( nSID, SFX_LOADED_MAINDOCUMENT != + ( pImp->nLoadedFlags & SFX_LOADED_MAINDOCUMENT ) ) ); + break; + + case SID_IMG_LOADING: + rSet.Put( SfxBoolItem( nSID, SFX_LOADED_IMAGES != + ( pImp->nLoadedFlags & SFX_LOADED_IMAGES ) ) ); + break; + } + } +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::ExecView_Impl(SfxRequest &rReq) +{ + switch ( rReq.GetSlot() ) + { + case SID_ACTIVATE: + { + SfxViewFrame *pFrame = SfxViewFrame::GetFirst( this, TRUE ); + if ( pFrame ) + pFrame->GetFrame().Appear(); + rReq.SetReturnValue( SfxObjectItem( 0, pFrame ) ); + rReq.Done(); + break; + } + case SID_NEWWINDOWFOREDIT: + { + SfxViewFrame* pFrame = SfxViewFrame::Current(); + if( pFrame->GetObjectShell() == this && + ( pFrame->GetFrameType() & SFXFRAME_HASTITLE ) ) + pFrame->ExecuteSlot( rReq ); + else + { + String aFileName( GetObjectShell()->GetMedium()->GetName() ); + if ( aFileName.Len() ) + { + SfxStringItem aName( SID_FILE_NAME, aFileName ); + SfxBoolItem aCreateView( SID_OPEN_NEW_VIEW, TRUE ); + SFX_APP()->GetAppDispatcher_Impl()->Execute( + SID_OPENDOC, SFX_CALLMODE_ASYNCHRON, &aName, + &aCreateView, 0L); + } + } + } + } +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::StateView_Impl(SfxItemSet& /*rSet*/) +{ +} + +sal_uInt16 SfxObjectShell::ImplCheckSignaturesInformation( const uno::Sequence< security::DocumentSignatureInformation >& aInfos ) +{ + sal_Bool bCertValid = sal_True; + sal_uInt16 nResult = SIGNATURESTATE_NOSIGNATURES; + int nInfos = aInfos.getLength(); + bool bCompleteSignature = true; + if( nInfos ) + { + nResult = SIGNATURESTATE_SIGNATURES_OK; + for ( int n = 0; n < nInfos; n++ ) + { + if ( bCertValid ) + { + sal_Int32 nCertStat = aInfos[n].CertificateStatus; + bCertValid = nCertStat == security::CertificateValidity::VALID ? sal_True : sal_False; + } + + if ( !aInfos[n].SignatureIsValid ) + { + nResult = SIGNATURESTATE_SIGNATURES_BROKEN; + break; // we know enough + } + bCompleteSignature &= !aInfos[n].PartialDocumentSignature; + } + } + + if ( nResult == SIGNATURESTATE_SIGNATURES_OK && !bCertValid ) + nResult = SIGNATURESTATE_SIGNATURES_NOTVALIDATED; + else if ( nResult == SIGNATURESTATE_SIGNATURES_OK && bCertValid && !bCompleteSignature) + nResult = SIGNATURESTATE_SIGNATURES_PARTIAL_OK; + + // this code must not check whether the document is modified + // it should only check the provided info + + return nResult; +} + +uno::Sequence< security::DocumentSignatureInformation > SfxObjectShell::ImplAnalyzeSignature( sal_Bool bScriptingContent, const uno::Reference< security::XDocumentDigitalSignatures >& xSigner ) +{ + uno::Sequence< security::DocumentSignatureInformation > aResult; + uno::Reference< security::XDocumentDigitalSignatures > xLocSigner = xSigner; + + if ( GetMedium() && GetMedium()->GetName().Len() && IsOwnStorageFormat_Impl( *GetMedium()) && GetMedium()->GetStorage().is() ) + { + try + { + if ( !xLocSigner.is() ) + { + uno::Sequence< uno::Any > aArgs( 1 ); + aArgs[0] <<= ::rtl::OUString(); + try + { + uno::Reference < beans::XPropertySet > xPropSet( GetStorage(), uno::UNO_QUERY_THROW ); + aArgs[0] = xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ) ); + } + catch( uno::Exception& ) + { + } + + xLocSigner.set( comphelper::getProcessServiceFactory()->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.security.DocumentDigitalSignatures" ) ), aArgs ), uno::UNO_QUERY_THROW ); + + } + + if ( bScriptingContent ) + aResult = xLocSigner->verifyScriptingContentSignatures( GetMedium()->GetZipStorageToSign_Impl(), + uno::Reference< io::XInputStream >() ); + else + aResult = xLocSigner->verifyDocumentContentSignatures( GetMedium()->GetZipStorageToSign_Impl(), + uno::Reference< io::XInputStream >() ); + } + catch( com::sun::star::uno::Exception& ) + { + } + } + + return aResult; +} + +sal_uInt16 SfxObjectShell::ImplGetSignatureState( sal_Bool bScriptingContent ) +{ + sal_Int16* pState = bScriptingContent ? &pImp->nScriptingSignatureState : &pImp->nDocumentSignatureState; + + if ( *pState == SIGNATURESTATE_UNKNOWN ) + { + *pState = SIGNATURESTATE_NOSIGNATURES; + + uno::Sequence< security::DocumentSignatureInformation > aInfos = ImplAnalyzeSignature( bScriptingContent ); + *pState = ImplCheckSignaturesInformation( aInfos ); + } + + if ( *pState == SIGNATURESTATE_SIGNATURES_OK || *pState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED + || *pState == SIGNATURESTATE_SIGNATURES_PARTIAL_OK) + { + if ( IsModified() ) + *pState = SIGNATURESTATE_SIGNATURES_INVALID; + } + + return (sal_uInt16)*pState; +} + +void SfxObjectShell::ImplSign( sal_Bool bScriptingContent ) +{ + // Check if it is stored in OASIS format... + if ( GetMedium() + && GetMedium()->GetFilter() + && GetMedium()->GetName().Len() + && ( !GetMedium()->GetFilter()->IsOwnFormat() + || !GetMedium()->HasStorage_Impl() + ) + ) + { + // Only OASIS and OOo6.x formats will be handled further + InfoBox( NULL, SfxResId( RID_XMLSEC_INFO_WRONGDOCFORMAT ) ).Execute(); + return; + } + + // check whether the document is signed + ImplGetSignatureState( sal_False ); // document signature + ImplGetSignatureState( sal_True ); // script signature + sal_Bool bHasSign = ( pImp->nScriptingSignatureState != SIGNATURESTATE_NOSIGNATURES || pImp->nDocumentSignatureState != SIGNATURESTATE_NOSIGNATURES ); + + // the target ODF version on saving + SvtSaveOptions aSaveOpt; + SvtSaveOptions::ODFDefaultVersion nVersion = aSaveOpt.GetODFDefaultVersion(); + + // the document is not new and is not modified + ::rtl::OUString aODFVersion; + try + { + // check the version of the document + uno::Reference < beans::XPropertySet > xPropSet( GetStorage(), uno::UNO_QUERY_THROW ); + xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ) ) >>= aODFVersion; + } + catch( uno::Exception& ) + {} + + bool bNoSig = false; + + if ( IsModified() || !GetMedium() || !GetMedium()->GetName().Len() + || (!aODFVersion.equals( ODFVER_012_TEXT ) && !bHasSign) ) + { + // the document might need saving ( new, modified or in ODF1.1 format without signature ) + + if ( nVersion >= SvtSaveOptions::ODFVER_012 ) + { + + if ( (bHasSign && QueryBox( NULL, SfxResId( MSG_XMLSEC_QUERY_SAVESIGNEDBEFORESIGN ) ).Execute() == RET_YES) + || (!bHasSign && QueryBox( NULL, SfxResId( RID_XMLSEC_QUERY_SAVEBEFORESIGN ) ).Execute() == RET_YES) ) + { + USHORT nId = SID_SAVEDOC; + if ( !GetMedium() || !GetMedium()->GetName().Len() ) + nId = SID_SAVEASDOC; + SfxRequest aSaveRequest( nId, 0, GetPool() ); + //ToDo: Review. We needed to call SetModified, otherwise the document would not be saved. + SetModified(sal_True); + ExecFile_Impl( aSaveRequest ); + + // Check if it is stored in OASIS format... + if ( GetMedium() && GetMedium()->GetFilter() + && ( !GetMedium()->GetFilter()->IsOwnFormat() || !GetMedium()->HasStorage_Impl() + || SotStorage::GetVersion( GetMedium()->GetStorage() ) <= SOFFICE_FILEFORMAT_60 ) ) + { + // Only OASIS format will be handled further + InfoBox( NULL, SfxResId( RID_XMLSEC_INFO_WRONGDOCFORMAT ) ).Execute(); + return; + } + } + else + { + //When the document is modified then we must not show the digital signatures dialog + //If we have come here then the user denied to save. + if (!bHasSign) + bNoSig = true; + } + } + else + { + ErrorBox( NULL, WB_OK, SfxResId( STR_XMLSEC_ODF12_EXPECTED ) ).Execute(); + return; + } + + if ( IsModified() || !GetMedium() || !GetMedium()->GetName().Len() ) + return; + } + + // the document is not modified currently, so it can not become modified after signing + sal_Bool bAllowModifiedBack = sal_False; + if ( IsEnableSetModified() ) + { + EnableSetModified( sal_False ); + bAllowModifiedBack = sal_True; + } + + // we have to store to the original document, the original medium should be closed for this time + if ( !bNoSig + && ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) ) + { + GetMedium()->CloseAndRelease(); + + // We sign only ODF1.2, that means that if this point has been reached, + // the ODF1.2 signing process should be used. + // This code still might be called to show the signature of ODF1.1 document. + sal_Bool bSigned = GetMedium()->SignContents_Impl( + bScriptingContent, + aODFVersion, + pImp->nDocumentSignatureState == SIGNATURESTATE_SIGNATURES_OK + || pImp->nDocumentSignatureState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED + || pImp->nDocumentSignatureState == SIGNATURESTATE_SIGNATURES_PARTIAL_OK); + + DoSaveCompleted( GetMedium() ); + + if ( bSigned ) + { + if ( bScriptingContent ) + { + pImp->nScriptingSignatureState = SIGNATURESTATE_UNKNOWN;// Re-Check + + // adding of scripting signature removes existing document signature + pImp->nDocumentSignatureState = SIGNATURESTATE_UNKNOWN;// Re-Check + } + else + pImp->nDocumentSignatureState = SIGNATURESTATE_UNKNOWN;// Re-Check + + pImp->bSignatureErrorIsShown = sal_False; + + Invalidate( SID_SIGNATURE ); + Invalidate( SID_MACRO_SIGNATURE ); + Broadcast( SfxSimpleHint(SFX_HINT_TITLECHANGED) ); + } + } + + if ( bAllowModifiedBack ) + EnableSetModified( sal_True ); +} + +sal_uInt16 SfxObjectShell::GetDocumentSignatureState() +{ + return ImplGetSignatureState( FALSE ); +} + +void SfxObjectShell::SignDocumentContent() +{ + ImplSign( FALSE ); +} + +sal_uInt16 SfxObjectShell::GetScriptingSignatureState() +{ + return ImplGetSignatureState( TRUE ); +} + +void SfxObjectShell::SignScriptingContent() +{ + ImplSign( TRUE ); +} + +// static +const uno::Sequence<sal_Int8>& SfxObjectShell::getUnoTunnelId() +{ + static uno::Sequence<sal_Int8> * pSeq = 0; + if( !pSeq ) + { + osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); + if( !pSeq ) + { + static uno::Sequence< sal_Int8 > aSeq( 16 ); + rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, sal_True ); + pSeq = &aSeq; + } + } + return *pSeq; +} diff --git a/sfx2/source/doc/objstor.cxx b/sfx2/source/doc/objstor.cxx new file mode 100644 index 000000000000..037493c61252 --- /dev/null +++ b/sfx2/source/doc/objstor.cxx @@ -0,0 +1,3743 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#ifndef _MSGBOX_HXX //autogen +#include <vcl/msgbox.hxx> +#endif +#include <svl/eitem.hxx> +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <tools/zcodec.hxx> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/document/XImporter.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/document/FilterOptionsRequest.hpp> +#include <com/sun/star/document/XInteractionFilterOptions.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/task/XInteractionAskLater.hpp> +#include <com/sun/star/task/FutureDocumentVersionProductUpdateRequest.hpp> +#include <com/sun/star/task/InteractionClassification.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/document/MacroExecMode.hpp> +#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> +#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XSet.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/EmbedStates.hpp> +#include <com/sun/star/embed/Aspects.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/embed/XEmbedPersist.hpp> +#include <com/sun/star/embed/XLinkageSupport.hpp> +#include <com/sun/star/embed/EntryInitModes.hpp> +#include <com/sun/star/embed/XOptimizedStorage.hpp> +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <com/sun/star/security/XDocumentDigitalSignatures.hpp> + +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/configurationhelper.hxx> +#include <comphelper/interaction.hxx> +#include <svtools/sfxecode.hxx> +#include <unotools/securityoptions.hxx> +#include <cppuhelper/weak.hxx> +#include <comphelper/processfactory.hxx> +#include <tools/cachestr.hxx> +#include <unotools/streamwrap.hxx> + +#include <unotools/saveopt.hxx> +#include <unotools/useroptions.hxx> +#include <unotools/pathoptions.hxx> +#include <tools/urlobj.hxx> +#include <tools/diagnose_ex.h> +#include <unotools/localfilehelper.hxx> +#include <unotools/ucbhelper.hxx> +#include <unotools/tempfile.hxx> +#include <unotools/docinfohelper.hxx> +#include <ucbhelper/content.hxx> +#include <sot/storinfo.hxx> +#include <sot/exchange.hxx> +#include <sot/formats.hxx> +#include <comphelper/storagehelper.hxx> +#include <comphelper/seqstream.hxx> +#include <comphelper/documentconstants.hxx> +#include <comphelper/string.hxx> +#include <vcl/bitmapex.hxx> +#include <svtools/embedhlp.hxx> +#include <rtl/logfile.hxx> +#include <basic/modsizeexceeded.hxx> +#include <osl/file.hxx> + +#include <sfx2/signaturestate.hxx> +#include <sfx2/app.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/childwin.hxx> +#include <sfx2/request.hxx> +#include "sfxresid.hxx" +#include <sfx2/docfile.hxx> +#include "fltfnc.hxx" +#include <sfx2/docfilt.hxx> +#include <sfx2/docfac.hxx> +#include "objshimp.hxx" +#include "sfxtypes.hxx" +#include "doc.hrc" +#include <sfx2/sfxsids.hrc> +#include <sfx2/module.hxx> +#include <sfx2/dispatch.hxx> +#include "openflag.hxx" +#include "helper.hxx" +#include <sfx2/filedlghelper.hxx> +#include <sfx2/event.hxx> +#include "fltoptint.hxx" +#include <sfx2/viewfrm.hxx> +#include "graphhelp.hxx" +#include "appbaslib.hxx" +#include "appdata.hxx" + +#ifdef OS2 +#include <osl/file.hxx> +#include <stdio.h> +#include <sys/ea.h> +#endif + +#include "../appl/app.hrc" + +extern sal_uInt32 CheckPasswd_Impl( SfxObjectShell*, SfxItemPool&, SfxMedium* ); + +using namespace ::com::sun::star; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::document; +using namespace ::rtl; +using namespace ::cppu; + +namespace css = ::com::sun::star; + +//========================================================================= +void impl_addToModelCollection(const css::uno::Reference< css::frame::XModel >& xModel) +{ + if (!xModel.is()) + return; + + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = ::comphelper::getProcessServiceFactory(); + css::uno::Reference< css::container::XSet > xModelCollection( + xSMGR->createInstance(::rtl::OUString::createFromAscii("com.sun.star.frame.GlobalEventBroadcaster")), + css::uno::UNO_QUERY); + if (xModelCollection.is()) + { + try + { + xModelCollection->insert(css::uno::makeAny(xModel)); + } + catch ( uno::Exception& ) + { + OSL_ENSURE( sal_False, "The document seems to be in the collection already!\n" ); + } + } +} + +//========================================================================= + +sal_Bool SfxObjectShell::Save() +{ + return SaveChildren(); +} + +//-------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::SaveAs( SfxMedium& rMedium ) +{ + return SaveAsChildren( rMedium ); +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::QuerySlotExecutable( USHORT /*nSlotId*/ ) +{ + return sal_True; +} + +//------------------------------------------------------------------------- + +sal_Bool GetPasswd_Impl( const SfxItemSet* pSet, ::rtl::OUString& rPasswd ) +{ + const SfxPoolItem* pItem = NULL; + if ( pSet && SFX_ITEM_SET == pSet->GetItemState( SID_PASSWORD, sal_True, &pItem ) ) + { + DBG_ASSERT( pItem->IsA( TYPE(SfxStringItem) ), "wrong item type" ); + rPasswd = ( (const SfxStringItem*)pItem )->GetValue(); + return sal_True; + } + return sal_False; +} + +//------------------------------------------------------------------------- +sal_Bool SfxObjectShell::PutURLContentsToVersionStream_Impl( + ::rtl::OUString aURL, + const uno::Reference< embed::XStorage >& xDocStorage, + ::rtl::OUString aStreamName ) +{ + sal_Bool bResult = sal_False; + try + { + uno::Reference< embed::XStorage > xVersion = xDocStorage->openStorageElement( + ::rtl::OUString::createFromAscii( "Versions" ), + embed::ElementModes::READWRITE ); + + DBG_ASSERT( xVersion.is(), + "The method must throw an exception if the storage can not be opened!\n" ); + if ( !xVersion.is() ) + throw uno::RuntimeException(); + + uno::Reference< io::XStream > xVerStream = xVersion->openStreamElement( + aStreamName, + embed::ElementModes::READWRITE ); + DBG_ASSERT( xVerStream.is(), "The method must throw an exception if the storage can not be opened!\n" ); + if ( !xVerStream.is() ) + throw uno::RuntimeException(); + + uno::Reference< io::XOutputStream > xOutStream = xVerStream->getOutputStream(); + uno::Reference< io::XTruncate > xTrunc( xOutStream, uno::UNO_QUERY ); + + DBG_ASSERT( xTrunc.is(), "The output stream must exist and implement XTruncate interface!\n" ); + if ( !xTrunc.is() ) + throw RuntimeException(); + + uno::Reference< io::XInputStream > xTmpInStream = + ::comphelper::OStorageHelper::GetInputStreamFromURL( aURL ); + DBG_ASSERT( xTmpInStream.is(), "The method must create the stream or throw an exception!\n" ); + if ( !xTmpInStream.is() ) + throw uno::RuntimeException(); + + xTrunc->truncate(); + ::comphelper::OStorageHelper::CopyInputToOutput( xTmpInStream, xOutStream ); + xOutStream->closeOutput(); + + uno::Reference< embed::XTransactedObject > xTransact( xVersion, uno::UNO_QUERY ); + DBG_ASSERT( xTransact.is(), "The storage must implement XTransacted interface!\n" ); + if ( xTransact.is() ) + xTransact->commit(); + + bResult = sal_True; + } + catch( uno::Exception& ) + { + // TODO/LATER: handle the error depending on exception + SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + + return bResult; +} + +//------------------------------------------------------------------------- +::rtl::OUString SfxObjectShell::CreateTempCopyOfStorage_Impl( const uno::Reference< embed::XStorage >& xStorage ) +{ + ::rtl::OUString aTempURL = ::utl::TempFile().GetURL(); + + DBG_ASSERT( aTempURL.getLength(), "Can't create a temporary file!\n" ); + if ( aTempURL.getLength() ) + { + try + { + uno::Reference< embed::XStorage > xTempStorage = + ::comphelper::OStorageHelper::GetStorageFromURL( aTempURL, embed::ElementModes::READWRITE ); + + // the password will be transfered from the xStorage to xTempStorage by storage implemetation + xStorage->copyToStorage( xTempStorage ); + + // the temporary storage was commited by the previous method and it will die by refcount + } + catch ( uno::Exception& ) + { + DBG_ERROR( "Creation of a storage copy is failed!" ); + ::utl::UCBContentHelper::Kill( aTempURL ); + + aTempURL = ::rtl::OUString(); + + // TODO/LATER: may need error code setting based on exception + SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + } + + return aTempURL; +} + +//------------------------------------------------------------------------- +SvGlobalName SfxObjectShell::GetClassName() const +{ + return GetFactory().GetClassId(); +} + +//------------------------------------------------------------------------- +void SfxObjectShell::SetupStorage( const uno::Reference< embed::XStorage >& xStorage, + sal_Int32 nVersion, + sal_Bool bTemplate ) const +{ + uno::Reference< beans::XPropertySet > xProps( xStorage, uno::UNO_QUERY ); + + if ( xProps.is() ) + { + SvGlobalName aName; + String aFullTypeName, aShortTypeName, aAppName; + sal_uInt32 nClipFormat=0; + + FillClass( &aName, &nClipFormat, &aAppName, &aFullTypeName, &aShortTypeName, nVersion, bTemplate ); + if ( nClipFormat ) + { + // basic doesn't have a ClipFormat + // without MediaType the storage is not really usable, but currently the BasicIDE still + // is an SfxObjectShell and so we can't take this as an error + datatransfer::DataFlavor aDataFlavor; + SotExchange::GetFormatDataFlavor( nClipFormat, aDataFlavor ); + if ( aDataFlavor.MimeType.getLength() ) + { + try + { + xProps->setPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ), uno::makeAny( aDataFlavor.MimeType ) ); + } + catch( uno::Exception& ) + { + const_cast<SfxObjectShell*>( this )->SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + + ::rtl::OUString aVersion; + SvtSaveOptions aSaveOpt; + SvtSaveOptions::ODFDefaultVersion nDefVersion = aSaveOpt.GetODFDefaultVersion(); + + // older versions can not have this property set, it exists only starting from ODF1.2 + if ( nDefVersion >= SvtSaveOptions::ODFVER_012 ) + aVersion = ODFVER_012_TEXT; + + if ( aVersion.getLength() ) + { + try + { + xProps->setPropertyValue( ::rtl::OUString::createFromAscii( "Version" ), uno::makeAny( aVersion ) ); + } + catch( uno::Exception& ) + { + } + } + } + } + } +} + +//------------------------------------------------------------------------- +void SfxObjectShell::PrepareSecondTryLoad_Impl() +{ + // only for internal use + pImp->m_xDocStorage = uno::Reference< embed::XStorage >(); + pImp->m_bIsInit = sal_False; + ResetError(); +} + +//------------------------------------------------------------------------- +sal_Bool SfxObjectShell::GeneralInit_Impl( const uno::Reference< embed::XStorage >& xStorage, + sal_Bool bTypeMustBeSetAlready ) +{ + if ( pImp->m_bIsInit ) + return sal_False; + + pImp->m_bIsInit = sal_True; + if ( xStorage.is() ) + { + // no notification is required the storage is set the first time + pImp->m_xDocStorage = xStorage; + + try { + uno::Reference < beans::XPropertySet > xPropSet( xStorage, uno::UNO_QUERY_THROW ); + Any a = xPropSet->getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ) ); + ::rtl::OUString aMediaType; + if ( !(a>>=aMediaType) || !aMediaType.getLength() ) + { + if ( bTypeMustBeSetAlready ) + { + SetError( ERRCODE_IO_BROKENPACKAGE, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + return sal_False; + } + + SetupStorage( xStorage, SOFFICE_FILEFORMAT_CURRENT, sal_False ); + } + } + catch ( uno::Exception& ) + { + OSL_ENSURE( sal_False, "Can't check storage's mediatype!\n" ); + } + } + else + pImp->m_bCreateTempStor = sal_True; + + return sal_True; +} + +//------------------------------------------------------------------------- +sal_Bool SfxObjectShell::InitNew( const uno::Reference< embed::XStorage >& xStorage ) +{ + return GeneralInit_Impl( xStorage, sal_False ); +} + +//------------------------------------------------------------------------- +sal_Bool SfxObjectShell::Load( SfxMedium& rMedium ) +{ + return GeneralInit_Impl( rMedium.GetStorage(), sal_True ); +} + +sal_Bool SfxObjectShell::DoInitNew( SfxMedium* pMed ) +/* [Beschreibung] + + Diese von SvPersist geerbte virtuelle Methode wird gerufen, um + die SfxObjectShell-Instanz aus einem Storage (pStor != 0) bzw. + (pStor == 0) ganz neu zu initialisieren. + + Wie alle Do...-Methoden liegt hier eine Steuerung vor, die eigentliche + Implementierung erfolgt, indem die ebenfalls virtuellen Methode + InitNew(SvStorate*) von der SfxObjectShell-Subclass implementiert wird. + + F"ur pStor == 0 wird ein die SfxObjectShell-Instanz mit einem leeren + SfxMedium verbunden, sonst mit einem SfxMedium, welches auf den + als Parameter "ubergeben SvStorage verweist. + + Erst nach InitNew() oder Load() ist das Objekt korrekt initialisiert. + + [R"uckgabewert] + sal_True Das Objekt wurde initialisiert. + sal_False Das Objekt konnte nicht initialisiert werden +*/ + +{ + ModifyBlocker_Impl aBlock( this ); + pMedium = pMed; + if ( !pMedium ) + { + bIsTmp = sal_True; + pMedium = new SfxMedium; + } + + pMedium->CanDisposeStorage_Impl( sal_True ); + + if ( InitNew( pMed ? pMed->GetStorage() : uno::Reference < embed::XStorage >() ) ) + { + // empty documents always get their macros from the user, so there is no reason to restrict access + pImp->aMacroMode.allowMacroExecution(); + if ( SFX_CREATE_MODE_EMBEDDED == eCreateMode ) + SetTitle( String( SfxResId( STR_NONAME ) )); + + uno::Reference< frame::XModel > xModel ( GetModel(), uno::UNO_QUERY ); + if ( xModel.is() ) + { + SfxItemSet *pSet = GetMedium()->GetItemSet(); + uno::Sequence< beans::PropertyValue > aArgs; + TransformItems( SID_OPENDOC, *pSet, aArgs ); + sal_Int32 nLength = aArgs.getLength(); + aArgs.realloc( nLength + 1 ); + aArgs[nLength].Name = DEFINE_CONST_UNICODE("Title"); + aArgs[nLength].Value <<= ::rtl::OUString( GetTitle( SFX_TITLE_DETECT ) ); + xModel->attachResource( ::rtl::OUString(), aArgs ); + impl_addToModelCollection(xModel); + } + + SetInitialized_Impl( true ); + return sal_True; + } + + return sal_False; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::ImportFromGeneratedStream_Impl( + const uno::Reference< io::XStream >& xStream, + const uno::Sequence< beans::PropertyValue >& aMediaDescr ) +{ + if ( !xStream.is() ) + return sal_False; + + if ( pMedium && pMedium->HasStorage_Impl() ) + pMedium->CloseStorage(); + + sal_Bool bResult = sal_False; + + try + { + uno::Reference< embed::XStorage > xStorage = + ::comphelper::OStorageHelper::GetStorageFromStream( xStream, embed::ElementModes::READWRITE ); + + if ( !xStorage.is() ) + throw uno::RuntimeException(); + + if ( !pMedium ) + pMedium = new SfxMedium( xStorage, String() ); + else + pMedium->SetStorage_Impl( xStorage ); + + SfxAllItemSet aSet( SFX_APP()->GetPool() ); + TransformParameters( SID_OPENDOC, aMediaDescr, aSet ); + pMedium->GetItemSet()->Put( aSet ); + pMedium->CanDisposeStorage_Impl( sal_False ); + + // allow the subfilter to reinit the model + if ( pImp->m_bIsInit ) + pImp->m_bIsInit = sal_False; + + if ( LoadOwnFormat( *pMedium ) ) + { + bHasName = sal_True; + if ( !IsReadOnly() && IsLoadReadonly() ) + SetReadOnlyUI(); + + bResult = sal_True; + OSL_ENSURE( pImp->m_xDocStorage == xStorage, "Wrong storage is used!\n" ); + } + + // now the medium can be disconnected from the storage + // the medium is not allowed to dispose the storage so CloseStorage() can be used + pMedium->CloseStorage(); + } + catch( uno::Exception& ) + { + } + + return bResult; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::DoLoad( SfxMedium *pMed ) +{ + ModifyBlocker_Impl aBlock( this ); + + if ( SFX_CREATE_MODE_EMBEDDED != eCreateMode ) + GetpApp()->ShowStatusText( SfxResId(STR_DOC_LOADING) ); + + pMedium = pMed; + pMedium->CanDisposeStorage_Impl( sal_True ); + + sal_Bool bOk = sal_False; + const SfxFilter* pFilter = pMed->GetFilter(); + SfxItemSet* pSet = pMedium->GetItemSet(); + if( !pImp->nEventId ) + { + SFX_ITEMSET_ARG( + pSet, pTemplateItem, SfxBoolItem, + SID_TEMPLATE, sal_False); + SetActivateEvent_Impl( + ( pTemplateItem && pTemplateItem->GetValue() ) + ? SFX_EVENT_CREATEDOC : SFX_EVENT_OPENDOC ); + } + + + SFX_ITEMSET_ARG( pSet, pBaseItem, SfxStringItem, + SID_BASEURL, sal_False); + String aBaseURL; + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False); + if( pBaseItem ) + aBaseURL = pBaseItem->GetValue(); + else + { + if ( pSalvageItem ) + { + String aName( pMed->GetPhysicalName() ); + ::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aBaseURL ); + } + else + aBaseURL = pMed->GetBaseURL(); + } + pMed->GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, aBaseURL ) ); + + pImp->nLoadedFlags = 0; + pImp->bModelInitialized = sal_False; + + //TODO/LATER: make a clear strategy how to handle "UsesStorage" etc. + sal_Bool bOwnStorageFormat = IsOwnStorageFormat_Impl( *pMedium ); + sal_Bool bHasStorage = IsPackageStorageFormat_Impl( *pMedium ); + if ( pMedium->GetFilter() ) + { + sal_uInt32 nError = HandleFilter( pMedium, this ); + if ( nError != ERRCODE_NONE ) + SetError( nError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + + EnableSetModified( sal_False ); + + pMedium->LockOrigFileOnDemand( sal_True, sal_False ); + if ( GetError() == ERRCODE_NONE && bOwnStorageFormat && ( !pFilter || !( pFilter->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) ) ) + { + uno::Reference< embed::XStorage > xStorage; + if ( pMedium->GetError() == ERRCODE_NONE ) + xStorage = pMedium->GetStorage(); + + if( xStorage.is() && pMedium->GetLastStorageCreationState() == ERRCODE_NONE ) + { + DBG_ASSERT( pFilter, "No filter for storage found!" ); + + try + { + sal_Bool bWarnMediaTypeFallback = sal_False; + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pRepairPackageItem, SfxBoolItem, SID_REPAIRPACKAGE, sal_False); + + // treat the package as broken if the mediatype was retrieved as a fallback + uno::Reference< beans::XPropertySet > xStorProps( xStorage, uno::UNO_QUERY_THROW ); + xStorProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaTypeFallbackUsed" ) ) ) + >>= bWarnMediaTypeFallback; + + if ( pRepairPackageItem && pRepairPackageItem->GetValue() ) + { + // the macros in repaired documents should be disabled + pMedium->GetItemSet()->Put( SfxUInt16Item( SID_MACROEXECMODE, document::MacroExecMode::NEVER_EXECUTE ) ); + + // the mediatype was retrieved by using fallback solution but this is a repairing mode + // so it is acceptable to open the document if there is no contents that required manifest.xml + bWarnMediaTypeFallback = sal_False; + } + + if ( bWarnMediaTypeFallback || !xStorage->getElementNames().getLength() ) + SetError( ERRCODE_IO_BROKENPACKAGE, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + catch( uno::Exception& ) + { + // TODO/LATER: may need error code setting based on exception + SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + + // Load + if ( !GetError() ) + { + pImp->nLoadedFlags = 0; + pImp->bModelInitialized = sal_False; + bOk = xStorage.is() && LoadOwnFormat( *pMed ); + if ( bOk ) + { + // the document loaded from template has no name + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pTemplateItem, SfxBoolItem, SID_TEMPLATE, sal_False); + if ( !pTemplateItem || !pTemplateItem->GetValue() ) + bHasName = sal_True; + + if ( !IsReadOnly() && IsLoadReadonly() ) + SetReadOnlyUI(); + } + else + SetError( ERRCODE_ABORT, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + } + else + SetError( pMed->GetLastStorageCreationState(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + else if ( GetError() == ERRCODE_NONE && InitNew(0) ) + { + // Name vor ConvertFrom setzen, damit GetSbxObject() schon funktioniert + bHasName = sal_True; + SetName( SfxResId( STR_NONAME ) ); + + if( !bHasStorage ) + pMedium->GetInStream(); + else + pMedium->GetStorage(); + + if ( GetError() == ERRCODE_NONE ) + { + pImp->nLoadedFlags = 0; + pImp->bModelInitialized = sal_False; + if ( pMedium->GetFilter() && ( pMedium->GetFilter()->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) ) + { + uno::Reference < beans::XPropertySet > xSet( GetModel(), uno::UNO_QUERY ); + ::rtl::OUString sLockUpdates(::rtl::OUString::createFromAscii("LockUpdates")); + bool bSetProperty = true; + try + { + xSet->setPropertyValue( sLockUpdates, makeAny( (sal_Bool) sal_True ) ); + } + catch(const beans::UnknownPropertyException& ) + { + bSetProperty = false; + } + bOk = ImportFrom(*pMedium); + if(bSetProperty) + { + try + { + xSet->setPropertyValue( sLockUpdates, makeAny( (sal_Bool) sal_False ) ); + } + catch(const beans::UnknownPropertyException& ) + {} + } + UpdateLinks(); + FinishedLoading( SFX_LOADED_ALL ); + } + else + { + bOk = ConvertFrom(*pMedium); + InitOwnModel_Impl(); + } + } + } + + if ( bOk ) + { + try + { + ::ucbhelper::Content aContent( pMedium->GetName(), com::sun::star::uno::Reference < XCommandEnvironment >() ); + com::sun::star::uno::Reference < XPropertySetInfo > xProps = aContent.getProperties(); + if ( xProps.is() ) + { + ::rtl::OUString aAuthor( RTL_CONSTASCII_USTRINGPARAM("Author") ); + ::rtl::OUString aKeywords( RTL_CONSTASCII_USTRINGPARAM("Keywords") ); + ::rtl::OUString aSubject( RTL_CONSTASCII_USTRINGPARAM("Subject") ); + Any aAny; + ::rtl::OUString aValue; + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps + = xDPS->getDocumentProperties(); + if ( xProps->hasPropertyByName( aAuthor ) ) + { + aAny = aContent.getPropertyValue( aAuthor ); + if ( ( aAny >>= aValue ) ) + xDocProps->setAuthor(aValue); + } + if ( xProps->hasPropertyByName( aKeywords ) ) + { + aAny = aContent.getPropertyValue( aKeywords ); + if ( ( aAny >>= aValue ) ) + xDocProps->setKeywords( + ::comphelper::string::convertCommaSeparated(aValue)); +; + } + if ( xProps->hasPropertyByName( aSubject ) ) + { + aAny = aContent.getPropertyValue( aSubject ); + if ( ( aAny >>= aValue ) ) { + xDocProps->setSubject(aValue); + } + } + } + } + catch( Exception& ) + { + } + + // Falls nicht asynchron geladen wird selbst FinishedLoading aufrufen + if ( !( pImp->nLoadedFlags & SFX_LOADED_MAINDOCUMENT ) && + ( !pMedium->GetFilter() || pMedium->GetFilter()->UsesStorage() ) + ) + FinishedLoading( SFX_LOADED_MAINDOCUMENT ); + + if( IsOwnStorageFormat_Impl(*pMed) && pMed->GetFilter() ) + { +//???? dv DirEntry aDirEntry( pMed->GetPhysicalName() ); +//???? dv SetFileName( aDirEntry.GetFull() ); + } + Broadcast( SfxSimpleHint(SFX_HINT_NAMECHANGED) ); + + if ( SFX_CREATE_MODE_EMBEDDED != eCreateMode ) + { + GetpApp()->HideStatusText(); + + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pAsTempItem, SfxBoolItem, SID_TEMPLATE, sal_False); + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pPreviewItem, SfxBoolItem, SID_PREVIEW, sal_False); + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pHiddenItem, SfxBoolItem, SID_HIDDEN, sal_False); + if( bOk && pMedium->GetOrigURL().Len() + && !( pAsTempItem && pAsTempItem->GetValue() ) + && !( pPreviewItem && pPreviewItem->GetValue() ) + && !( pHiddenItem && pHiddenItem->GetValue() ) ) + { + INetURLObject aUrl( pMedium->GetOrigURL() ); + + if ( aUrl.GetProtocol() == INET_PROT_FILE ) + { + const SfxFilter* pOrgFilter = pMedium->GetOrigFilter(); + Application::AddToRecentDocumentList( + aUrl.GetURLNoPass( INetURLObject::NO_DECODE ), + (pOrgFilter) ? pOrgFilter->GetMimeType() : String() ); + } + } + } + + if ( pMedium->HasStorage_Impl() ) + { + uno::Reference< XInteractionHandler > xHandler( pMedium->GetInteractionHandler() ); + if ( xHandler.is() && !SFX_APP()->Get_Impl()->bODFVersionWarningLater ) + { + uno::Reference<beans::XPropertySet> xStorageProps( pMedium->GetStorage(), uno::UNO_QUERY_THROW ); + ::rtl::OUString sVersion; + try + { + xStorageProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ) ) >>= sVersion; + } + catch( const uno::Exception& ) + { + // Custom Property "ODFVersion" does not exist + } + + if ( sVersion.getLength() ) + { + double nVersion = sVersion.toDouble(); + if ( nVersion > 1.20001 && SfxObjectShell_Impl::NeedsOfficeUpdateDialog() ) + // ODF version greater than 1.2 - added some decimal places to be safe against floating point conversion errors (hack) + { + ::rtl::OUString sDocumentURL( pMedium->GetOrigURL() ); + ::rtl::OUString aSystemFileURL; + if ( osl::FileBase::getSystemPathFromFileURL( sDocumentURL, aSystemFileURL ) == osl::FileBase::E_None ) + sDocumentURL = aSystemFileURL; + + FutureDocumentVersionProductUpdateRequest aUpdateRequest; + aUpdateRequest.Classification = InteractionClassification_QUERY; + aUpdateRequest.DocumentURL = sDocumentURL; + + ::rtl::Reference< ::comphelper::OInteractionRequest > pRequest = new ::comphelper::OInteractionRequest( makeAny( aUpdateRequest ) ); + pRequest->addContinuation( new ::comphelper::OInteractionApprove ); + pRequest->addContinuation( new ::comphelper::OInteractionAbort ); + + typedef ::comphelper::OInteraction< XInteractionAskLater > OInteractionAskLater; + OInteractionAskLater* pLater = new OInteractionAskLater; + pRequest->addContinuation( pLater ); + + try + { + xHandler->handle( pRequest.get() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + if ( pLater->wasSelected() ) + SFX_APP()->Get_Impl()->bODFVersionWarningLater = true; + } + } + } + } + } + else + GetpApp()->HideStatusText(); + + return bOk; +} + +sal_uInt32 SfxObjectShell::HandleFilter( SfxMedium* pMedium, SfxObjectShell* pDoc ) +{ + sal_uInt32 nError = ERRCODE_NONE; + SfxItemSet* pSet = pMedium->GetItemSet(); + SFX_ITEMSET_ARG( pSet, pOptions, SfxStringItem, SID_FILE_FILTEROPTIONS, sal_False ); + SFX_ITEMSET_ARG( pSet, pData, SfxUnoAnyItem, SID_FILTER_DATA, sal_False ); + if ( !pData && !pOptions ) + { + com::sun::star::uno::Reference< XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory(); + com::sun::star::uno::Reference< XNameAccess > xFilterCFG; + if( xServiceManager.is() ) + { + xFilterCFG = com::sun::star::uno::Reference< XNameAccess >( + xServiceManager->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ), + UNO_QUERY ); + } + + if( xFilterCFG.is() ) + { + BOOL bAbort = FALSE; + try { + const SfxFilter* pFilter = pMedium->GetFilter(); + Sequence < PropertyValue > aProps; + Any aAny = xFilterCFG->getByName( pFilter->GetName() ); + if ( aAny >>= aProps ) + { + sal_Int32 nPropertyCount = aProps.getLength(); + for( sal_Int32 nProperty=0; nProperty < nPropertyCount; ++nProperty ) + if( aProps[nProperty].Name.equals( ::rtl::OUString::createFromAscii("UIComponent")) ) + { + ::rtl::OUString aServiceName; + aProps[nProperty].Value >>= aServiceName; + if( aServiceName.getLength() ) + { + com::sun::star::uno::Reference< XInteractionHandler > rHandler = pMedium->GetInteractionHandler(); + if( rHandler.is() ) + { + // we need some properties in the media descriptor, so we have to make sure that they are in + Any aStreamAny; + aStreamAny <<= pMedium->GetInputStream(); + if ( pSet->GetItemState( SID_INPUTSTREAM ) < SFX_ITEM_SET ) + pSet->Put( SfxUnoAnyItem( SID_INPUTSTREAM, aStreamAny ) ); + if ( pSet->GetItemState( SID_FILE_NAME ) < SFX_ITEM_SET ) + pSet->Put( SfxStringItem( SID_FILE_NAME, pMedium->GetName() ) ); + if ( pSet->GetItemState( SID_FILTER_NAME ) < SFX_ITEM_SET ) + pSet->Put( SfxStringItem( SID_FILTER_NAME, pFilter->GetName() ) ); + + Sequence< PropertyValue > rProperties; + TransformItems( SID_OPENDOC, *pSet, rProperties, NULL ); + RequestFilterOptions* pFORequest = new RequestFilterOptions( pDoc->GetModel(), rProperties ); + + com::sun::star::uno::Reference< XInteractionRequest > rRequest( pFORequest ); + rHandler->handle( rRequest ); + + if ( !pFORequest->isAbort() ) + { + SfxAllItemSet aNewParams( pDoc->GetPool() ); + TransformParameters( SID_OPENDOC, + pFORequest->getFilterOptions(), + aNewParams, + NULL ); + + SFX_ITEMSET_ARG( &aNewParams, + pFilterOptions, + SfxStringItem, + SID_FILE_FILTEROPTIONS, + sal_False ); + if ( pFilterOptions ) + pSet->Put( *pFilterOptions ); + + SFX_ITEMSET_ARG( &aNewParams, + pFilterData, + SfxUnoAnyItem, + SID_FILTER_DATA, + sal_False ); + if ( pFilterData ) + pSet->Put( *pFilterData ); + } + else + bAbort = TRUE; + } + } + + break; + } + } + + if( bAbort ) + { + // filter options were not entered + nError = ERRCODE_ABORT; + } + } + catch( NoSuchElementException& ) + { + // the filter name is unknown + nError = ERRCODE_IO_INVALIDPARAMETER; + } + catch( Exception& ) + { + nError = ERRCODE_ABORT; + } + } + } + + return nError; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::IsOwnStorageFormat_Impl(const SfxMedium &rMedium) const +{ + return !rMedium.GetFilter() || // Embedded + ( rMedium.GetFilter()->IsOwnFormat() && + rMedium.GetFilter()->UsesStorage() && + rMedium.GetFilter()->GetVersion() >= SOFFICE_FILEFORMAT_60 ); +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::IsPackageStorageFormat_Impl(const SfxMedium &rMedium) const +{ + return !rMedium.GetFilter() || // Embedded + ( rMedium.GetFilter()->UsesStorage() && + rMedium.GetFilter()->GetVersion() >= SOFFICE_FILEFORMAT_60 ); +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::DoSave() +// DoSave wird nur noch ueber OLE aufgerufen. Sichern eigener Dokumente im SFX +// laeuft uber DoSave_Impl, um das Anlegen von Backups zu ermoeglichen. +// Save in eigenes Format jetzt auch wieder Hierueber +{ + sal_Bool bOk = sal_False ; + { + ModifyBlocker_Impl aBlock( this ); + + pImp->bIsSaving = sal_True; + + ::rtl::OUString aPasswd; + if ( IsPackageStorageFormat_Impl( *GetMedium() ) ) + { + if ( GetPasswd_Impl( GetMedium()->GetItemSet(), aPasswd ) ) + { + try + { + //TODO/MBA: GetOutputStorage?! Special mode, because it's "Save"?! + ::comphelper::OStorageHelper::SetCommonStoragePassword( GetMedium()->GetStorage(), aPasswd ); + bOk = sal_True; + } + catch( uno::Exception& ) + { + SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + + DBG_ASSERT( bOk, "The root storage must allow to set common password!\n" ); + } + else + bOk = sal_True; + + if ( HasBasic() ) + { + try + { + // The basic and dialogs related contents are still not able to proceed with save operation ( saveTo only ) + // so since the document storage is locked a workaround has to be used + + uno::Reference< embed::XStorage > xTmpStorage = ::comphelper::OStorageHelper::GetTemporaryStorage(); + DBG_ASSERT( xTmpStorage.is(), "If a storage can not be created an exception must be thrown!\n" ); + if ( !xTmpStorage.is() ) + throw uno::RuntimeException(); + + ::rtl::OUString aBasicStorageName( RTL_CONSTASCII_USTRINGPARAM( "Basic" ) ); + ::rtl::OUString aDialogsStorageName( RTL_CONSTASCII_USTRINGPARAM( "Dialogs" ) ); + if ( GetMedium()->GetStorage()->hasByName( aBasicStorageName ) ) + GetMedium()->GetStorage()->copyElementTo( aBasicStorageName, xTmpStorage, aBasicStorageName ); + if ( GetMedium()->GetStorage()->hasByName( aDialogsStorageName ) ) + GetMedium()->GetStorage()->copyElementTo( aDialogsStorageName, xTmpStorage, aDialogsStorageName ); + + GetBasicManager(); + + // disconnect from the current storage + pImp->pBasicManager->setStorage( xTmpStorage ); + + // store to the current storage + pImp->pBasicManager->storeLibrariesToStorage( GetMedium()->GetStorage() ); + + // connect to the current storage back + pImp->pBasicManager->setStorage( GetMedium()->GetStorage() ); + } + catch( uno::Exception& ) + { + SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + bOk = sal_False; + } + } + } + + if ( bOk ) + bOk = Save(); + + bOk = pMedium->Commit(); + } + +//#88046 +// if ( bOk ) +// SetModified( sal_False ); + return bOk; +} + +void Lock_Impl( SfxObjectShell* pDoc, BOOL bLock ) +{ + SfxViewFrame *pFrame= SfxViewFrame::GetFirst( pDoc ); + while ( pFrame ) + { + pFrame->GetDispatcher()->Lock( bLock ); + pFrame->Enable( !bLock ); + pFrame = SfxViewFrame::GetNext( *pFrame, pDoc ); + } + +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::SaveTo_Impl +( + SfxMedium &rMedium, // Medium, in das gespeichert werden soll + const SfxItemSet* pSet +) + +/* [Beschreibung] + + Schreibt den aktuellen Inhalt in das Medium rMedium. + Ist das Zielmedium kein Storage, so wird ueber ein temporaeres + Medium gespeichert, sonst direkt, da das Medium transacted + geschaltet ist, wenn wir es selbst geoeffnet haben und falls wir + Server sind entweder der Container einen transacted Storage zur + Verfuegung stellt oder selbst einen temporaeren Storage erzeugt hat. +*/ + +{ + RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "PERFORMANCE SfxObjectShell::SaveTo_Impl" ); + if( RTL_LOGFILE_HASLOGFILE() ) + { + ByteString aString( rMedium.GetName(), RTL_TEXTENCODING_ASCII_US ); + RTL_LOGFILE_PRODUCT_CONTEXT_TRACE1( aLog, "saving \"%s\"", aString.GetBuffer() ); + } + + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Begin" ) ) ); + + ModifyBlocker_Impl aMod(this); + + const SfxFilter *pFilter = rMedium.GetFilter(); + if ( !pFilter ) + { + // if no filter was set, use the default filter + // this should be changed in the feature, it should be an error! + DBG_ERROR("No filter set!"); + pFilter = GetFactory().GetFilterContainer()->GetAnyFilter( SFX_FILTER_IMPORT | SFX_FILTER_EXPORT ); + rMedium.SetFilter(pFilter); + } + + sal_Bool bStorageBasedSource = IsPackageStorageFormat_Impl( *pMedium ); + sal_Bool bStorageBasedTarget = IsPackageStorageFormat_Impl( rMedium ); + sal_Bool bOwnSource = IsOwnStorageFormat_Impl( *pMedium ); + sal_Bool bOwnTarget = IsOwnStorageFormat_Impl( rMedium ); + + // Examine target format to determine whether to query if any password + // protected libraries exceed the size we can handler + if ( bOwnTarget && !QuerySaveSizeExceededModules_Impl( rMedium.GetInteractionHandler() ) ) + { + SetError( ERRCODE_IO_ABORT, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + return sal_False; + } + + sal_Bool bNeedsDisconnectionOnFail = sal_False; + + sal_Bool bStoreToSameLocation = sal_False; + + // the detection whether the script is changed should be done before saving + sal_Bool bTryToPreserveScriptSignature = sal_False; + // no way to detect whether a filter is oasis format, have to wait for saving process + sal_Bool bNoPreserveForOasis = sal_False; + if ( bOwnSource && bOwnTarget + && ( pImp->nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_OK + || pImp->nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED + || pImp->nScriptingSignatureState == SIGNATURESTATE_SIGNATURES_INVALID ) ) + { + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "MacroSignaturePreserving" ) ) ); + + // the checking of the library modified state iterates over the libraries, should be done only when required + // currently the check is commented out since it is broken, we have to check the signature every time we save + // TODO/LATER: let isAnyContainerModified() work! + bTryToPreserveScriptSignature = sal_True; // !pImp->pBasicManager->isAnyContainerModified(); + if ( bTryToPreserveScriptSignature ) + { + // check that the storage format stays the same + SvtSaveOptions aSaveOpt; + SvtSaveOptions::ODFDefaultVersion nVersion = aSaveOpt.GetODFDefaultVersion(); + + ::rtl::OUString aODFVersion; + try + { + uno::Reference < beans::XPropertySet > xPropSet( GetStorage(), uno::UNO_QUERY_THROW ); + xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ) ) >>= aODFVersion; + } + catch( uno::Exception& ) + {} + + // preserve only if the same filter has been used + bTryToPreserveScriptSignature = pMedium->GetFilter() && pFilter && pMedium->GetFilter()->GetFilterName() == pFilter->GetFilterName(); + + bNoPreserveForOasis = ( + (aODFVersion.equals( ODFVER_012_TEXT ) && nVersion == SvtSaveOptions::ODFVER_011) || + (!aODFVersion.getLength() && nVersion >= SvtSaveOptions::ODFVER_012) + ); + } + } + + sal_Bool bCopyTo = sal_False; + SfxItemSet *pMedSet = rMedium.GetItemSet(); + if( pMedSet ) + { + SFX_ITEMSET_ARG( pMedSet, pSaveToItem, SfxBoolItem, SID_SAVETO, sal_False ); + bCopyTo = GetCreateMode() == SFX_CREATE_MODE_EMBEDDED || + (pSaveToItem && pSaveToItem->GetValue()); + } + + // use UCB for case sensitive/insensitive file name comparison + if ( pMedium + && pMedium->GetName().CompareIgnoreCaseToAscii( "private:stream", 14 ) != COMPARE_EQUAL + && rMedium.GetName().CompareIgnoreCaseToAscii( "private:stream", 14 ) != COMPARE_EQUAL + && ::utl::UCBContentHelper::EqualURLs( pMedium->GetName(), rMedium.GetName() ) ) + { + bStoreToSameLocation = sal_True; + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Save" ) ) ); + + if ( pMedium->DocNeedsFileDateCheck() ) + rMedium.CheckFileDate( pMedium->GetInitFileDate( sal_False ) ); + + if ( bCopyTo && GetCreateMode() != SFX_CREATE_MODE_EMBEDDED ) + { + // export to the same location is vorbidden + SetError( ERRCODE_IO_CANTWRITE, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + else + { + // before we overwrite the original file, we will make a backup if there is a demand for that + // if the backup is not created here it will be created internally and will be removed in case of successful saving + const sal_Bool bDoBackup = SvtSaveOptions().IsBackup(); + if ( bDoBackup ) + { + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "DoBackup" ) ) ); + rMedium.DoBackup_Impl(); + if ( rMedium.GetError() ) + { + SetError( rMedium.GetErrorCode(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + rMedium.ResetError(); + } + } + + if ( bStorageBasedSource && bStorageBasedTarget ) + { + // The active storage must be switched. The simple saving is not enough. + // The problem is that the target medium contains target MediaDescriptor. + + // In future the switch of the persistance could be done on stream level: + // a new wrapper service will be implemented that allows to exchange + // persistance on the fly. So the real persistance will be set + // to that stream only after successful commit of the storage. + // TODO/LATER: + // create wrapper stream based on the URL + // create a new storage based on this stream + // store to this new storage + // commit the new storage + // call saveCompleted based with this new storage ( get rid of old storage and "frees" URL ) + // commit the wrapper stream ( the stream will connect the URL only on commit, after that it will hold it ) + // if the last step is failed the stream should stay to be transacted and should be commited on any flush + // so we can forget the stream in any way and the next storage commit will flush it + + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Save: Own to Own" ) ) ); + + bNeedsDisconnectionOnFail = DisconnectStorage_Impl( + *pMedium, rMedium ); + if ( bNeedsDisconnectionOnFail + || ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) ) + { + pMedium->CloseAndRelease(); + + // TODO/LATER: for now the medium must be closed since it can already contain streams from old medium + // in future those streams should not be copied in case a valid target url is provided, + // if the url is not provided ( means the document is based on a stream ) this code is not + // reachable. + rMedium.CloseAndRelease(); + rMedium.GetOutputStorage(); + } + } + else if ( !bStorageBasedSource && !bStorageBasedTarget ) + { + // the source and the target formats are alien + // just disconnect the stream from the source format + // so that the target medium can use it + + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Save: Alien to Alien" ) ) ); + + pMedium->CloseAndRelease(); + rMedium.CloseAndRelease(); + rMedium.CreateTempFileNoCopy(); + rMedium.GetOutStream(); + } + else if ( !bStorageBasedSource && bStorageBasedTarget ) + { + // the source format is an alien one but the target + // format is an own one so just disconnect the source + // medium + + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Save: Alien to Own" ) ) ); + + pMedium->CloseAndRelease(); + rMedium.CloseAndRelease(); + rMedium.GetOutputStorage(); + } + else // means if ( bStorageBasedSource && !bStorageBasedTarget ) + { + // the source format is an own one but the target is + // an alien format, just connect the source to temporary + // storage + + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Save: Own to Alien" ) ) ); + + bNeedsDisconnectionOnFail = DisconnectStorage_Impl( + *pMedium, rMedium ); + if ( bNeedsDisconnectionOnFail + || ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) ) + { + pMedium->CloseAndRelease(); + rMedium.CloseAndRelease(); + rMedium.CreateTempFileNoCopy(); + rMedium.GetOutStream(); + } + } + } + } + else + { + // This is SaveAs or export action, prepare the target medium + // the alien filters still might write directly to the file, that is of course a bug, + // but for now the framework has to be ready for it + // TODO/LATER: let the medium be prepared for alien formats as well + + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "SaveAs/Export" ) ) ); + + rMedium.CloseAndRelease(); + if ( bStorageBasedTarget ) + { + rMedium.GetOutputStorage(); + } + } + + // TODO/LATER: error handling + if( rMedium.GetErrorCode() || pMedium->GetErrorCode() || GetErrorCode() ) + return sal_False; + + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Locking" ) ) ); + + rMedium.LockOrigFileOnDemand( sal_False, sal_False ); + + if ( bStorageBasedTarget ) + { + if ( rMedium.GetErrorCode() ) + return sal_False; + + // If the filter is a "cross export" filter ( f.e. a filter for exporting an impress document from + // a draw document ), the ClassId of the destination storage is different from the ClassId of this + // document. It can be retrieved from the default filter for the desired target format + long nFormat = rMedium.GetFilter()->GetFormat(); + SfxFilterMatcher& rMatcher = SFX_APP()->GetFilterMatcher(); + const SfxFilter *pFilt = rMatcher.GetFilter4ClipBoardId( nFormat ); + if ( pFilt ) + { + if ( pFilt->GetServiceName() != rMedium.GetFilter()->GetServiceName() ) + { + datatransfer::DataFlavor aDataFlavor; + SotExchange::GetFormatDataFlavor( nFormat, aDataFlavor ); + + try + { + uno::Reference< beans::XPropertySet > xProps( rMedium.GetStorage(), uno::UNO_QUERY ); + DBG_ASSERT( xProps.is(), "The storage implementation must implement XPropertySet!" ); + if ( !xProps.is() ) + throw uno::RuntimeException(); + + xProps->setPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ), + uno::makeAny( aDataFlavor.MimeType ) ); + } + catch( uno::Exception& ) + { + } + } + } + } + + // TODO/LATER: error handling + if( rMedium.GetErrorCode() || pMedium->GetErrorCode() || GetErrorCode() ) + return sal_False; + + sal_Bool bOldStat = pImp->bForbidReload; + pImp->bForbidReload = sal_True; + + // lock user interface while saving the document + Lock_Impl( this, sal_True ); + + sal_Bool bOk = sal_False; + // TODO/LATER: get rid of bOk + + if( bOwnTarget && !( pFilter->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) ) + { + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Storing in own format." ) ) ); + uno::Reference< embed::XStorage > xMedStorage = rMedium.GetStorage(); + if ( !xMedStorage.is() ) + { + // no saving without storage, unlock UI and return + Lock_Impl( this, sal_False ); + pImp->bForbidReload = bOldStat; + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Storing failed, still no error set." ) ) ); + return sal_False; + } + + // transfer password from the parameters to the storage + ::rtl::OUString aPasswd; + sal_Bool bPasswdProvided = sal_False; + if ( GetPasswd_Impl( rMedium.GetItemSet(), aPasswd ) ) + { + bPasswdProvided = sal_True; + try { + ::comphelper::OStorageHelper::SetCommonStoragePassword( xMedStorage, aPasswd ); + bOk = sal_True; + } + catch( uno::Exception& ) + { + DBG_ERROR( "Setting of common encryption key failed!" ); + SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + } + else + bOk = sal_True; + + pFilter = rMedium.GetFilter(); + + const SfxStringItem *pVersionItem = pSet ? (const SfxStringItem*) + SfxRequest::GetItem( pSet, SID_DOCINFO_COMMENTS, sal_False, TYPE(SfxStringItem) ) : NULL; + ::rtl::OUString aTmpVersionURL; + + if ( bOk ) + { + bOk = sal_False; + // currently the case that the storage is the same should be impossible + if ( xMedStorage == GetStorage() ) + { + OSL_ENSURE( !pVersionItem, "This scenario is impossible currently!\n" ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Should be impossible." ) ) ); + // usual save procedure + bOk = Save(); + } + else + { + // save to target + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Save as own format." ) ) ); + bOk = SaveAsOwnFormat( rMedium ); + if ( bOk && pVersionItem ) + { + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "pVersionItem != NULL" ) ) ); + aTmpVersionURL = CreateTempCopyOfStorage_Impl( xMedStorage ); + bOk = ( aTmpVersionURL.getLength() > 0 ); + } + } + } + + + if ( bOk && GetCreateMode() != SFX_CREATE_MODE_EMBEDDED && !bPasswdProvided ) + { + // store the thumbnail representation image + // the thumbnail is not stored in case of encrypted document + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Thumbnail creation." ) ) ); + if ( !GenerateAndStoreThumbnail( bPasswdProvided, + sal_False, + pFilter->IsOwnTemplateFormat(), + xMedStorage ) ) + { + // TODO: error handling + OSL_ENSURE( sal_False, "Couldn't store thumbnail representation!" ); + } + } + + if ( bOk ) + { + if ( pImp->bIsSaving || pImp->bPreserveVersions ) + { + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Preserve versions." ) ) ); + try + { + Sequence < util::RevisionTag > aVersions = rMedium.GetVersionList(); + if ( aVersions.getLength() ) + { + // copy the version streams + ::rtl::OUString aVersionsName( RTL_CONSTASCII_USTRINGPARAM( "Versions" ) ); + uno::Reference< embed::XStorage > xNewVerStor = xMedStorage->openStorageElement( + aVersionsName, + embed::ElementModes::READWRITE ); + uno::Reference< embed::XStorage > xOldVerStor = GetStorage()->openStorageElement( + aVersionsName, + embed::ElementModes::READ ); + if ( !xNewVerStor.is() || !xOldVerStor.is() ) + throw uno::RuntimeException(); + + for ( sal_Int32 n=0; n<aVersions.getLength(); n++ ) + { + if ( xOldVerStor->hasByName( aVersions[n].Identifier ) ) + xOldVerStor->copyElementTo( aVersions[n].Identifier, xNewVerStor, aVersions[n].Identifier ); + } + + uno::Reference< embed::XTransactedObject > xTransact( xNewVerStor, uno::UNO_QUERY ); + if ( xTransact.is() ) + xTransact->commit(); + } + } + catch( uno::Exception& ) + { + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Preserve versions has failed." ) ) ); + DBG_ERROR( "Couldn't copy versions!\n" ); + bOk = sal_False; + // TODO/LATER: a specific error could be set + } + } + + if ( bOk && pVersionItem ) + { + // store a version also + const SfxStringItem *pAuthorItem = pSet ? (const SfxStringItem*) + SfxRequest::GetItem( pSet, SID_DOCINFO_AUTHOR, sal_False, TYPE(SfxStringItem) ) : NULL; + + // version comment + util::RevisionTag aInfo; + aInfo.Comment = pVersionItem->GetValue(); + + // version author + String aAuthor; + if ( pAuthorItem ) + aInfo.Author = pAuthorItem->GetValue(); + else + // if not transferred as a parameter, get it from user settings + aInfo.Author = SvtUserOptions().GetFullName(); + + DateTime aTime; + aInfo.TimeStamp.Day = aTime.GetDay(); + aInfo.TimeStamp.Month = aTime.GetMonth(); + aInfo.TimeStamp.Year = aTime.GetYear(); + aInfo.TimeStamp.Hours = aTime.GetHour(); + aInfo.TimeStamp.Minutes = aTime.GetMin(); + aInfo.TimeStamp.Seconds = aTime.GetSec(); + + if ( bOk ) + { + // add new version information into the versionlist and save the versionlist + // the version list must have been transferred from the "old" medium before + rMedium.AddVersion_Impl( aInfo ); + rMedium.SaveVersionList_Impl( sal_True ); + bOk = PutURLContentsToVersionStream_Impl( aTmpVersionURL, xMedStorage, aInfo.Identifier ); + } + } + else if ( bOk && ( pImp->bIsSaving || pImp->bPreserveVersions ) ) + { + rMedium.SaveVersionList_Impl( sal_True ); + } + } + + if ( aTmpVersionURL.getLength() ) + ::utl::UCBContentHelper::Kill( aTmpVersionURL ); + } + else + { + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Storing in alien format." ) ) ); + // it's a "SaveAs" in an alien format + if ( rMedium.GetFilter() && ( rMedium.GetFilter()->GetFilterFlags() & SFX_FILTER_STARONEFILTER ) ) + bOk = ExportTo( rMedium ); + else + bOk = ConvertTo( rMedium ); + + // after saving the document, the temporary object storage must be updated + // if the old object storage was not a temporary one, it will be updated also, because it will be used + // as a source for copying the objects into the new temporary storage that will be created below + // updating means: all child objects must be stored into it + // ( same as on loading, where these objects are copied to the temporary storage ) + // but don't commit these changes, because in the case when the old object storage is not a temporary one, + // all changes will be written into the original file ! + + if( bOk && !bCopyTo ) + // we also don't touch any graphical replacements here + bOk = SaveChildren( TRUE ); + } + + if ( bOk ) + { + // if ODF version of oasis format changes on saving the signature should not be preserved + if ( bOk && bTryToPreserveScriptSignature && bNoPreserveForOasis ) + bTryToPreserveScriptSignature = ( SotStorage::GetVersion( rMedium.GetStorage() ) == SOFFICE_FILEFORMAT_60 ); + + uno::Reference< security::XDocumentDigitalSignatures > xDDSigns; + if ( bOk && bTryToPreserveScriptSignature ) + { + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Copying scripting signature." ) ) ); + + // if the scripting code was not changed and it is signed the signature should be preserved + // unfortunately at this point we have only information whether the basic code has changed or not + // so the only way is to check the signature if the basic was not changed + try + { + // get the ODF version of the new medium + uno::Sequence< uno::Any > aArgs( 1 ); + aArgs[0] <<= ::rtl::OUString(); + try + { + uno::Reference < beans::XPropertySet > xPropSet( rMedium.GetStorage(), uno::UNO_QUERY_THROW ); + aArgs[0] = xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ) ); + } + catch( uno::Exception& ) + { + } + + xDDSigns = uno::Reference< security::XDocumentDigitalSignatures >( + comphelper::getProcessServiceFactory()->createInstanceWithArguments( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.security.DocumentDigitalSignatures" ) ), + aArgs ), + uno::UNO_QUERY_THROW ); + + ::rtl::OUString aScriptSignName = xDDSigns->getScriptingContentSignatureDefaultStreamName(); + + if ( aScriptSignName.getLength() ) + { + pMedium->Close(); + + // target medium is still not commited, it should not be closed + // commit the package storage and close it, but leave the streams open + rMedium.StorageCommit_Impl(); + rMedium.CloseStorage(); + + uno::Reference< embed::XStorage > xReadOrig = pMedium->GetZipStorageToSign_Impl(); + if ( !xReadOrig.is() ) + throw uno::RuntimeException(); + uno::Reference< embed::XStorage > xMetaInf = xReadOrig->openStorageElement( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "META-INF" ) ), + embed::ElementModes::READ ); + + uno::Reference< embed::XStorage > xTarget = rMedium.GetZipStorageToSign_Impl( sal_False ); + if ( !xTarget.is() ) + throw uno::RuntimeException(); + uno::Reference< embed::XStorage > xTargetMetaInf = xTarget->openStorageElement( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "META-INF" ) ), + embed::ElementModes::READWRITE ); + + if ( xMetaInf.is() && xTargetMetaInf.is() ) + { + xMetaInf->copyElementTo( aScriptSignName, xTargetMetaInf, aScriptSignName ); + + uno::Reference< embed::XTransactedObject > xTransact( xTargetMetaInf, uno::UNO_QUERY ); + if ( xTransact.is() ) + xTransact->commit(); + + xTargetMetaInf->dispose(); + + // now check the copied signature + uno::Sequence< security::DocumentSignatureInformation > aInfos = + xDDSigns->verifyScriptingContentSignatures( xTarget, + uno::Reference< io::XInputStream >() ); + sal_uInt16 nState = ImplCheckSignaturesInformation( aInfos ); + if ( nState == SIGNATURESTATE_SIGNATURES_OK || nState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED + || nState == SIGNATURESTATE_SIGNATURES_PARTIAL_OK) + { + rMedium.SetCachedSignatureState_Impl( nState ); + + // commit the ZipStorage from target medium + xTransact.set( xTarget, uno::UNO_QUERY ); + if ( xTransact.is() ) + xTransact->commit(); + } + else + { + // it should not happen, the copies signature is invalid! + // throw the changes away + OSL_ASSERT( "An invalid signature was copied!" ); + } + } + } + } + catch( uno::Exception& ) + { + } + + pMedium->Close(); + rMedium.CloseZipStorage_Impl(); + } + + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Medium commit." ) ) ); + + // transfer data to its destinated location + // the medium commits the storage or the stream it is based on + RegisterTransfer( rMedium ); + bOk = rMedium.Commit(); + + if ( bOk ) + { + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Storing is successful." ) ) ); + + // if the target medium is an alien format and the "old" medium was an own format and the "old" medium + // has a name, the object storage must be exchanged, because now we need a new temporary storage + // as object storage + if ( !bCopyTo && bStorageBasedSource && !bStorageBasedTarget ) + { + if ( bStoreToSameLocation ) + { + // if the old medium already disconnected from document storage, the storage still must + // be switched if backup file is used + if ( bNeedsDisconnectionOnFail ) + ConnectTmpStorage_Impl( pImp->m_xDocStorage, NULL ); + } + else if ( pMedium->GetName().Len() + || ( pMedium->HasStorage_Impl() && pMedium->WillDisposeStorageOnClose_Impl() ) ) + { + OSL_ENSURE( pMedium->GetName().Len(), "Fallback is used, the medium without name should not dispose the storage!\n" ); + // copy storage of old medium to new temporary storage and take this over + if( !ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) ) + { + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Process after storing has failed." ) ) ); + bOk = sal_False; + } + } + } + } + else + { + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Storing has failed." ) ) ); + + // in case the document storage was connected to backup temporarely it must be disconnected now + if ( bNeedsDisconnectionOnFail ) + ConnectTmpStorage_Impl( pImp->m_xDocStorage, NULL ); + } + } + + // unlock user interface + Lock_Impl( this, sal_False ); + pImp->bForbidReload = bOldStat; + + if ( bOk ) + { + try + { + ::ucbhelper::Content aContent( rMedium.GetName(), com::sun::star::uno::Reference < XCommandEnvironment >() ); + com::sun::star::uno::Reference < XPropertySetInfo > xProps = aContent.getProperties(); + if ( xProps.is() ) + { + ::rtl::OUString aAuthor( RTL_CONSTASCII_USTRINGPARAM("Author") ); + ::rtl::OUString aKeywords( RTL_CONSTASCII_USTRINGPARAM("Keywords") ); + ::rtl::OUString aSubject( RTL_CONSTASCII_USTRINGPARAM("Subject") ); + Any aAny; + + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps + = xDPS->getDocumentProperties(); + + if ( xProps->hasPropertyByName( aAuthor ) ) + { + aAny <<= xDocProps->getAuthor(); + aContent.setPropertyValue( aAuthor, aAny ); + } + if ( xProps->hasPropertyByName( aKeywords ) ) + { + aAny <<= ::comphelper::string::convertCommaSeparated( + xDocProps->getKeywords()); + aContent.setPropertyValue( aKeywords, aAny ); + } + if ( xProps->hasPropertyByName( aSubject ) ) + { + aAny <<= xDocProps->getSubject(); + aContent.setPropertyValue( aSubject, aAny ); + } + } + } + catch( Exception& ) + { + } + +#ifdef OS2 + { +#define CHAR_POINTER(THE_OUSTRING) ::rtl::OUStringToOString (THE_OUSTRING, RTL_TEXTENCODING_UTF8).pData->buffer + // Header for a single-valued ASCII EA data item + typedef struct _EA_ASCII_header { + USHORT usAttr; /* value: EAT_ASCII */ + USHORT usLen; /* length of data */ + CHAR szType[_MAX_PATH]; /* ASCII data fits in here ... */ + } EA_ASCII_HEADER; + char filePath[_MAX_PATH]; + char fileExt[_MAX_PATH]; + char docType[_MAX_PATH]; + int rc; + oslFileError eRet; + ::rtl::OUString aSystemFileURL; + const ::rtl::OUString aFileURL = rMedium.GetName(); + // close medium + rMedium.Close(); + + // convert file URL to system path + if (osl::FileBase::getSystemPathFromFileURL( aFileURL, aSystemFileURL) == osl::FileBase::E_None) { + EA_ASCII_HEADER eaAscii; + struct _ea eaType; + strcpy( filePath, CHAR_POINTER( aSystemFileURL)); + strcpy( docType, CHAR_POINTER( rMedium.GetFilter()->GetServiceName())); +#if OSL_DEBUG_LEVEL>1 + printf( "file name: %s\n", filePath); + printf( "filter name: %s\n", CHAR_POINTER(rMedium.GetFilter()->GetFilterName())); + printf( "service name: %s\n", docType); +#endif + // initialize OS/2 EA data structure + eaAscii.usAttr = EAT_ASCII; + _splitpath ( filePath, NULL, NULL, NULL, fileExt); + if (!stricmp( fileExt, ".pdf")) + strcpy( eaAscii.szType, "Acrobat Document"); + else if (!strcmp( docType, "com.sun.star.text.TextDocument")) + strcpy( eaAscii.szType, "OpenOfficeOrg Writer Document"); + else if (!strcmp( docType, "com.sun.star.sheet.SpreadsheetDocument")) + strcpy( eaAscii.szType, "OpenOfficeOrg Calc Document"); + else if (!strcmp( docType, "com.sun.star.presentation.PresentationDocument")) + strcpy( eaAscii.szType, "OpenOfficeOrg Impress Document"); + else if (!strcmp( docType, "com.sun.star.drawing.DrawingDocument")) + strcpy( eaAscii.szType, "OpenOfficeOrg Draw Document"); + else + strcpy( eaAscii.szType, "OpenOfficeOrg Document"); + eaAscii.usLen = strlen( eaAscii.szType); + // fill libc EA data structure + eaType.flags = 0; + eaType.size = sizeof(USHORT)*2 + eaAscii.usLen; + eaType.value = &eaAscii; + // put EA to file + rc = _ea_put( &eaType, filePath, 0, ".TYPE"); +#if OSL_DEBUG_LEVEL>1 + printf( "ea name: %s, rc %d, errno %d\n", eaAscii.szType, rc, errno); +#endif + } + } +#endif + + } + + return bOk; +} + +//------------------------------------------------------------------------ +sal_Bool SfxObjectShell::DisconnectStorage_Impl( SfxMedium& rSrcMedium, SfxMedium& rTargetMedium ) +{ + RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::DisconnectStorage_Impl" ); + + // this method disconnects the storage from source medium, and attaches it to the backup created by the target medium + + uno::Reference< embed::XStorage > xStorage = rSrcMedium.GetStorage(); + + sal_Bool bResult = sal_False; + if ( xStorage == pImp->m_xDocStorage ) + { + try + { + uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY_THROW ); + ::rtl::OUString aBackupURL = rTargetMedium.GetBackup_Impl(); + if ( !aBackupURL.getLength() ) + { + // the backup could not be created, try to disconnect the storage and close the source SfxMedium + // in this case the optimization is not possible, connect storage to a temporary file + rTargetMedium.ResetError(); + xOptStorage->writeAndAttachToStream( uno::Reference< io::XStream >() ); + rSrcMedium.CanDisposeStorage_Impl( sal_False ); + rSrcMedium.Close(); + + // now try to create the backup + rTargetMedium.GetBackup_Impl(); + } + else + { + // the following call will only compare stream sizes + // TODO/LATER: this is a very risky part, since if the URL contents are different from the storage + // contents, the storag will be broken + xOptStorage->attachToURL( aBackupURL, sal_True ); + + // the storage is successfuly attached to backup, thus it it owned by the document not by the medium + rSrcMedium.CanDisposeStorage_Impl( sal_False ); + bResult = sal_True; + } + } + catch ( uno::Exception& ) + {} + } + + OSL_ENSURE( bResult, "Storage disconnecting has failed - affects performance!" ); + + return bResult; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxObjectShell::ConnectTmpStorage_Impl( + const uno::Reference< embed::XStorage >& xStorage, + SfxMedium* pMediumArg ) + +/* [Beschreibung] + + Arbeitet die Applikation auf einem temporaeren Storage, + so darf der temporaere Storage nicht aus dem SaveCompleted + genommen werden. Daher wird in diesem Fall schon hier an + den neuen Storage connected. SaveCompleted tut dann nichts. + + */ + +{ + RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::ConnectTmpStorage_Impl" ); + + sal_Bool bResult = sal_False; + + if ( xStorage.is() ) + { + try + { + // the empty argument means that the storage will create temporary stream itself + uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY_THROW ); + xOptStorage->writeAndAttachToStream( uno::Reference< io::XStream >() ); + + // the storage is successfuly disconnected from the original sources, thus the medium must not dispose it + if ( pMediumArg ) + pMediumArg->CanDisposeStorage_Impl( sal_False ); + + bResult = sal_True; + } + catch( uno::Exception& ) + { + } + + // if switching of the storage does not work for any reason ( nonroot storage for example ) use the old method + if ( !bResult ) try + { + uno::Reference< embed::XStorage > xTmpStorage = ::comphelper::OStorageHelper::GetTemporaryStorage(); + + DBG_ASSERT( xTmpStorage.is(), "If a storage can not be created an exception must be thrown!\n" ); + if ( !xTmpStorage.is() ) + throw uno::RuntimeException(); + + // TODO/LATER: may be it should be done in SwitchPersistence also + // TODO/LATER: find faster way to copy storage; perhaps sharing with backup?! + xStorage->copyToStorage( xTmpStorage ); + //CopyStoragesOfUnknownMediaType( xStorage, xTmpStorage ); + bResult = SaveCompleted( xTmpStorage ); + + if ( bResult ) + { + pImp->pBasicManager->setStorage( xTmpStorage ); + + // Get rid of this workaround after issue i113914 is fixed + try + { + uno::Reference< script::XStorageBasedLibraryContainer > xBasicLibraries( pImp->xBasicLibraries, uno::UNO_QUERY_THROW ); + xBasicLibraries->setRootStorage( xTmpStorage ); + } + catch( uno::Exception& ) + {} + try + { + uno::Reference< script::XStorageBasedLibraryContainer > xDialogLibraries( pImp->xDialogLibraries, uno::UNO_QUERY_THROW ); + xDialogLibraries->setRootStorage( xTmpStorage ); + } + catch( uno::Exception& ) + {} + } + } + catch( uno::Exception& ) + {} + + if ( !bResult ) + { + // TODO/LATER: may need error code setting based on exception + SetError( ERRCODE_IO_GENERAL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + } + + return bResult; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::DoSaveObjectAs( SfxMedium& rMedium, BOOL bCommit ) +{ + sal_Bool bOk = sal_False; + { + ModifyBlocker_Impl aBlock( this ); + + uno::Reference < embed::XStorage > xNewStor = rMedium.GetStorage(); + if ( !xNewStor.is() ) + return sal_False; + + uno::Reference < beans::XPropertySet > xPropSet( xNewStor, uno::UNO_QUERY ); + if ( xPropSet.is() ) + { + Any a = xPropSet->getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ) ); + ::rtl::OUString aMediaType; + if ( !(a>>=aMediaType) || !aMediaType.getLength() ) + { + OSL_ENSURE( sal_False, "The mediatype must be set already!\n" ); + SetupStorage( xNewStor, SOFFICE_FILEFORMAT_CURRENT, sal_False ); + } + + pImp->bIsSaving = sal_False; + bOk = SaveAsOwnFormat( rMedium ); + + if ( bCommit ) + { + try { + uno::Reference< embed::XTransactedObject > xTransact( xNewStor, uno::UNO_QUERY_THROW ); + xTransact->commit(); + } + catch( uno::Exception& ) + { + DBG_ERROR( "The strotage was not commited on DoSaveAs!\n" ); + } + } + } + } + + return bOk; +} + +//------------------------------------------------------------------------- +// TODO/LATER: may be the call must be removed completelly +sal_Bool SfxObjectShell::DoSaveAs( SfxMedium& rMedium ) +{ + // hier kommen nur Root-Storages rein, die via Temp-File gespeichert werden + rMedium.CreateTempFileNoCopy(); + SetError(rMedium.GetErrorCode(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + if ( GetError() ) + return sal_False; + + // copy version list from "old" medium to target medium, so it can be used on saving + if ( pImp->bPreserveVersions ) + rMedium.TransferVersionList_Impl( *pMedium ); + + sal_Bool bRet = SaveTo_Impl( rMedium, NULL ); + if ( !bRet ) + SetError(rMedium.GetErrorCode(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + return bRet; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::DoSaveCompleted( SfxMedium* pNewMed ) +{ + RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::DoSaveCompleted" ); + + sal_Bool bOk = sal_True; + sal_Bool bMedChanged = pNewMed && pNewMed!=pMedium; +/* sal_Bool bCreatedTempStor = pNewMed && pMedium && + IsPackageStorageFormat_Impl(*pMedium) && + !IsPackageStorageFormat_Impl(*pNewMed) && + pMedium->GetName().Len(); +*/ + DBG_ASSERT( !pNewMed || pNewMed->GetError() == ERRCODE_NONE, "DoSaveCompleted: Medium has error!" ); + + // delete Medium (and Storage!) after all notifications + SfxMedium* pOld = pMedium; + if ( bMedChanged ) + { + pMedium = pNewMed; + pMedium->CanDisposeStorage_Impl( sal_True ); + } + + const SfxFilter *pFilter = pMedium ? pMedium->GetFilter() : 0; + if ( pNewMed ) + { + if( bMedChanged ) + { + if( pNewMed->GetName().Len() ) + bHasName = sal_True; + Broadcast( SfxSimpleHint(SFX_HINT_NAMECHANGED) ); + getDocProperties()->setGenerator( + ::utl::DocInfoHelper::GetGeneratorString() ); + } + + uno::Reference< embed::XStorage > xStorage; + if ( !pFilter || IsPackageStorageFormat_Impl( *pMedium ) ) + { + uno::Reference < embed::XStorage > xOld = GetStorage(); + + // when the package based medium is broken and has no storage or if the storage + // is the same as the document storage the current document storage should be preserved + xStorage = pMedium->GetStorage(); + bOk = SaveCompleted( xStorage ); + if ( bOk && xStorage.is() && xOld != xStorage + && (!pOld || !pOld->HasStorage_Impl() || xOld != pOld->GetStorage() ) ) + { + // old own storage was not controlled by old Medium -> dispose it + try { + xOld->dispose(); + } catch( uno::Exception& ) + { + // the storage is disposed already + // can happen during reload scenario when the medium has disposed it during the closing + // will be fixed in one of the next milestones + } + } + } + else + { + if( pMedium->GetOpenMode() & STREAM_WRITE ) + pMedium->GetInStream(); + xStorage = GetStorage(); + } + + // TODO/LATER: may be this code will be replaced, but not sure + // Set storage in document library containers + pImp->pBasicManager->setStorage( xStorage ); + + // Get rid of this workaround after issue i113914 is fixed + try + { + uno::Reference< script::XStorageBasedLibraryContainer > xBasicLibraries( pImp->xBasicLibraries, uno::UNO_QUERY_THROW ); + xBasicLibraries->setRootStorage( xStorage ); + } + catch( uno::Exception& ) + {} + try + { + uno::Reference< script::XStorageBasedLibraryContainer > xDialogLibraries( pImp->xDialogLibraries, uno::UNO_QUERY_THROW ); + xDialogLibraries->setRootStorage( xStorage ); + } + catch( uno::Exception& ) + {} + } + else + { + if( pMedium ) + { + if( pFilter && !IsPackageStorageFormat_Impl( *pMedium ) && (pMedium->GetOpenMode() & STREAM_WRITE )) + { + pMedium->ReOpen(); + bOk = SaveCompletedChildren( sal_False ); + } + else + bOk = SaveCompleted( NULL ); + } + // entweder Save oder ConvertTo + else + bOk = SaveCompleted( NULL ); + } + + if ( bOk && pNewMed ) + { + if( bMedChanged ) + { + delete pOld; + + uno::Reference< frame::XModel > xModel = GetModel(); + if ( xModel.is() ) + { + ::rtl::OUString aURL = pNewMed->GetOrigURL(); + uno::Sequence< beans::PropertyValue > aMediaDescr; + TransformItems( SID_OPENDOC, *pNewMed->GetItemSet(), aMediaDescr ); + try + { + xModel->attachResource( aURL, aMediaDescr ); + } + catch( uno::Exception& ) + {} + } + + // before the title regenerated the document must loose the signatures + pImp->nDocumentSignatureState = SIGNATURESTATE_NOSIGNATURES; + pImp->nScriptingSignatureState = pNewMed->GetCachedSignatureState_Impl(); + OSL_ENSURE( pImp->nScriptingSignatureState != SIGNATURESTATE_SIGNATURES_BROKEN, "The signature must not be broken at this place" ); + pImp->bSignatureErrorIsShown = sal_False; + + // TODO/LATER: in future the medium must control own signature state, not the document + pNewMed->SetCachedSignatureState_Impl( SIGNATURESTATE_NOSIGNATURES ); // set the default value back + + // Titel neu setzen + if ( pNewMed->GetName().Len() && SFX_CREATE_MODE_EMBEDDED != eCreateMode ) + InvalidateName(); + SetModified(sal_False); // nur bei gesetztem Medium zur"ucksetzen + Broadcast( SfxSimpleHint(SFX_HINT_MODECHANGED) ); + + // this is the end of the saving process, it is possible that the file was changed + // between medium commit and this step ( attributes change and so on ) + // so get the file date again + if ( pNewMed->DocNeedsFileDateCheck() ) + pNewMed->GetInitFileDate( sal_True ); + } + } + + pMedium->ClearBackup_Impl(); + pMedium->LockOrigFileOnDemand( sal_True, sal_False ); + + return bOk; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::ConvertFrom +( + SfxMedium& /*rMedium*/ /* <SfxMedium>, welches die Quell-Datei beschreibt + (z.B. Dateiname, <SfxFilter>, Open-Modi etc.) */ +) + +/* [Beschreibung] + + Diese Methode wird zum Laden von Dokumenten "uber alle Filter gerufen, + die nicht SFX_FILTER_OWN sind oder f"ur die kein Clipboard-Format + registriert wurde (also kein Storage-Format benutzen). Mit anderen Worten: + mit dieser Methode wird importiert. + + Das hier zu "offende File sollte "uber 'rMedium' ge"offnet werden, + um die richtigen Open-Modi zu gew"ahrleisten. Insbesondere wenn das + Format beibehalten wird (nur m"oglich bei SFX_FILTER_SIMULATE oder + SFX_FILTER_ONW) mu\s die Datei STREAM_SHARE_DENYWRITE ge"offnet werden. + + + [R"uckgabewert] + + sal_Bool sal_True + Das Dokument konnte geladen werden. + + sal_False + Das Dokument konnte nicht geladen werden, ein + Fehlercode ist mit <SvMedium::GetError()const> zu + erhalten. + + + [Beispiel] + + sal_Bool DocSh::ConvertFrom( SfxMedium &rMedium ) + { + SvStreamRef xStream = rMedium.GetInStream(); + if( xStream.is() ) + { + xStream->SetBufferSize(4096); + *xStream >> ...; + + // NICHT 'rMedium.CloseInStream()' rufen! File gelockt halten! + return SVSTREAM_OK == rMedium.GetError(); + } + + return sal_False; + } + + + [Querverweise] + + <SfxObjectShell::ConvertTo(SfxMedium&)> + <SFX_FILTER_REGISTRATION> +*/ +{ + return sal_False; +} + +sal_Bool SfxObjectShell::InsertFrom( SfxMedium& rMedium ) +{ + ::rtl::OUString aTypeName( rMedium.GetFilter()->GetTypeName() ); + ::rtl::OUString aFilterName( rMedium.GetFilter()->GetFilterName() ); + + uno::Reference< lang::XMultiServiceFactory > xMan = ::comphelper::getProcessServiceFactory(); + uno::Reference < lang::XMultiServiceFactory > xFilterFact ( + xMan->createInstance( DEFINE_CONST_UNICODE( "com.sun.star.document.FilterFactory" ) ), uno::UNO_QUERY ); + + uno::Sequence < beans::PropertyValue > aProps; + uno::Reference < container::XNameAccess > xFilters ( xFilterFact, uno::UNO_QUERY ); + if ( xFilters->hasByName( aFilterName ) ) + { + xFilters->getByName( aFilterName ) >>= aProps; + rMedium.GetItemSet()->Put( SfxStringItem( SID_FILTER_NAME, aFilterName ) ); + } + + ::rtl::OUString aFilterImplName; + sal_Int32 nFilterProps = aProps.getLength(); + for ( sal_Int32 nFilterProp = 0; nFilterProp<nFilterProps; nFilterProp++ ) + { + const beans::PropertyValue& rFilterProp = aProps[nFilterProp]; + if ( rFilterProp.Name.compareToAscii("FilterService") == COMPARE_EQUAL ) + { + rFilterProp.Value >>= aFilterImplName; + break; + } + } + + uno::Reference< document::XFilter > xLoader; + if ( aFilterImplName.getLength() ) + { + try{ + xLoader = uno::Reference< document::XFilter > + ( xFilterFact->createInstanceWithArguments( aFilterName, uno::Sequence < uno::Any >() ), uno::UNO_QUERY ); + }catch(const uno::Exception&) + { xLoader.clear(); } + } + if ( xLoader.is() ) + { + // #131744#: it happens that xLoader does not support xImporter! + try{ + uno::Reference< lang::XComponent > xComp( GetModel(), uno::UNO_QUERY_THROW ); + uno::Reference< document::XImporter > xImporter( xLoader, uno::UNO_QUERY_THROW ); + xImporter->setTargetDocument( xComp ); + + uno::Sequence < beans::PropertyValue > lDescriptor; + rMedium.GetItemSet()->Put( SfxStringItem( SID_FILE_NAME, rMedium.GetName() ) ); + TransformItems( SID_OPENDOC, *rMedium.GetItemSet(), lDescriptor ); + + com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aArgs ( lDescriptor.getLength() ); + com::sun::star::beans::PropertyValue * pNewValue = aArgs.getArray(); + const com::sun::star::beans::PropertyValue * pOldValue = lDescriptor.getConstArray(); + const OUString sInputStream ( RTL_CONSTASCII_USTRINGPARAM ( "InputStream" ) ); + + sal_Bool bHasInputStream = sal_False; + BOOL bHasBaseURL = FALSE; + sal_Int32 i; + sal_Int32 nEnd = lDescriptor.getLength(); + + for ( i = 0; i < nEnd; i++ ) + { + pNewValue[i] = pOldValue[i]; + if ( pOldValue [i].Name == sInputStream ) + bHasInputStream = sal_True; + else if ( pOldValue[i].Name.equalsAsciiL ( RTL_CONSTASCII_STRINGPARAM ( "DocumentBaseURL" ) ) ) + bHasBaseURL = sal_True; + } + + if ( !bHasInputStream ) + { + aArgs.realloc ( ++nEnd ); + aArgs[nEnd-1].Name = sInputStream; + aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XInputStream > ( new utl::OSeekableInputStreamWrapper ( *rMedium.GetInStream() ) ); + } + + if ( !bHasBaseURL ) + { + aArgs.realloc ( ++nEnd ); + aArgs[nEnd-1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "DocumentBaseURL" ) ); + aArgs[nEnd-1].Value <<= rMedium.GetBaseURL(); + } + + aArgs.realloc( ++nEnd ); + aArgs[nEnd-1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "InsertMode" ) ); + aArgs[nEnd-1].Value <<= (sal_Bool) sal_True; + + return xLoader->filter( aArgs ); + }catch(const uno::Exception&) + {} + } + + return sal_False; +} + +sal_Bool SfxObjectShell::ImportFrom( SfxMedium& rMedium ) +{ + ::rtl::OUString aTypeName( rMedium.GetFilter()->GetTypeName() ); + ::rtl::OUString aFilterName( rMedium.GetFilter()->GetFilterName() ); + + uno::Reference< lang::XMultiServiceFactory > xMan = ::comphelper::getProcessServiceFactory(); + uno::Reference < lang::XMultiServiceFactory > xFilterFact ( + xMan->createInstance( DEFINE_CONST_UNICODE( "com.sun.star.document.FilterFactory" ) ), uno::UNO_QUERY ); + + uno::Sequence < beans::PropertyValue > aProps; + uno::Reference < container::XNameAccess > xFilters ( xFilterFact, uno::UNO_QUERY ); + if ( xFilters->hasByName( aFilterName ) ) + { + xFilters->getByName( aFilterName ) >>= aProps; + rMedium.GetItemSet()->Put( SfxStringItem( SID_FILTER_NAME, aFilterName ) ); + } + + ::rtl::OUString aFilterImplName; + sal_Int32 nFilterProps = aProps.getLength(); + for ( sal_Int32 nFilterProp = 0; nFilterProp<nFilterProps; nFilterProp++ ) + { + const beans::PropertyValue& rFilterProp = aProps[nFilterProp]; + if ( rFilterProp.Name.compareToAscii("FilterService") == COMPARE_EQUAL ) + { + rFilterProp.Value >>= aFilterImplName; + break; + } + } + + uno::Reference< document::XFilter > xLoader; + if ( aFilterImplName.getLength() ) + { + try{ + xLoader = uno::Reference< document::XFilter > + ( xFilterFact->createInstanceWithArguments( aFilterName, uno::Sequence < uno::Any >() ), uno::UNO_QUERY ); + }catch(const uno::Exception&) + { xLoader.clear(); } + } + if ( xLoader.is() ) + { + // #131744#: it happens that xLoader does not support xImporter! + try{ + uno::Reference< lang::XComponent > xComp( GetModel(), uno::UNO_QUERY_THROW ); + uno::Reference< document::XImporter > xImporter( xLoader, uno::UNO_QUERY_THROW ); + xImporter->setTargetDocument( xComp ); + + uno::Sequence < beans::PropertyValue > lDescriptor; + rMedium.GetItemSet()->Put( SfxStringItem( SID_FILE_NAME, rMedium.GetName() ) ); + TransformItems( SID_OPENDOC, *rMedium.GetItemSet(), lDescriptor ); + + com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aArgs ( lDescriptor.getLength() ); + com::sun::star::beans::PropertyValue * pNewValue = aArgs.getArray(); + const com::sun::star::beans::PropertyValue * pOldValue = lDescriptor.getConstArray(); + const OUString sInputStream ( RTL_CONSTASCII_USTRINGPARAM ( "InputStream" ) ); + + sal_Bool bHasInputStream = sal_False; + BOOL bHasBaseURL = FALSE; + sal_Int32 i; + sal_Int32 nEnd = lDescriptor.getLength(); + + for ( i = 0; i < nEnd; i++ ) + { + pNewValue[i] = pOldValue[i]; + if ( pOldValue [i].Name == sInputStream ) + bHasInputStream = sal_True; + else if ( pOldValue[i].Name.equalsAsciiL ( RTL_CONSTASCII_STRINGPARAM ( "DocumentBaseURL" ) ) ) + bHasBaseURL = sal_True; + } + + if ( !bHasInputStream ) + { + aArgs.realloc ( ++nEnd ); + aArgs[nEnd-1].Name = sInputStream; + aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XInputStream > ( new utl::OSeekableInputStreamWrapper ( *rMedium.GetInStream() ) ); + } + + if ( !bHasBaseURL ) + { + aArgs.realloc ( ++nEnd ); + aArgs[nEnd-1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "DocumentBaseURL" ) ); + aArgs[nEnd-1].Value <<= rMedium.GetBaseURL(); + } + + return xLoader->filter( aArgs ); + }catch(const uno::Exception&) + {} + } + + return sal_False; +} + +sal_Bool SfxObjectShell::ExportTo( SfxMedium& rMedium ) +{ + ::rtl::OUString aTypeName( rMedium.GetFilter()->GetTypeName() ); + ::rtl::OUString aFilterName( rMedium.GetFilter()->GetFilterName() ); + uno::Reference< document::XExporter > xExporter; + + { + uno::Reference< lang::XMultiServiceFactory > xMan = ::comphelper::getProcessServiceFactory(); + uno::Reference < lang::XMultiServiceFactory > xFilterFact ( + xMan->createInstance( DEFINE_CONST_UNICODE( "com.sun.star.document.FilterFactory" ) ), uno::UNO_QUERY ); + + uno::Sequence < beans::PropertyValue > aProps; + uno::Reference < container::XNameAccess > xFilters ( xFilterFact, uno::UNO_QUERY ); + if ( xFilters->hasByName( aFilterName ) ) + xFilters->getByName( aFilterName ) >>= aProps; + + ::rtl::OUString aFilterImplName; + sal_Int32 nFilterProps = aProps.getLength(); + for ( sal_Int32 nFilterProp = 0; nFilterProp<nFilterProps; nFilterProp++ ) + { + const beans::PropertyValue& rFilterProp = aProps[nFilterProp]; + if ( rFilterProp.Name.compareToAscii("FilterService") == COMPARE_EQUAL ) + { + rFilterProp.Value >>= aFilterImplName; + break; + } + } + + if ( aFilterImplName.getLength() ) + { + try{ + xExporter = uno::Reference< document::XExporter > + ( xFilterFact->createInstanceWithArguments( aFilterName, uno::Sequence < uno::Any >() ), uno::UNO_QUERY ); + }catch(const uno::Exception&) + { xExporter.clear(); } + } + } + + if ( xExporter.is() ) + { + try{ + uno::Reference< lang::XComponent > xComp( GetModel(), uno::UNO_QUERY_THROW ); + uno::Reference< document::XFilter > xFilter( xExporter, uno::UNO_QUERY_THROW ); + xExporter->setSourceDocument( xComp ); + + com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aOldArgs; + SfxItemSet* pItems = rMedium.GetItemSet(); + TransformItems( SID_SAVEASDOC, *pItems, aOldArgs ); + + const com::sun::star::beans::PropertyValue * pOldValue = aOldArgs.getConstArray(); + com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aArgs ( aOldArgs.getLength() ); + com::sun::star::beans::PropertyValue * pNewValue = aArgs.getArray(); + + // put in the REAL file name, and copy all PropertyValues + const OUString sOutputStream ( RTL_CONSTASCII_USTRINGPARAM ( "OutputStream" ) ); + const OUString sStream ( RTL_CONSTASCII_USTRINGPARAM ( "StreamForOutput" ) ); + BOOL bHasOutputStream = FALSE; + BOOL bHasStream = FALSE; + BOOL bHasBaseURL = FALSE; + sal_Int32 i; + sal_Int32 nEnd = aOldArgs.getLength(); + + for ( i = 0; i < nEnd; i++ ) + { + pNewValue[i] = pOldValue[i]; + if ( pOldValue[i].Name.equalsAsciiL ( RTL_CONSTASCII_STRINGPARAM ( "FileName" ) ) ) + pNewValue[i].Value <<= OUString ( rMedium.GetName() ); + else if ( pOldValue[i].Name == sOutputStream ) + bHasOutputStream = sal_True; + else if ( pOldValue[i].Name == sStream ) + bHasStream = sal_True; + else if ( pOldValue[i].Name.equalsAsciiL ( RTL_CONSTASCII_STRINGPARAM ( "DocumentBaseURL" ) ) ) + bHasBaseURL = sal_True; + } + + if ( !bHasOutputStream ) + { + aArgs.realloc ( ++nEnd ); + aArgs[nEnd-1].Name = sOutputStream; + aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XOutputStream > ( new utl::OOutputStreamWrapper ( *rMedium.GetOutStream() ) ); + } + + // add stream as well, for OOX export and maybe others + if ( !bHasStream ) + { + aArgs.realloc ( ++nEnd ); + aArgs[nEnd-1].Name = sStream; + aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XStream > ( new utl::OStreamWrapper ( *rMedium.GetOutStream() ) ); + } + + if ( !bHasBaseURL ) + { + aArgs.realloc ( ++nEnd ); + aArgs[nEnd-1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "DocumentBaseURL" ) ); + aArgs[nEnd-1].Value <<= rMedium.GetBaseURL( sal_True ); + } + + return xFilter->filter( aArgs ); + }catch(const uno::Exception&) + {} + } + + return sal_False; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::ConvertTo +( + SfxMedium& /*rMedium*/ /* <SfxMedium>, welches die Ziel-Datei beschreibt + (z.B. Dateiname, <SfxFilter>, Open-Modi etc.) */ +) + +/* [Beschreibung] + + Diese Methode wird zum Speichern von Dokumenten "uber alle Filter gerufen, + die nicht SFX_FILTER_OWN sind oder f"ur die kein Clipboard-Format + registriert wurde (also kein Storage-Format benutzen). Mit anderen Worten: + mit dieser Methode wird exportiert. + + Das hier zu "offende File sollte "uber 'rMedium' ge"offnet werden, + um die richtigen Open-Modi zu gew"ahrleisten. Insbesondere wenn das + Format beibehalten wird (nur m"oglich bei SFX_FILTER_SIMULATE oder + SFX_FILTER_ONW) mu\s die Datei auch nach dem Speichern im Modus + STREAM_SHARE_DENYWRITE ge"offnet bleiben. + + + [R"uckgabewert] + + sal_Bool sal_True + Das Dokument konnte gespeichert werden. + + sal_False + Das Dokument konnte nicht gespeichert werden, ein + Fehlercode ist mit <SvMedium::GetError()const> zu + erhalten. + + + [Beispiel] + + sal_Bool DocSh::ConvertTo( SfxMedium &rMedium ) + { + SvStreamRef xStream = rMedium.GetOutStream(); + if ( xStream.is() ) + { + xStream->SetBufferSize(4096); + *xStream << ...; + + rMedium.CloseOutStream(); // "offnet automatisch wieder den InStream + return SVSTREAM_OK == rMedium.GetError(); + } + return sal_False ; + } + + + [Querverweise] + + <SfxObjectShell::ConvertFrom(SfxMedium&)> + <SFX_FILTER_REGISTRATION> +*/ + +{ + return sal_False; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::DoSave_Impl( const SfxItemSet* pArgs ) +{ + SfxMedium* pRetrMedium = GetMedium(); + const SfxFilter* pFilter = pRetrMedium->GetFilter(); + + // copy the original itemset, but remove the "version" item, because pMediumTmp + // is a new medium "from scratch", so no version should be stored into it + SfxItemSet* pSet = new SfxAllItemSet(*pRetrMedium->GetItemSet()); + pSet->ClearItem( SID_VERSION ); + pSet->ClearItem( SID_DOC_BASEURL ); + + // create a medium as a copy; this medium is only for writingm, because it uses the same name as the original one + // writing is done through a copy, that will be transferred to the target ( of course after calling HandsOff ) + SfxMedium* pMediumTmp = new SfxMedium( pRetrMedium->GetName(), pRetrMedium->GetOpenMode(), pRetrMedium->IsDirect(), pFilter, pSet ); + pMediumTmp->SetLongName( pRetrMedium->GetLongName() ); +// pMediumTmp->CreateTempFileNoCopy(); + if ( pMediumTmp->GetErrorCode() != ERRCODE_NONE ) + { + SetError( pMediumTmp->GetError(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + delete pMediumTmp; + return sal_False; + } + + // copy version list from "old" medium to target medium, so it can be used on saving + pMediumTmp->TransferVersionList_Impl( *pRetrMedium ); +/* + if ( pFilter && ( pFilter->GetFilterFlags() & SFX_FILTER_PACKED ) ) + SetError( GetMedium()->Unpack_Impl( pRetrMedium->GetPhysicalName() ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); +*/ + + // an interaction handler here can aquire only in case of GUI Saving + // and should be removed after the saving is done + com::sun::star::uno::Reference< XInteractionHandler > xInteract; + SFX_ITEMSET_ARG( pArgs, pxInteractionItem, SfxUnoAnyItem, SID_INTERACTIONHANDLER, sal_False ); + if ( pxInteractionItem && ( pxInteractionItem->GetValue() >>= xInteract ) && xInteract.is() ) + pMediumTmp->GetItemSet()->Put( SfxUnoAnyItem( SID_INTERACTIONHANDLER, makeAny( xInteract ) ) ); + + sal_Bool bSaved = sal_False; + if( !GetError() && SaveTo_Impl( *pMediumTmp, pArgs ) ) + { + bSaved = sal_True; + + if( pMediumTmp->GetItemSet() ) + { + pMediumTmp->GetItemSet()->ClearItem( SID_INTERACTIONHANDLER ); + pMediumTmp->GetItemSet()->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL ); + } + + SetError(pMediumTmp->GetErrorCode(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + + sal_Bool bOpen( sal_False ); + bOpen = DoSaveCompleted( pMediumTmp ); + DBG_ASSERT(bOpen,"Fehlerbehandlung fuer DoSaveCompleted nicht implementiert"); + } + else + { + // transfer error code from medium to objectshell + SetError( pMediumTmp->GetError(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + + // reconnect to object storage + DoSaveCompleted( 0 ); + + if( pRetrMedium->GetItemSet() ) + { + pRetrMedium->GetItemSet()->ClearItem( SID_INTERACTIONHANDLER ); + pRetrMedium->GetItemSet()->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL ); + } + + delete pMediumTmp; + } + + SetModified( !bSaved ); + return bSaved; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::Save_Impl( const SfxItemSet* pSet ) +{ + if ( IsReadOnly() ) + { + SetError( ERRCODE_SFX_DOCUMENTREADONLY, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + return sal_False; + } + + DBG_CHKTHIS(SfxObjectShell, 0); + + pImp->bIsSaving = sal_True; + sal_Bool bSaved = FALSE; + SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False); + if ( pSalvageItem ) + { + SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False); + String aFilterName; + const SfxFilter *pFilter = NULL; + if ( pFilterItem ) + pFilter = SfxFilterMatcher( String::CreateFromAscii( GetFactory().GetShortName()) ).GetFilter4FilterName( aFilterName ); + + SfxMedium *pMed = new SfxMedium( + pSalvageItem->GetValue(), STREAM_READWRITE | STREAM_SHARE_DENYWRITE | STREAM_TRUNC, sal_False, pFilter ); + + SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pPasswordItem, SfxStringItem, SID_PASSWORD, sal_False ); + if ( pPasswordItem ) + pMed->GetItemSet()->Put( *pPasswordItem ); + + bSaved = DoSaveAs( *pMed ); + if ( bSaved ) + bSaved = DoSaveCompleted( pMed ); + else + delete pMed; + } + else + bSaved = DoSave_Impl( pSet ); + return bSaved; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::CommonSaveAs_Impl +( + const INetURLObject& aURL, + const String& aFilterName, + SfxItemSet* aParams +) +{ + if( aURL.HasError() ) + { + SetError( ERRCODE_IO_INVALIDPARAMETER, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + return sal_False; + } + + if ( aURL != INetURLObject( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:stream" ) ) ) ) + { + // gibt es schon ein Doc mit dem Namen? + SfxObjectShell* pDoc = 0; + for ( SfxObjectShell* pTmp = SfxObjectShell::GetFirst(); + pTmp && !pDoc; + pTmp = SfxObjectShell::GetNext(*pTmp) ) + { + if( ( pTmp != this ) && pTmp->GetMedium() ) + { + INetURLObject aCompare( pTmp->GetMedium()->GetName() ); + if ( aCompare == aURL ) + pDoc = pTmp; + } + } + if ( pDoc ) + { + // dann Fehlermeldeung: "schon offen" + SetError(ERRCODE_SFX_ALREADYOPEN, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + return sal_False; + } + } + + DBG_ASSERT( aURL.GetProtocol() != INET_PROT_NOT_VALID, "Illegal URL!" ); + DBG_ASSERT( aParams->Count() != 0, "fehlerhafte Parameter"); + + SFX_ITEMSET_ARG( aParams, pSaveToItem, SfxBoolItem, SID_SAVETO, sal_False ); + sal_Bool bSaveTo = pSaveToItem ? pSaveToItem->GetValue() : sal_False; + + const SfxFilter* pFilter = GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName ); + if ( !pFilter + || !pFilter->CanExport() + || (!bSaveTo && !pFilter->CanImport()) ) + { + SetError( ERRCODE_IO_INVALIDPARAMETER, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + return sal_False; + } + + SFX_ITEMSET_ARG( aParams, pCopyStreamItem, SfxBoolItem, SID_COPY_STREAM_IF_POSSIBLE, sal_False ); + if ( bSaveTo && pCopyStreamItem && pCopyStreamItem->GetValue() && !IsModified() ) + { + if ( pMedium->TryDirectTransfer( aURL.GetMainURL( INetURLObject::NO_DECODE ), *aParams ) ) + return sal_True; + } + aParams->ClearItem( SID_COPY_STREAM_IF_POSSIBLE ); + + pImp->bPasswd = aParams && SFX_ITEM_SET == aParams->GetItemState(SID_PASSWORD); + + SfxMedium *pActMed = GetMedium(); + const INetURLObject aActName(pActMed->GetName()); + + BOOL bWasReadonly = IsReadOnly(); + + if ( aURL == aActName && aURL != INetURLObject( OUString::createFromAscii( "private:stream" ) ) + && IsReadOnly() ) + { + SetError(ERRCODE_SFX_DOCUMENTREADONLY, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + return sal_False; + } + + // this notification should be already sent by caller in sfxbasemodel + // SFX_APP()->NotifyEvent(SfxEventHint( bSaveTo? SFX_EVENT_SAVETODOC : SFX_EVENT_SAVEASDOC,this)); + + if( SFX_ITEM_SET != aParams->GetItemState(SID_UNPACK) && SvtSaveOptions().IsSaveUnpacked() ) + aParams->Put( SfxBoolItem( SID_UNPACK, sal_False ) ); + + ::rtl::OUString aTempFileURL; + if ( IsDocShared() ) + aTempFileURL = pMedium->GetURLObject().GetMainURL( INetURLObject::NO_DECODE ); + + if ( PreDoSaveAs_Impl(aURL.GetMainURL( INetURLObject::NO_DECODE ),aFilterName,aParams)) + { + pImp->bWaitingForPicklist = sal_True; + + // Daten am Medium updaten + SfxItemSet *pSet = GetMedium()->GetItemSet(); + pSet->ClearItem( SID_INTERACTIONHANDLER ); + pSet->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL ); + pSet->ClearItem( SID_STANDARD_DIR ); + pSet->ClearItem( SID_PATH ); + + if ( !bSaveTo ) + { + pSet->ClearItem( SID_REFERER ); + pSet->ClearItem( SID_POSTDATA ); + pSet->ClearItem( SID_TEMPLATE ); + pSet->ClearItem( SID_DOC_READONLY ); + pSet->ClearItem( SID_CONTENTTYPE ); + pSet->ClearItem( SID_CHARSET ); + pSet->ClearItem( SID_FILTER_NAME ); + pSet->ClearItem( SID_OPTIONS ); + //pSet->ClearItem( SID_FILE_FILTEROPTIONS ); + pSet->ClearItem( SID_VERSION ); + pSet->ClearItem( SID_EDITDOC ); + pSet->ClearItem( SID_OVERWRITE ); + pSet->ClearItem( SID_DEFAULTFILEPATH ); + pSet->ClearItem( SID_DEFAULTFILENAME ); + + SFX_ITEMSET_GET( (*aParams), pFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False ); + if ( pFilterItem ) + pSet->Put( *pFilterItem ); + + SFX_ITEMSET_GET( (*aParams), pOptionsItem, SfxStringItem, SID_OPTIONS, sal_False ); + if ( pOptionsItem ) + pSet->Put( *pOptionsItem ); + + SFX_ITEMSET_GET( (*aParams), pFilterOptItem, SfxStringItem, SID_FILE_FILTEROPTIONS, sal_False ); + if ( pFilterOptItem ) + pSet->Put( *pFilterOptItem ); + + if ( IsDocShared() && aTempFileURL.getLength() ) + { + // this is a shared document that has to be disconnected from the old location + FreeSharedFile( aTempFileURL ); + + if ( pFilter->IsOwnFormat() + && pFilter->UsesStorage() + && pFilter->GetVersion() >= SOFFICE_FILEFORMAT_60 ) + { + // the target format is the own format + // the target document must be shared + SwitchToShared( sal_True, sal_False ); + } + } + } + + if ( bWasReadonly && !bSaveTo ) + Broadcast( SfxSimpleHint(SFX_HINT_MODECHANGED) ); + + return sal_True; + } + else + return sal_False; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::PreDoSaveAs_Impl +( + const String& rFileName, + const String& aFilterName, + SfxItemSet* pParams +) +{ + // copy all items stored in the itemset of the current medium + SfxAllItemSet* pMergedParams = new SfxAllItemSet( *pMedium->GetItemSet() ); + + // in "SaveAs" title and password will be cleared ( maybe the new itemset contains new values, otherwise they will be empty ) + pMergedParams->ClearItem( SID_PASSWORD ); + pMergedParams->ClearItem( SID_DOCINFO_TITLE ); + + pMergedParams->ClearItem( SID_INPUTSTREAM ); + pMergedParams->ClearItem( SID_STREAM ); + pMergedParams->ClearItem( SID_CONTENT ); + pMergedParams->ClearItem( SID_DOC_READONLY ); + pMergedParams->ClearItem( SID_DOC_BASEURL ); + + pMergedParams->ClearItem( SID_REPAIRPACKAGE ); + + // "SaveAs" will never store any version information - it's a complete new file ! + pMergedParams->ClearItem( SID_VERSION ); + + // merge the new parameters into the copy + // all values present in both itemsets will be overwritten by the new parameters + if( pParams ) + pMergedParams->Put( *pParams ); + //DELETEZ( pParams ); + +#ifdef DBG_UTIL + if ( pMergedParams->GetItemState( SID_DOC_SALVAGE) >= SFX_ITEM_SET ) + DBG_ERROR("Salvage item present in Itemset, check the parameters!"); +#endif + + // should be unneccessary - too hot to handle! + pMergedParams->ClearItem( SID_DOC_SALVAGE ); + + // take over the new merged itemset + pParams = pMergedParams; + + // create a medium for the target URL + SfxMedium *pNewFile = new SfxMedium( rFileName, STREAM_READWRITE | STREAM_SHARE_DENYWRITE | STREAM_TRUNC, sal_False, 0, pParams ); + + // set filter; if no filter is given, take the default filter of the factory + if ( aFilterName.Len() ) + pNewFile->SetFilter( GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName ) ); + else + pNewFile->SetFilter( GetFactory().GetFilterContainer()->GetAnyFilter( SFX_FILTER_IMPORT | SFX_FILTER_EXPORT ) ); + + if ( pNewFile->GetErrorCode() != ERRCODE_NONE ) + { + // creating temporary file failed ( f.e. floppy disk not inserted! ) + SetError( pNewFile->GetError(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + delete pNewFile; + return sal_False; + } + + // check if a "SaveTo" is wanted, no "SaveAs" + SFX_ITEMSET_ARG( pParams, pSaveToItem, SfxBoolItem, SID_SAVETO, sal_False ); + sal_Bool bCopyTo = GetCreateMode() == SFX_CREATE_MODE_EMBEDDED || (pSaveToItem && pSaveToItem->GetValue()); + + // distinguish between "Save" and "SaveAs" + pImp->bIsSaving = sal_False; + + // copy version list from "old" medium to target medium, so it can be used on saving + if ( pImp->bPreserveVersions ) + pNewFile->TransferVersionList_Impl( *pMedium ); + +/* + if ( GetMedium()->GetFilter() && ( GetMedium()->GetFilter()->GetFilterFlags() & SFX_FILTER_PACKED ) ) + { + SfxMedium *pMed = bCopyTo ? pMedium : pNewFile; + pNewFile->SetError( GetMedium()->Unpack_Impl( pMed->GetPhysicalName() ) , ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } +*/ + // Save the document ( first as temporary file, then transfer to the target URL by committing the medium ) + sal_Bool bOk = sal_False; + if ( !pNewFile->GetErrorCode() && SaveTo_Impl( *pNewFile, NULL ) ) + { + bOk = sal_True; + + // transfer a possible error from the medium to the document + SetError( pNewFile->GetErrorCode(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + + // notify the document that saving was done successfully + if ( !bCopyTo ) + { + bOk = DoSaveCompleted( pNewFile ); + } + else + bOk = DoSaveCompleted(0); + + if( bOk ) + { + if( !bCopyTo ) + SetModified( sal_False ); + } + else + { + // TODO/LATER: the code below must be dead since the storage commit makes all the stuff + // and the DoSaveCompleted call should not be able to fail in general + + DBG_ASSERT( !bCopyTo, "Error while reconnecting to medium, can't be handled!"); + SetError( pNewFile->GetErrorCode(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + + if ( !bCopyTo ) + { + // reconnect to the old medium + BOOL bRet( FALSE ); + bRet = DoSaveCompleted( pMedium ); + DBG_ASSERT( bRet, "Error in DoSaveCompleted, can't be handled!"); + } + + // TODO/LATER: disconnect the new file from the storage for the case when pure saving is done + // if storing has corrupted the file, probably it must be restored either here or + // by the storage + DELETEZ( pNewFile ); + } + } + else + { + SetError( pNewFile->GetErrorCode(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + + // reconnect to the old storage + DoSaveCompleted( 0 ); + + DELETEZ( pNewFile ); + } + + if ( bCopyTo ) + DELETEZ( pNewFile ); + else if( !bOk ) + SetModified( sal_True ); + + return bOk; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxObjectShell::LoadFrom( SfxMedium& /*rMedium*/ ) +{ + DBG_ERROR( "Base implementation, must not be called in general!" ); + return sal_True; +} + +//------------------------------------------------------------------------- +sal_Bool SfxObjectShell::IsInformationLost() +{ + Sequence< PropertyValue > aProps = GetModel()->getArgs(); + ::rtl::OUString aFilterName; + ::rtl::OUString aPreusedFilterName; + for ( sal_Int32 nInd = 0; nInd < aProps.getLength(); nInd++ ) + { + if ( aProps[nInd].Name.equalsAscii( "FilterName" ) ) + aProps[nInd].Value >>= aFilterName; + else if ( aProps[nInd].Name.equalsAscii( "PreusedFilterName" ) ) + aProps[nInd].Value >>= aPreusedFilterName; + } + + // if current filter can lead to information loss and it was used + // for the latest store then the user should be asked to store in own format + if ( aFilterName.getLength() && aFilterName.equals( aPreusedFilterName ) ) + { + const SfxFilter *pFilt = GetMedium()->GetFilter(); + DBG_ASSERT( pFilt && aFilterName.equals( pFilt->GetName() ), "MediaDescriptor contains wrong filter!\n" ); + return ( pFilt && pFilt->IsAlienFormat() && !(pFilt->GetFilterFlags() & SFX_FILTER_SILENTEXPORT ) ); + } + + return sal_False; +} + +//------------------------------------------------------------------------- +sal_Bool SfxObjectShell::CanReload_Impl() + +/* [Beschreibung] + + Interne Methode zum Feststellen, ob eine erneutes Laden des + Dokuments (auch als RevertToSaved oder LastVersion bekannt) + m"oglich ist. +*/ + +{ + return pMedium && HasName() && !IsInModalMode() && !pImp->bForbidReload; +} + +//------------------------------------------------------------------------- + +sal_uInt16 SfxObjectShell::GetHiddenInformationState( sal_uInt16 nStates ) +{ + sal_uInt16 nState = 0; + if ( nStates & HIDDENINFORMATION_DOCUMENTVERSIONS ) + { + if ( GetMedium()->GetVersionList().getLength() ) + nState |= HIDDENINFORMATION_DOCUMENTVERSIONS; + } + + return nState; +} + +sal_Int16 SfxObjectShell::QueryHiddenInformation( HiddenWarningFact eFact, Window* pParent ) +{ + sal_Int16 nRet = RET_YES; + USHORT nResId = 0; + SvtSecurityOptions::EOption eOption = static_cast< SvtSecurityOptions::EOption >( -1 ); + + switch ( eFact ) + { + case WhenSaving : + { + nResId = STR_HIDDENINFO_CONTINUE_SAVING; + eOption = SvtSecurityOptions::E_DOCWARN_SAVEORSEND; + break; + } + case WhenPrinting : + { + nResId = STR_HIDDENINFO_CONTINUE_PRINTING; + eOption = SvtSecurityOptions::E_DOCWARN_PRINT; + break; + } + case WhenSigning : + { + nResId = STR_HIDDENINFO_CONTINUE_SIGNING; + eOption = SvtSecurityOptions::E_DOCWARN_SIGNING; + break; + } + case WhenCreatingPDF : + { + nResId = STR_HIDDENINFO_CONTINUE_CREATEPDF; + eOption = SvtSecurityOptions::E_DOCWARN_CREATEPDF; + break; + } + default: + { + DBG_ERRORFILE( "SfxObjectShell::DetectHiddenInformation(): what fact?" ); + } + } + + if ( eOption != -1 && SvtSecurityOptions().IsOptionSet( eOption ) ) + { + String sMessage( SfxResId( STR_HIDDENINFO_CONTAINS ) ); + sal_uInt16 nWantedStates = HIDDENINFORMATION_RECORDEDCHANGES | HIDDENINFORMATION_NOTES; + if ( eFact != WhenPrinting ) + nWantedStates |= HIDDENINFORMATION_DOCUMENTVERSIONS; + sal_uInt16 nStates = GetHiddenInformationState( nWantedStates ); + bool bWarning = false; + + if ( ( nStates & HIDDENINFORMATION_RECORDEDCHANGES ) == HIDDENINFORMATION_RECORDEDCHANGES ) + { + sMessage += String( SfxResId( STR_HIDDENINFO_RECORDCHANGES ) ); + sMessage += '\n'; + bWarning = true; + } + if ( ( nStates & HIDDENINFORMATION_NOTES ) == HIDDENINFORMATION_NOTES ) + { + sMessage += String( SfxResId( STR_HIDDENINFO_NOTES ) ); + sMessage += '\n'; + bWarning = true; + } + if ( ( nStates & HIDDENINFORMATION_DOCUMENTVERSIONS ) == HIDDENINFORMATION_DOCUMENTVERSIONS ) + { + sMessage += String( SfxResId( STR_HIDDENINFO_DOCVERSIONS ) ); + sMessage += '\n'; + bWarning = true; + } + + if ( bWarning ) + { + sMessage += '\n'; + sMessage += String( SfxResId( nResId ) ); + WarningBox aWBox( pParent, WB_YES_NO | WB_DEF_NO, sMessage ); + nRet = aWBox.Execute(); + } + } + + return nRet; +} + +sal_Bool SfxObjectShell::HasSecurityOptOpenReadOnly() const +{ + return sal_True; +} + +sal_Bool SfxObjectShell::IsSecurityOptOpenReadOnly() const +{ + return IsLoadReadonly(); +} + +void SfxObjectShell::SetSecurityOptOpenReadOnly( sal_Bool _b ) +{ + SetLoadReadonly( _b ); +} + +sal_Bool SfxObjectShell::LoadOwnFormat( SfxMedium& rMedium ) +{ + RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "PERFORMANCE SfxObjectShell::LoadOwnFormat" ); + if( RTL_LOGFILE_HASLOGFILE() ) + { + ByteString aString( rMedium.GetName(), RTL_TEXTENCODING_ASCII_US ); + RTL_LOGFILE_PRODUCT_CONTEXT_TRACE1( aLog, "loading \"%s\"", aString.GetBuffer() ); + } + + uno::Reference< embed::XStorage > xStorage = rMedium.GetStorage(); + if ( xStorage.is() ) + { + // Password + SFX_ITEMSET_ARG( rMedium.GetItemSet(), pPasswdItem, SfxStringItem, SID_PASSWORD, sal_False ); + if ( pPasswdItem || ERRCODE_IO_ABORT != CheckPasswd_Impl( this, SFX_APP()->GetPool(), pMedium ) ) + { + ::rtl::OUString aPasswd; + if ( GetPasswd_Impl(pMedium->GetItemSet(), aPasswd) ) + { + try + { + // the following code must throw an exception in case of failure + ::comphelper::OStorageHelper::SetCommonStoragePassword( xStorage, aPasswd ); + } + catch( uno::Exception& ) + { + // TODO/LATER: handle the error code + } + } + + // load document + return Load( rMedium ); + } + return sal_False; + } + else + return sal_False; +} + +sal_Bool SfxObjectShell::SaveAsOwnFormat( SfxMedium& rMedium ) +{ + uno::Reference< embed::XStorage > xStorage = rMedium.GetStorage(); + if( xStorage.is() ) + { + sal_Int32 nVersion = rMedium.GetFilter()->GetVersion(); + + // OASIS templates have own mediatypes ( SO7 also actually, but it is to late to use them here ) + sal_Bool bTemplate = ( rMedium.GetFilter()->IsOwnTemplateFormat() && nVersion > SOFFICE_FILEFORMAT_60 ); + + SetupStorage( xStorage, nVersion, bTemplate ); + + if ( HasBasic() ) + { + // Initialize Basic + GetBasicManager(); + + // Save dialog/script container + pImp->pBasicManager->storeLibrariesToStorage( xStorage ); + } + + return SaveAs( rMedium ); + } + else return sal_False; +} + +uno::Reference< embed::XStorage > SfxObjectShell::GetStorage() +{ + if ( !pImp->m_xDocStorage.is() ) + { + OSL_ENSURE( pImp->m_bCreateTempStor, "The storage must exist already!\n" ); + try { + // no notification is required the storage is set the first time + pImp->m_xDocStorage = ::comphelper::OStorageHelper::GetTemporaryStorage(); + OSL_ENSURE( pImp->m_xDocStorage.is(), "The method must either return storage or throw an exception!" ); + + SetupStorage( pImp->m_xDocStorage, SOFFICE_FILEFORMAT_CURRENT, sal_False ); + pImp->m_bCreateTempStor = sal_False; + SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_STORAGECHANGED, GlobalEventConfig::GetEventName(STR_EVENT_STORAGECHANGED), this ) ); + } + catch( uno::Exception& ) + { + // TODO/LATER: error handling? + } + } + + OSL_ENSURE( pImp->m_xDocStorage.is(), "The document storage must be created!" ); + return pImp->m_xDocStorage; +} + + +sal_Bool SfxObjectShell::SaveChildren( BOOL bObjectsOnly ) +{ + RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveChildren" ); + + sal_Bool bResult = sal_True; + if ( pImp->mpObjectContainer ) + { + sal_Bool bOasis = ( SotStorage::GetVersion( GetStorage() ) > SOFFICE_FILEFORMAT_60 ); + GetEmbeddedObjectContainer().StoreChildren(bOasis,bObjectsOnly); + } + + return bResult; +} + +sal_Bool SfxObjectShell::SaveAsChildren( SfxMedium& rMedium ) +{ + RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveAsChildren" ); + + sal_Bool bResult = sal_True; + + uno::Reference < embed::XStorage > xStorage = rMedium.GetStorage(); + if ( !xStorage.is() ) + return sal_False; + + if ( xStorage == GetStorage() ) + return SaveChildren(); + + sal_Bool bOasis = sal_True; + if ( pImp->mpObjectContainer ) + { + bOasis = ( SotStorage::GetVersion( xStorage ) > SOFFICE_FILEFORMAT_60 ); + GetEmbeddedObjectContainer().StoreAsChildren(bOasis,SFX_CREATE_MODE_EMBEDDED == eCreateMode,xStorage); + } + + if ( bResult ) + bResult = CopyStoragesOfUnknownMediaType( GetStorage(), xStorage ); + + return bResult; +} + +sal_Bool SfxObjectShell::SaveCompletedChildren( sal_Bool bSuccess ) +{ + RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveCompletedChildren" ); + + sal_Bool bResult = sal_True; + + if ( pImp->mpObjectContainer ) + { + uno::Sequence < ::rtl::OUString > aNames = GetEmbeddedObjectContainer().GetObjectNames(); + for ( sal_Int32 n=0; n<aNames.getLength(); n++ ) + { + uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObjectContainer().GetEmbeddedObject( aNames[n] ); + OSL_ENSURE( xObj.is(), "An empty entry in the embedded objects list!\n" ); + if ( xObj.is() ) + { + uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); + if ( xPersist.is() ) + { + try + { + xPersist->saveCompleted( bSuccess ); + } + catch( uno::Exception& ) + { + // TODO/LATER: error handling + bResult = sal_False; + break; + } + } + } + } + } + + return bResult; +} + +sal_Bool SfxObjectShell::SwitchChildrenPersistance( const uno::Reference< embed::XStorage >& xStorage, + sal_Bool bForceNonModified ) +{ + RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SwitchChildrenPersistence" ); + + if ( !xStorage.is() ) + { + // TODO/LATER: error handling + return sal_False; + } + + sal_Bool bResult = sal_True; + + if ( pImp->mpObjectContainer ) + pImp->mpObjectContainer->SetPersistentEntries(xStorage,bForceNonModified); + + return bResult; +} + +// Never call this method directly, always use the DoSaveCompleted call +sal_Bool SfxObjectShell::SaveCompleted( const uno::Reference< embed::XStorage >& xStorage ) +{ + RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveCompleted" ); + + sal_Bool bResult = sal_False; + sal_Bool bSendNotification = sal_False; + uno::Reference< embed::XStorage > xOldStorageHolder; + +#ifdef DBG_UTIL + // check for wrong creation of object container + BOOL bHasContainer = ( pImp->mpObjectContainer != 0 ); +#endif + + if ( !xStorage.is() || xStorage == GetStorage() ) + { + // no persistence change + bResult = SaveCompletedChildren( sal_False ); + } + else + { + if ( pImp->mpObjectContainer ) + GetEmbeddedObjectContainer().SwitchPersistence( xStorage ); + + bResult = SwitchChildrenPersistance( xStorage, sal_True ); + } + + if ( bResult ) + { + if ( xStorage.is() && pImp->m_xDocStorage != xStorage ) + { + // make sure that until the storage is assigned the object container is not created by accident! + DBG_ASSERT( bHasContainer == (pImp->mpObjectContainer != 0), "Wrong storage in object container!" ); + xOldStorageHolder = pImp->m_xDocStorage; + pImp->m_xDocStorage = xStorage; + bSendNotification = sal_True; + + if ( IsEnableSetModified() ) + SetModified( sal_False ); + } + } + else + { + if ( pImp->mpObjectContainer ) + GetEmbeddedObjectContainer().SwitchPersistence( pImp->m_xDocStorage ); + + // let already successfully connected objects be switched back + SwitchChildrenPersistance( pImp->m_xDocStorage, sal_True ); + } + + if ( bSendNotification ) + { + SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_STORAGECHANGED, GlobalEventConfig::GetEventName(STR_EVENT_STORAGECHANGED), this ) ); + } + + return bResult; +} + + +sal_Bool StoragesOfUnknownMediaTypeAreCopied_Impl( const uno::Reference< embed::XStorage >& xSource, + const uno::Reference< embed::XStorage >& xTarget ) +{ + OSL_ENSURE( xSource.is() && xTarget.is(), "Source and/or target storages are not available!\n" ); + if ( !xSource.is() || !xTarget.is() || xSource == xTarget ) + return sal_True; + + try + { + uno::Sequence< ::rtl::OUString > aSubElements = xSource->getElementNames(); + for ( sal_Int32 nInd = 0; nInd < aSubElements.getLength(); nInd++ ) + { + if ( xSource->isStorageElement( aSubElements[nInd] ) ) + { + ::rtl::OUString aMediaType; + ::rtl::OUString aMediaTypePropName( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ); + sal_Bool bGotMediaType = sal_False; + + try + { + uno::Reference< embed::XOptimizedStorage > xOptStorage( xSource, uno::UNO_QUERY_THROW ); + bGotMediaType = + ( xOptStorage->getElementPropertyValue( aSubElements[nInd], aMediaTypePropName ) >>= aMediaType ); + } + catch( uno::Exception& ) + {} + + if ( !bGotMediaType ) + { + uno::Reference< embed::XStorage > xSubStorage; + try { + xSubStorage = xSource->openStorageElement( aSubElements[nInd], embed::ElementModes::READ ); + } catch( uno::Exception& ) + {} + + if ( !xSubStorage.is() ) + { + xSubStorage = ::comphelper::OStorageHelper::GetTemporaryStorage(); + xSource->copyStorageElementLastCommitTo( aSubElements[nInd], xSubStorage ); + } + + uno::Reference< beans::XPropertySet > xProps( xSubStorage, uno::UNO_QUERY_THROW ); + bGotMediaType = ( xProps->getPropertyValue( aMediaTypePropName ) >>= aMediaType ); + } + + // TODO/LATER: there should be a way to detect whether an object with such a MediaType can exist + // probably it should be placed in the MimeType-ClassID table or in standalone table + if ( aMediaType.getLength() + && aMediaType.compareToAscii( "application/vnd.sun.star.oleobject" ) != COMPARE_EQUAL ) + { + ::com::sun::star::datatransfer::DataFlavor aDataFlavor; + aDataFlavor.MimeType = aMediaType; + sal_uInt32 nFormat = SotExchange::GetFormat( aDataFlavor ); + + switch ( nFormat ) + { + case SOT_FORMATSTR_ID_STARWRITER_60 : + case SOT_FORMATSTR_ID_STARWRITERWEB_60 : + case SOT_FORMATSTR_ID_STARWRITERGLOB_60 : + case SOT_FORMATSTR_ID_STARDRAW_60 : + case SOT_FORMATSTR_ID_STARIMPRESS_60 : + case SOT_FORMATSTR_ID_STARCALC_60 : + case SOT_FORMATSTR_ID_STARCHART_60 : + case SOT_FORMATSTR_ID_STARMATH_60 : + case SOT_FORMATSTR_ID_STARWRITER_8: + case SOT_FORMATSTR_ID_STARWRITERWEB_8: + case SOT_FORMATSTR_ID_STARWRITERGLOB_8: + case SOT_FORMATSTR_ID_STARDRAW_8: + case SOT_FORMATSTR_ID_STARIMPRESS_8: + case SOT_FORMATSTR_ID_STARCALC_8: + case SOT_FORMATSTR_ID_STARCHART_8: + case SOT_FORMATSTR_ID_STARMATH_8: + break; + + default: + { + if ( !xTarget->hasByName( aSubElements[nInd] ) ) + return sal_False; + } + } + } + } + } + } + catch( uno::Exception& ) + { + OSL_ENSURE( sal_False, "Cant check storage consistency!\n" ); + } + + return sal_True; +} + + +sal_Bool SfxObjectShell::SwitchPersistance( const uno::Reference< embed::XStorage >& xStorage ) +{ + RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SwitchPersistance" ); + + sal_Bool bResult = sal_False; +#ifdef DBG_UTIL + // check for wrong creation of object container + BOOL bHasContainer = ( pImp->mpObjectContainer != 0 ); +#endif + if ( xStorage.is() ) + { + if ( pImp->mpObjectContainer ) + GetEmbeddedObjectContainer().SwitchPersistence( xStorage ); + bResult = SwitchChildrenPersistance( xStorage ); + + // TODO/LATER: substorages that have unknown mimetypes probably should be copied to the target storage here + OSL_ENSURE( StoragesOfUnknownMediaTypeAreCopied_Impl( pImp->m_xDocStorage, xStorage ), + "Some of substorages with unknown mimetypes is lost!" ); + } + + if ( bResult ) + { + // make sure that until the storage is assigned the object container is not created by accident! + DBG_ASSERT( bHasContainer == (pImp->mpObjectContainer != 0), "Wrong storage in object container!" ); + if ( pImp->m_xDocStorage != xStorage ) + DoSaveCompleted( new SfxMedium( xStorage, GetMedium()->GetBaseURL() ) ); + + if ( IsEnableSetModified() ) + SetModified( sal_True ); // ??? + } + + return bResult; +} + +sal_Bool SfxObjectShell::CopyStoragesOfUnknownMediaType( const uno::Reference< embed::XStorage >& xSource, + const uno::Reference< embed::XStorage >& xTarget ) +{ + RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::CopyStoragesOfUnknownMediaType" ); + + // This method does not commit the target storage and should not do it + sal_Bool bResult = sal_True; + + try + { + uno::Sequence< ::rtl::OUString > aSubElements = xSource->getElementNames(); + for ( sal_Int32 nInd = 0; nInd < aSubElements.getLength(); nInd++ ) + { + if ( aSubElements[nInd].equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Configurations" ) ) ) ) + { + // The workaround for compatibility with SO7, "Configurations" substorage must be preserved + if ( xSource->isStorageElement( aSubElements[nInd] ) ) + { + OSL_ENSURE( !xTarget->hasByName( aSubElements[nInd] ), + "The target storage is an output storage, the element should not exist in the target!\n" ); + + xSource->copyElementTo( aSubElements[nInd], xTarget, aSubElements[nInd] ); + } + } + else if ( xSource->isStorageElement( aSubElements[nInd] ) ) + { + ::rtl::OUString aMediaType; + ::rtl::OUString aMediaTypePropName( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ); + sal_Bool bGotMediaType = sal_False; + + try + { + uno::Reference< embed::XOptimizedStorage > xOptStorage( xSource, uno::UNO_QUERY_THROW ); + bGotMediaType = + ( xOptStorage->getElementPropertyValue( aSubElements[nInd], aMediaTypePropName ) >>= aMediaType ); + } + catch( uno::Exception& ) + {} + + if ( !bGotMediaType ) + { + uno::Reference< embed::XStorage > xSubStorage; + try { + xSubStorage = xSource->openStorageElement( aSubElements[nInd], embed::ElementModes::READ ); + } catch( uno::Exception& ) + {} + + if ( !xSubStorage.is() ) + { + // TODO/LATER: as optimization in future a substorage of target storage could be used + // instead of the temporary storage; this substorage should be removed later + // if the MimeType is wrong + xSubStorage = ::comphelper::OStorageHelper::GetTemporaryStorage(); + xSource->copyStorageElementLastCommitTo( aSubElements[nInd], xSubStorage ); + } + + uno::Reference< beans::XPropertySet > xProps( xSubStorage, uno::UNO_QUERY_THROW ); + bGotMediaType = ( xProps->getPropertyValue( aMediaTypePropName ) >>= aMediaType ); + } + + // TODO/LATER: there should be a way to detect whether an object with such a MediaType can exist + // probably it should be placed in the MimeType-ClassID table or in standalone table + if ( aMediaType.getLength() + && aMediaType.compareToAscii( "application/vnd.sun.star.oleobject" ) != COMPARE_EQUAL ) + { + ::com::sun::star::datatransfer::DataFlavor aDataFlavor; + aDataFlavor.MimeType = aMediaType; + sal_uInt32 nFormat = SotExchange::GetFormat( aDataFlavor ); + + switch ( nFormat ) + { + case SOT_FORMATSTR_ID_STARWRITER_60 : + case SOT_FORMATSTR_ID_STARWRITERWEB_60 : + case SOT_FORMATSTR_ID_STARWRITERGLOB_60 : + case SOT_FORMATSTR_ID_STARDRAW_60 : + case SOT_FORMATSTR_ID_STARIMPRESS_60 : + case SOT_FORMATSTR_ID_STARCALC_60 : + case SOT_FORMATSTR_ID_STARCHART_60 : + case SOT_FORMATSTR_ID_STARMATH_60 : + case SOT_FORMATSTR_ID_STARWRITER_8: + case SOT_FORMATSTR_ID_STARWRITERWEB_8: + case SOT_FORMATSTR_ID_STARWRITERGLOB_8: + case SOT_FORMATSTR_ID_STARDRAW_8: + case SOT_FORMATSTR_ID_STARIMPRESS_8: + case SOT_FORMATSTR_ID_STARCALC_8: + case SOT_FORMATSTR_ID_STARCHART_8: + case SOT_FORMATSTR_ID_STARMATH_8: + break; + + default: + { + OSL_ENSURE( + aSubElements[nInd].equalsAscii( "Configurations2" ) || !xTarget->hasByName( aSubElements[nInd] ), + "The target storage is an output storage, the element should not exist in the target!\n" ); + + if ( !xTarget->hasByName( aSubElements[nInd] ) ) + { + xSource->copyElementTo( aSubElements[nInd], xTarget, aSubElements[nInd] ); + } + } + } + } + } + } + } + catch( uno::Exception& ) + { + bResult = sal_False; + // TODO/LATER: a specific error could be provided + } + + return bResult; +} + +sal_Bool SfxObjectShell::GenerateAndStoreThumbnail( sal_Bool bEncrypted, + sal_Bool bSigned, + sal_Bool bIsTemplate, + const uno::Reference< embed::XStorage >& xStor ) +{ + RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::GenerateAndStoreThumbnail" ); + + sal_Bool bResult = sal_False; + + try { + uno::Reference< embed::XStorage > xThumbnailStor = + xStor->openStorageElement( ::rtl::OUString::createFromAscii( "Thumbnails" ), + embed::ElementModes::READWRITE ); + if ( xThumbnailStor.is() ) + { + uno::Reference< io::XStream > xStream = xThumbnailStor->openStreamElement( + ::rtl::OUString::createFromAscii( "thumbnail.png" ), + embed::ElementModes::READWRITE ); + + if ( xStream.is() && WriteThumbnail( bEncrypted, bSigned, bIsTemplate, xStream ) ) + { + uno::Reference< embed::XTransactedObject > xTransact( xThumbnailStor, uno::UNO_QUERY_THROW ); + xTransact->commit(); + bResult = sal_True; + } + } + } + catch( uno::Exception& ) + { + } + + return bResult; +} + +sal_Bool SfxObjectShell::WriteThumbnail( sal_Bool bEncrypted, + sal_Bool bSigned, + sal_Bool bIsTemplate, + const uno::Reference< io::XStream >& xStream ) +{ + sal_Bool bResult = sal_False; + + if ( xStream.is() ) + { + try { + uno::Reference< io::XTruncate > xTruncate( xStream->getOutputStream(), uno::UNO_QUERY_THROW ); + xTruncate->truncate(); + + if ( bEncrypted ) + { + sal_uInt16 nResID = GraphicHelper::getThumbnailReplacementIDByFactoryName_Impl( + ::rtl::OUString::createFromAscii( GetFactory().GetShortName() ), + bIsTemplate ); + if ( nResID ) + { + if ( !bSigned ) + { + bResult = GraphicHelper::getThumbnailReplacement_Impl( nResID, xStream ); + } + else + { + // retrieve the bitmap and write a signature bitmap over it + SfxResId aResId( nResID ); + BitmapEx aThumbBitmap( aResId ); + bResult = GraphicHelper::getSignedThumbnailFormatFromBitmap_Impl( aThumbBitmap, xStream ); + } + } + } + else + { + ::boost::shared_ptr<GDIMetaFile> pMetaFile = + GetPreviewMetaFile( sal_False ); + if ( pMetaFile ) + { + bResult = GraphicHelper::getThumbnailFormatFromGDI_Impl( + pMetaFile.get(), bSigned, xStream ); + } + } + } + catch( uno::Exception& ) + {} + } + + return bResult; +} + +void SfxObjectShell::UpdateLinks() +{ +} + +sal_Bool SfxObjectShell::QuerySaveSizeExceededModules_Impl( const uno::Reference< task::XInteractionHandler >& xHandler ) +{ + if ( !HasBasic() ) + return sal_True; + + if ( !pImp->pBasicManager->isValid() ) + GetBasicManager(); + uno::Sequence< rtl::OUString > sModules; + if ( xHandler.is() ) + { + if( pImp->pBasicManager->LegacyPsswdBinaryLimitExceeded( sModules ) ) + { + ModuleSizeExceeded* pReq = new ModuleSizeExceeded( sModules ); + uno::Reference< task::XInteractionRequest > xReq( pReq ); + xHandler->handle( xReq ); + return pReq->isApprove(); + } + } + // No interaction handler, default is to continue to save + return sal_True; +} +// ----------------------------------------------------------------------------- +uno::Reference< task::XInteractionHandler > SfxObjectShell::getInteractionHandler() const +{ + uno::Reference< task::XInteractionHandler > xRet; + if ( GetMedium() ) + xRet = GetMedium()->GetInteractionHandler(); + return xRet; +} diff --git a/sfx2/source/doc/objuno.cxx b/sfx2/source/doc/objuno.cxx new file mode 100644 index 000000000000..466f8dd43104 --- /dev/null +++ b/sfx2/source/doc/objuno.cxx @@ -0,0 +1,1350 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/StringPair.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/xml/sax/XParser.hpp> +#include <com/sun/star/document/XImporter.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> + +#include <unotools/configmgr.hxx> +#include <tools/inetdef.hxx> +#include <unotools/bootstrap.hxx> +#include <cppuhelper/interfacecontainer.hxx> +#include <osl/mutex.hxx> +#include <rtl/ustrbuf.hxx> +#include <vcl/svapp.hxx> +#include <vos/mutex.hxx> + +#include <tools/errcode.hxx> +#include <svl/cntwids.hrc> +#include <comphelper/string.hxx> +#include <comphelper/sequenceasvector.hxx> +#include <comphelper/storagehelper.hxx> +#include <sot/storage.hxx> + +#include <sfx2/objuno.hxx> +#include <sfx2/sfx.hrc> + +#include <vector> +#include <algorithm> + +#include "sfxresid.hxx" +#include "doc.hrc" + +using namespace ::com::sun::star; + +// TODO/REFACTOR: provide service for MS formats +// TODO/REFACTOR: IsEncrypted is never set nor read +// Generator is not saved ATM; which value?! +// Generator handling must be implemented +// Deprecate "Theme", rework IDL +// AutoLoadEnabled is deprecated?! +// Reasonable defaults for DateTime +// MIMEType readonly?! +// Announce changes about Theme, Language, Generator, removed entries etc. +// IsEncrypted is necessary for binary formats! +// Open: When to call PrepareDocInfoForSave? Currently only called for own formats and HTML/Writer +// Open: How to load and save EditingTime to MS formats +// PPT-Export should use SavePropertySet + +//============================================================================= + +// The number of user defined fields handled by the evil XDocumentInfo +// interface. There are exactly 4. No more, no less. +#define FOUR 4 + +#define PROPERTY_UNBOUND 0 +#define PROPERTY_MAYBEVOID ::com::sun::star::beans::PropertyAttribute::MAYBEVOID + +const SfxItemPropertyMapEntry* lcl_GetDocInfoPropertyMap() +{ + static SfxItemPropertyMapEntry aDocInfoPropertyMap_Impl[] = + { + { "Author" , 6 , WID_FROM, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + { "AutoloadEnabled" , 15, MID_DOCINFO_AUTOLOADENABLED, &::getBooleanCppuType(), PROPERTY_UNBOUND, 0 }, + { "AutoloadSecs" , 12, MID_DOCINFO_AUTOLOADSECS, &::getCppuType((const sal_Int32*)0), PROPERTY_UNBOUND, 0 }, + { "AutoloadURL" , 11, MID_DOCINFO_AUTOLOADURL, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + { "CreationDate" , 12, WID_DATE_CREATED, &::getCppuType((const ::com::sun::star::util::DateTime*)0),PROPERTY_MAYBEVOID, 0 }, + { "DefaultTarget" , 13, MID_DOCINFO_DEFAULTTARGET, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + { "Description" , 11, MID_DOCINFO_DESCRIPTION, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + { "DocumentStatistic", 17 , MID_DOCINFO_STATISTIC, &::getCppuType((const uno::Sequence< beans::NamedValue >*)0), PROPERTY_UNBOUND, 0 }, + { "EditingCycles" , 13, MID_DOCINFO_REVISION, &::getCppuType((const sal_Int16*)0), PROPERTY_UNBOUND, 0 }, + { "EditingDuration" , 15, MID_DOCINFO_EDITTIME, &::getCppuType((const sal_Int32*)0), PROPERTY_UNBOUND, 0 }, + { "Generator" , 9, SID_APPLICATION, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + { "Keywords" , 8 , WID_KEYWORDS, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + { "Language" , 8, MID_DOCINFO_CHARLOCALE, &::getCppuType((const lang::Locale*)0), PROPERTY_UNBOUND, 0 }, + { "MIMEType" , 8 , WID_CONTENT_TYPE, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND | ::com::sun::star::beans::PropertyAttribute::READONLY, 0 }, + { "ModifiedBy" , 10, MID_DOCINFO_MODIFICATIONAUTHOR, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + { "ModifyDate" , 10, WID_DATE_MODIFIED, &::getCppuType((const ::com::sun::star::util::DateTime*)0),PROPERTY_MAYBEVOID, 0 }, + { "PrintDate" , 9 , MID_DOCINFO_PRINTDATE, &::getCppuType((const ::com::sun::star::util::DateTime*)0),PROPERTY_MAYBEVOID, 0 }, + { "PrintedBy" , 9 , MID_DOCINFO_PRINTEDBY, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + { "Subject" , 7 , MID_DOCINFO_SUBJECT, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + { "Template" , 8 , MID_DOCINFO_TEMPLATE, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + { "TemplateFileName", 16, SID_TEMPLATE_NAME, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + { "TemplateDate" , 12, MID_DOCINFO_TEMPLATEDATE, &::getCppuType((const ::com::sun::star::util::DateTime*)0),PROPERTY_MAYBEVOID, 0 }, + { "Title" , 5 , WID_TITLE, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + {0,0,0,0,0,0} + }; + return aDocInfoPropertyMap_Impl; +} + +static USHORT aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31 }; + +inline USHORT DaysInMonth( USHORT nMonth, USHORT nYear ) +{ + if ( nMonth != 2 ) + return aDaysInMonth[nMonth-1]; + else + { + if ( (((nYear % 4) == 0) && ((nYear % 100) != 0)) || + ((nYear % 400) == 0) ) + return aDaysInMonth[nMonth-1] + 1; + else + return aDaysInMonth[nMonth-1]; + } +} + +bool IsValidDateTime( const util::DateTime& rDT ) +{ + if ( !rDT.Month || (rDT.Month > 12) ) + return false; + if ( !rDT.Day || (rDT.Day > DaysInMonth( rDT.Month, rDT.Year )) ) + return false; + else if ( rDT.Year <= 1582 ) + { + if ( rDT.Year < 1582 ) + return false; + else if ( rDT.Month < 10 ) + return false; + else if ( (rDT.Month == 10) && (rDT.Day < 15) ) + return false; + } + + return true; +} + +struct OUStringHashCode +{ + size_t operator()( const ::rtl::OUString& sString ) const + { + return sString.hashCode(); + } +}; + +struct SfxExtendedItemPropertyMap : public SfxItemPropertyMapEntry +{ + ::com::sun::star::uno::Any aValue; +}; + +void Copy( const uno::Reference < document::XStandaloneDocumentInfo >& rSource, const uno::Reference < document::XStandaloneDocumentInfo >& rTarget ) +{ + try + { + uno::Reference< beans::XPropertySet > xSet( rSource, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xTarget( rTarget, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySetInfo > xSetInfo = xSet->getPropertySetInfo(); + uno::Reference< beans::XPropertyContainer > xContainer( rTarget, uno::UNO_QUERY ); + uno::Sequence< beans::Property > lProps = xSetInfo->getProperties(); + const beans::Property* pProps = lProps.getConstArray(); + sal_Int32 c = lProps.getLength(); + sal_Int32 i = 0; + for (i=0; i<c; ++i) + { + uno::Any aValue = xSet->getPropertyValue( pProps[i].Name ); + if ( pProps[i].Attributes & ::com::sun::star::beans::PropertyAttribute::REMOVABLE ) + // QUESTION: DefaultValue?! + xContainer->addProperty( pProps[i].Name, pProps[i].Attributes, aValue ); + try + { + // it is possible that the propertysets from XML and binary files differ; we shouldn't break then + xTarget->setPropertyValue( pProps[i].Name, aValue ); + } + catch ( uno::Exception& ) {} + } + + sal_Int16 nCount = rSource->getUserFieldCount(); + sal_Int16 nSupportedCount = rTarget->getUserFieldCount(); + for ( sal_Int16 nInd = 0; nInd < nCount && nInd < nSupportedCount; nInd++ ) + { + ::rtl::OUString aPropName = rSource->getUserFieldName( nInd ); + rTarget->setUserFieldName( nInd, aPropName ); + ::rtl::OUString aPropVal = rSource->getUserFieldValue( nInd ); + rTarget->setUserFieldValue( nInd, aPropVal ); + } + } + catch ( uno::Exception& ) {} +} + +class MixedPropertySetInfo : public ::cppu::WeakImplHelper1< ::com::sun::star::beans::XPropertySetInfo > +{ + private: + + SfxItemPropertyMap _aPropertyMap; + ::rtl::OUString* _pUserKeys; + uno::Reference<beans::XPropertySet> _xUDProps; + + public: + + MixedPropertySetInfo( const SfxItemPropertyMapEntry* pFixProps, + ::rtl::OUString* pUserKeys, + uno::Reference<beans::XPropertySet> xUDProps); + + virtual ~MixedPropertySetInfo(); + + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property > SAL_CALL getProperties( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::beans::Property SAL_CALL getPropertyByName( const ::rtl::OUString& aName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL hasPropertyByName( const ::rtl::OUString& Name ) throw (::com::sun::star::uno::RuntimeException); +}; + +//----------------------------------------------------------------------------- + +MixedPropertySetInfo::MixedPropertySetInfo(const SfxItemPropertyMapEntry* pFixProps, + ::rtl::OUString* pUserKeys, + uno::Reference<beans::XPropertySet> xUDProps) + : _aPropertyMap( pFixProps ) + , _pUserKeys(pUserKeys) + , _xUDProps(xUDProps) +{ +} + +//----------------------------------------------------------------------------- + +MixedPropertySetInfo::~MixedPropertySetInfo() +{ +} + +//----------------------------------------------------------------------------- + +::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property > SAL_CALL MixedPropertySetInfo::getProperties() + throw(::com::sun::star::uno::RuntimeException) +{ + ::comphelper::SequenceAsVector< ::com::sun::star::beans::Property > lProps; + + // copy "fix" props + //todo: os: this ugly thing should be replaced + const SfxItemPropertyMapEntry* pFixProp = lcl_GetDocInfoPropertyMap(); + + while(pFixProp && pFixProp->pName) + { + ::com::sun::star::beans::Property aProp; + + aProp.Name = ::rtl::OUString::createFromAscii(pFixProp->pName); + aProp.Handle = pFixProp->nWID; + aProp.Type = *(pFixProp->pType); + aProp.Attributes = (sal_Int16)(pFixProp->nFlags); + + lProps.push_back(aProp); + ++pFixProp; + } + + // copy "dynamic" props + + // NB: this is really ugly: + // The returned properties must _not_ include the 4 user-defined fields! + // These are _not_ properties of the XDocumentInfo interface. + // Some things rely on this, e.g. Copy would break otherwise. + // This will have interesting consequences if someone expects to insert + // a property with the same name as an user-defined key, but nobody + // sane does that. + uno::Sequence<beans::Property> udProps = + _xUDProps->getPropertySetInfo()->getProperties(); + for (sal_Int32 i = 0; i < udProps.getLength(); ++i) { + if (std::find(_pUserKeys, _pUserKeys+FOUR, udProps[i].Name) + == _pUserKeys+FOUR) { + // #i100027#: handles from udProps are not valid here + udProps[i].Handle = -1; + lProps.push_back(udProps[i]); + } + } + + return lProps.getAsConstList(); +} + +//----------------------------------------------------------------------------- + +::com::sun::star::beans::Property SAL_CALL MixedPropertySetInfo::getPropertyByName( + const ::rtl::OUString& sName ) + throw(::com::sun::star::beans::UnknownPropertyException, + ::com::sun::star::uno::RuntimeException ) +{ + ::com::sun::star::beans::Property aProp; + + // search it as "fix" prop + if( _aPropertyMap.hasPropertyByName( sName ) ) + return _aPropertyMap.getPropertyByName( sName ); + else + // search it as "dynamic" prop + return _xUDProps->getPropertySetInfo()->getPropertyByName(sName); +} + +//----------------------------------------------------------------------------- + +::sal_Bool SAL_CALL MixedPropertySetInfo::hasPropertyByName(const ::rtl::OUString& sName) + throw(::com::sun::star::uno::RuntimeException) +{ + return _aPropertyMap.hasPropertyByName( sName ) ? // "fix" prop? + sal_True : + _xUDProps->getPropertySetInfo()->hasPropertyByName(sName); // "dynamic" prop? +} + +//----------------------------------------------------------------------------- + +struct SfxDocumentInfoObject_Impl +{ + ::osl::Mutex _aMutex; + ::cppu::OInterfaceContainerHelper _aDisposeContainer; + + sal_Bool bDisposed; + + // this contains the names of the 4 user defined properties + // which are accessible via the evil XDocumentInfo interface + ::rtl::OUString m_UserDefined[FOUR]; + + // the actual contents + uno::Reference<document::XDocumentProperties> m_xDocProps; + SfxItemPropertyMap m_aPropertyMap; + + SfxDocumentInfoObject_Impl() + : _aDisposeContainer( _aMutex ) + , bDisposed(sal_False) + , m_xDocProps() + , m_aPropertyMap( lcl_GetDocInfoPropertyMap() ) + { + // the number of user fields is not changeable from the outside + // we can't set it too high because every name/value pair will be written to the file (even if empty) + // currently our dialog has only 4 user keys so 4 is still a reasonable number + } + + /// the initialization function + void Reset(uno::Reference<document::XDocumentProperties> xDocProps, ::rtl::OUString* pUserDefined = 0); +}; + +void SfxDocumentInfoObject_Impl::Reset(uno::Reference<document::XDocumentProperties> xDocProps, ::rtl::OUString* pUserDefined) +{ + if (pUserDefined == 0) { + // NB: this is an ugly hack; the "Properties" ui dialog displays + // exactly 4 user-defined fields and expects these to be available + // (should be redesigned), but I do not want to do this in + // DocumentProperties; do it here instead + uno::Reference<beans::XPropertyAccess> xPropAccess( + xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); + uno::Reference<beans::XPropertyContainer> xPropContainer( + xPropAccess, uno::UNO_QUERY_THROW); + uno::Sequence< beans::PropertyValue > + props = xPropAccess->getPropertyValues(); + sal_Int32 oldLength = props.getLength(); + if (oldLength < FOUR) { + std::vector< ::rtl::OUString > names; + for (sal_Int32 i = 0; i < oldLength; ++i) { + names.push_back(props[i].Name); + } + const ::rtl::OUString sInfo( + String( SfxResId( STR_DOCINFO_INFOFIELD ) )); + for (sal_Int32 i = oldLength; i < FOUR; ++i) { + ::rtl::OUString sName(sInfo); + sal_Int32 idx = sName.indexOfAsciiL("%1", 2); + ::rtl::OUString name = (idx > 0) + ? sName.replaceAt(idx, 2, ::rtl::OUString::valueOf(i+1)) + : sName + ::rtl::OUString::valueOf(i+1); + while (std::find(names.begin(), names.end(), name) + != names.end()) { + name += ::rtl::OUString::createFromAscii("'"); + } + // FIXME there is a race condition here + try { + xPropContainer->addProperty(name, + beans::PropertyAttribute::REMOVEABLE, + uno::makeAny(::rtl::OUString::createFromAscii(""))); + } catch (uno::RuntimeException) { + throw; + } catch (uno::Exception) { + // ignore + } + } + } + props = xPropAccess->getPropertyValues(); + for (sal_Int32 i = 0; i < FOUR; ++i) { + m_UserDefined[i] = props[i].Name; + } + } else { + std::copy(pUserDefined, pUserDefined+FOUR, m_UserDefined); + } + m_xDocProps = xDocProps; +} + +//----------------------------------------------------------------------------- + +SfxDocumentInfoObject::SfxDocumentInfoObject() + : _pImp( new SfxDocumentInfoObject_Impl() ) +{ +} + +//----------------------------------------------------------------------------- + +SfxDocumentInfoObject::~SfxDocumentInfoObject() +{ + delete _pImp; +} + +//----------------------------------------------------------------------------- + +// ::com::sun::star::lang::XInitialization: +void SAL_CALL +SfxDocumentInfoObject::initialize(const uno::Sequence< uno::Any > & aArguments) + throw (uno::RuntimeException, uno::Exception) +{ + if (aArguments.getLength() >= 1) { + uno::Any any = aArguments[0]; + uno::Reference<document::XDocumentProperties> xDoc; + if (!(any >>= xDoc) || !xDoc.is()) throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii( + "SfxDocumentInfoObject::initialize: no XDocumentProperties given"), + *this, 0); + _pImp->Reset(xDoc); + } else { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii( + "SfxDocumentInfoObject::initialize: no argument given"), + *this, 0); + } +} + +// ::com::sun::star::util::XCloneable: +uno::Reference<util::XCloneable> SAL_CALL +SfxDocumentInfoObject::createClone() throw (uno::RuntimeException) +{ + SfxDocumentInfoObject *pNew = new SfxDocumentInfoObject; + uno::Reference< util::XCloneable > + xCloneable(_pImp->m_xDocProps, uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps( + xCloneable->createClone(), uno::UNO_QUERY_THROW); + pNew->_pImp->Reset(xDocProps, _pImp->m_UserDefined); + return pNew; +} + +// ::com::sun::star::document::XDocumentProperties: +uno::Reference< document::XDocumentProperties > SAL_CALL +SfxDocumentInfoObject::getDocumentProperties() + throw(::com::sun::star::uno::RuntimeException) +{ + return _pImp->m_xDocProps; +} + +//----------------------------------------------------------------------------- + +const SfxDocumentInfoObject& SfxDocumentInfoObject::operator=( const SfxDocumentInfoObject & rOther) +{ + uno::Reference< util::XCloneable > + xCloneable(rOther._pImp->m_xDocProps, uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps( + xCloneable->createClone(), uno::UNO_QUERY_THROW); + _pImp->Reset(xDocProps, rOther._pImp->m_UserDefined); + return *this; +} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxDocumentInfoObject::dispose() throw( ::com::sun::star::uno::RuntimeException ) +{ + ::com::sun::star::lang::EventObject aEvent( (::cppu::OWeakObject *)this ); + _pImp->_aDisposeContainer.disposeAndClear( aEvent ); + ::osl::MutexGuard aGuard( _pImp->_aMutex ); + _pImp->m_xDocProps = 0; + // NB: do not call m_xDocProps->dispose(), there could be other refs + _pImp->bDisposed = sal_True; +} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxDocumentInfoObject::addEventListener(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener > & aListener) throw( ::com::sun::star::uno::RuntimeException ) +{ + _pImp->_aDisposeContainer.addInterface( aListener ); +} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxDocumentInfoObject::removeEventListener(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener > & aListener) throw( ::com::sun::star::uno::RuntimeException ) +{ + _pImp->_aDisposeContainer.removeInterface( aListener ); +} +//----------------------------------------------------------------------------- + +::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL SfxDocumentInfoObject::getPropertySetInfo() throw( ::com::sun::star::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( _pImp->_aMutex ); + + uno::Reference<beans::XPropertySet> xPropSet( + _pImp->m_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); + MixedPropertySetInfo* pInfo = new MixedPropertySetInfo( lcl_GetDocInfoPropertyMap(), _pImp->m_UserDefined, xPropSet); + uno::Reference< beans::XPropertySetInfo > xInfo( + static_cast< beans::XPropertySetInfo* >(pInfo), uno::UNO_QUERY_THROW); + return xInfo; +} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxDocumentInfoObject::setPropertyValue(const ::rtl::OUString& aPropertyName, const uno::Any& aValue) throw ( + uno::RuntimeException, beans::UnknownPropertyException, + beans::PropertyVetoException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + const SfxItemPropertySimpleEntry* pEntry = _pImp->m_aPropertyMap.getByName( aPropertyName ); + // fix prop! + if ( pEntry ) + setFastPropertyValue( pEntry->nWID, aValue ); + else + // dynamic prop! + { + uno::Reference<beans::XPropertySet> xPropSet( + _pImp->m_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); + return xPropSet->setPropertyValue(aPropertyName, aValue); + } +} + +//----------------------------------------------------------------------------- + +uno::Any SAL_CALL SfxDocumentInfoObject::getPropertyValue(const ::rtl::OUString& aPropertyName) throw( + uno::RuntimeException, beans::UnknownPropertyException, + lang::WrappedTargetException) +{ + const SfxItemPropertySimpleEntry* pEntry = _pImp->m_aPropertyMap.getByName( aPropertyName ); + // fix prop! + if ( pEntry ) + return getFastPropertyValue( pEntry->nWID ); + else + // dynamic prop! + { + uno::Reference<beans::XPropertySet> xPropSet( + _pImp->m_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); + return xPropSet->getPropertyValue(aPropertyName); + } +} + +sal_Bool SAL_CALL SfxDocumentInfoObject::isModified() throw(::com::sun::star::uno::RuntimeException) +{ + uno::Reference<util::XModifiable> xModif( + _pImp->m_xDocProps, uno::UNO_QUERY_THROW); + return xModif->isModified(); +} + +void SAL_CALL SfxDocumentInfoObject::setModified( sal_Bool bModified ) + throw (::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException) +{ + uno::Reference<util::XModifiable> xModif( + _pImp->m_xDocProps, uno::UNO_QUERY_THROW); + return xModif->setModified(bModified); +} + +void SAL_CALL SfxDocumentInfoObject::addModifyListener( const uno::Reference< util::XModifyListener >& xListener) throw( uno::RuntimeException ) +{ + uno::Reference<util::XModifiable> xModif( + _pImp->m_xDocProps, uno::UNO_QUERY_THROW); + return xModif->addModifyListener(xListener); +} + +void SAL_CALL SfxDocumentInfoObject::removeModifyListener( const uno::Reference< util::XModifyListener >& xListener) throw( uno::RuntimeException ) +{ + uno::Reference<util::XModifiable> xModif( + _pImp->m_xDocProps, uno::UNO_QUERY_THROW); + return xModif->removeModifyListener(xListener); +} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxDocumentInfoObject::addPropertyChangeListener(const ::rtl::OUString&, const uno::Reference< beans::XPropertyChangeListener > & ) throw( + uno::RuntimeException, beans::UnknownPropertyException, + lang::WrappedTargetException) +{} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxDocumentInfoObject::removePropertyChangeListener(const ::rtl::OUString&, const uno::Reference< beans::XPropertyChangeListener > & ) throw( + uno::RuntimeException, beans::UnknownPropertyException, + lang::WrappedTargetException) +{} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxDocumentInfoObject::addVetoableChangeListener(const ::rtl::OUString&, const uno::Reference< beans::XVetoableChangeListener > & ) throw( + uno::RuntimeException, beans::UnknownPropertyException, + lang::WrappedTargetException) +{} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxDocumentInfoObject::removeVetoableChangeListener(const ::rtl::OUString&, const uno::Reference< beans::XVetoableChangeListener > & ) throw( + uno::RuntimeException, beans::UnknownPropertyException, + lang::WrappedTargetException) +{} + +uno::Sequence< beans::PropertyValue > SAL_CALL SfxDocumentInfoObject::getPropertyValues( void ) throw( uno::RuntimeException ) +{ + ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > xInfo = getPropertySetInfo(); + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property > aProps = xInfo->getProperties(); + + const ::com::sun::star::beans::Property* pProps = aProps.getConstArray(); + sal_uInt32 nCount = aProps.getLength(); + + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >aSeq( nCount ); + ::com::sun::star::beans::PropertyValue* pValues = aSeq.getArray(); + + for ( sal_uInt32 n = 0; n < nCount; ++n ) + { + ::com::sun::star::beans::PropertyValue& rCurrValue = pValues[n]; + const ::com::sun::star::beans::Property& rCurrProp = pProps[n]; + + rCurrValue.Name = rCurrProp.Name; + rCurrValue.Handle = rCurrProp.Handle; + rCurrValue.Value = getPropertyValue( rCurrProp.Name ); + } + + return aSeq; +} + +void SAL_CALL SfxDocumentInfoObject::setPropertyValues( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aProps ) + throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException ) +{ + const ::com::sun::star::beans::PropertyValue* pProps = aProps.getConstArray(); + sal_uInt32 nCount = aProps.getLength(); + + for ( sal_uInt32 n = 0; n < nCount; ++n ) + { + const ::com::sun::star::beans::PropertyValue& rProp = pProps[n]; + setPropertyValue( rProp.Name, rProp.Value ); + } +} + +void SAL_CALL SfxDocumentInfoObject::addProperty(const ::rtl::OUString& sName , + sal_Int16 nAttributes , + const ::com::sun::star::uno::Any& aDefaultValue) + throw(::com::sun::star::beans::PropertyExistException , + ::com::sun::star::beans::IllegalTypeException , + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException ) +{ + // clash with "fix" properties ? + sal_Bool bFixProp = _pImp->m_aPropertyMap.getByName( sName ) != 0; + if ( bFixProp ) + { + ::rtl::OUStringBuffer sMsg(256); + sMsg.appendAscii("The property \"" ); + sMsg.append (sName ); + sMsg.appendAscii("\" " ); + if ( bFixProp ) + sMsg.appendAscii(" already exists as a fix property. Please have a look into the IDL documentation of the DocumentInfo service."); + + throw ::com::sun::star::beans::PropertyExistException( + sMsg.makeStringAndClear(), + static_cast< ::cppu::OWeakObject* >(this)); + } + + uno::Reference<beans::XPropertyContainer> xPropSet( + _pImp->m_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); + return xPropSet->addProperty(sName, nAttributes, aDefaultValue); +} + +void SAL_CALL SfxDocumentInfoObject::removeProperty(const ::rtl::OUString& sName) + throw(::com::sun::star::beans::UnknownPropertyException, + ::com::sun::star::beans::NotRemoveableException , + ::com::sun::star::uno::RuntimeException ) +{ + // clash with "fix" properties ? + sal_Bool bFixProp = _pImp->m_aPropertyMap.getByName( sName ) != 0; + if ( bFixProp ) + { + ::rtl::OUStringBuffer sMsg(256); + sMsg.appendAscii("The property \"" ); + sMsg.append (sName ); + sMsg.appendAscii("\" cant be removed. Its a fix property of the DocumentInfo service."); + + throw ::com::sun::star::beans::NotRemoveableException( + sMsg.makeStringAndClear(), + static_cast< ::cppu::OWeakObject* >(this)); + } + + uno::Reference<beans::XPropertyContainer> xPropSet( + _pImp->m_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); + return xPropSet->removeProperty(sName); +} + +BOOL equalsDateTime( const util::DateTime& D1, const util::DateTime& D2 ) +{ + return D1.HundredthSeconds == D2.HundredthSeconds && + D1.Seconds == D2.Seconds && + D1.Minutes == D2.Minutes && + D1.Hours == D2.Hours && + D1.Day == D2.Day && + D1.Month == D2.Month && + D1.Year == D2.Year; +} + +void SAL_CALL SfxDocumentInfoObject::setFastPropertyValue(sal_Int32 nHandle, const ::com::sun::star::uno::Any& aValue) throw( + uno::RuntimeException, beans::UnknownPropertyException, + beans::PropertyVetoException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + // Attention: Only fix properties should be provided by this method. + // Dynamic properties has no handle in real ... because it cant be used inside multithreaded environments :-) + + ::osl::ClearableMutexGuard aGuard( _pImp->_aMutex ); + + if ( aValue.getValueType() == ::getCppuType((const ::rtl::OUString*)0) ) + { + ::rtl::OUString sTemp ; + aValue >>= sTemp ; + switch ( nHandle ) + { + case SID_APPLICATION : + _pImp->m_xDocProps->setGenerator(sTemp); + break; + case WID_FROM : + { + // QUESTION: do we still need this? + /* + // String aStrVal( sTemp ); + if ( aStrVal.Len() > TIMESTAMP_MAXLENGTH ) + { + SvAddressParser aParser( aStrVal ); + if ( aParser.Count() > 0 ) + { + String aEmail = aParser.GetEmailAddress(0); + String aRealname = aParser.GetRealName(0); + + if ( aRealname.Len() <= TIMESTAMP_MAXLENGTH ) + aStrVal = aRealname; + else if ( aEmail.Len() <= TIMESTAMP_MAXLENGTH ) + aStrVal = aEmail; + } + } */ + + if ( _pImp->m_xDocProps->getAuthor() != sTemp ) + _pImp->m_xDocProps->setAuthor(sTemp); + break; + } + case MID_DOCINFO_PRINTEDBY: + if ( _pImp->m_xDocProps->getPrintedBy() != sTemp ) + _pImp->m_xDocProps->setPrintedBy(sTemp); + break; + case MID_DOCINFO_MODIFICATIONAUTHOR: + if ( _pImp->m_xDocProps->getModifiedBy() != sTemp ) + _pImp->m_xDocProps->setModifiedBy(sTemp); + break; + case WID_TITLE : + { + if ( _pImp->m_xDocProps->getTitle() != sTemp ) + _pImp->m_xDocProps->setTitle(sTemp); + break; + } + case MID_DOCINFO_SUBJECT : + if ( _pImp->m_xDocProps->getSubject() != sTemp ) + _pImp->m_xDocProps->setSubject(sTemp); + break; + case WID_KEYWORDS : + { + _pImp->m_xDocProps->setKeywords( + ::comphelper::string::convertCommaSeparated(sTemp)); + } + break; + case MID_DOCINFO_TEMPLATE: + if ( _pImp->m_xDocProps->getTemplateName() != sTemp ) + _pImp->m_xDocProps->setTemplateName(sTemp); + break; + case SID_TEMPLATE_NAME: + if ( _pImp->m_xDocProps->getTemplateURL() != sTemp ) + _pImp->m_xDocProps->setTemplateURL(sTemp); + break; + case MID_DOCINFO_DESCRIPTION: + if ( _pImp->m_xDocProps->getDescription() != sTemp ) + _pImp->m_xDocProps->setDescription(sTemp); + break; + case MID_DOCINFO_AUTOLOADURL: + if ( _pImp->m_xDocProps->getAutoloadURL() != sTemp ) + _pImp->m_xDocProps->setAutoloadURL(sTemp); + break; + case MID_DOCINFO_DEFAULTTARGET: + if ( _pImp->m_xDocProps->getDefaultTarget() != sTemp ) + _pImp->m_xDocProps->setDefaultTarget(sTemp); + break; +// case WID_CONTENT_TYPE : // this is readonly! + default: + break; + } + } + else if ( aValue.getValueType() == ::getCppuType((const ::com::sun::star::util::DateTime*)0) ) + { + com::sun::star::util::DateTime aTemp; + aValue >>= aTemp ; + switch ( nHandle ) + { + case WID_DATE_CREATED : + { + if ( !equalsDateTime(_pImp->m_xDocProps->getCreationDate(), aTemp ) ) + { + _pImp->m_xDocProps->setCreationDate(aTemp); + } + break; + } + case WID_DATE_MODIFIED : + { + if ( !equalsDateTime(_pImp->m_xDocProps->getModificationDate(), aTemp ) ) + { + _pImp->m_xDocProps->setModificationDate(aTemp); + } + break; + } + case MID_DOCINFO_PRINTDATE : + { + if ( !equalsDateTime(_pImp->m_xDocProps->getPrintDate(), aTemp ) ) + { + _pImp->m_xDocProps->setPrintDate(aTemp); + } + break; + } + case MID_DOCINFO_TEMPLATEDATE : + { + if ( !equalsDateTime(_pImp->m_xDocProps->getTemplateDate(), aTemp ) ) + { + _pImp->m_xDocProps->setTemplateDate(aTemp); + } + break; + } + default: + break; + } + } + + else if ( aValue.getValueType() == ::getBooleanCppuType() ) + { + sal_Bool bBoolVal = false; + aValue >>= bBoolVal ; + switch ( nHandle ) + { + case MID_DOCINFO_AUTOLOADENABLED: + // NB: this property does not exist any more + // it is emulated as enabled iff delay > 0 + if ( bBoolVal && (0 == _pImp->m_xDocProps->getAutoloadSecs()) ) { + _pImp->m_xDocProps->setAutoloadSecs(60); // default + } else if ( !bBoolVal && (0 != _pImp->m_xDocProps->getAutoloadSecs()) ) { + _pImp->m_xDocProps->setAutoloadSecs(0); + _pImp->m_xDocProps->setAutoloadURL(::rtl::OUString::createFromAscii("")); + } + break; + default: + break; + } + } + else if ( aValue.getValueType() == ::getCppuType((const sal_Int32*)0) ) + { + sal_Int32 nIntVal = 0; + aValue >>= nIntVal ; + switch ( nHandle ) + { + case MID_DOCINFO_AUTOLOADSECS: + if ( nIntVal != _pImp->m_xDocProps->getAutoloadSecs()) + _pImp->m_xDocProps->setAutoloadSecs(nIntVal); + break; + case MID_DOCINFO_EDITTIME: + if ( nIntVal != _pImp->m_xDocProps->getEditingDuration()) + _pImp->m_xDocProps->setEditingDuration(nIntVal); + break; + default: + break; + } + } + else if ( aValue.getValueType() == ::getCppuType((const sal_Int16*)0) ) + { + short nIntVal = 0; + aValue >>= nIntVal ; + switch ( nHandle ) + { + case MID_DOCINFO_REVISION: + if ( nIntVal != _pImp->m_xDocProps->getEditingCycles()) + _pImp->m_xDocProps->setEditingCycles(nIntVal); + break; + default: + break; + } + } + else if ( aValue.getValueType() == ::getCppuType((const uno::Sequence< beans::NamedValue >*)0) ) + { + if ( nHandle == MID_DOCINFO_STATISTIC ) + { + uno::Sequence < beans::NamedValue > aData; + aValue >>= aData; + { + _pImp->m_xDocProps->setDocumentStatistics(aData); + } + } + } + else if ( aValue.getValueType() == ::getCppuType((const lang::Locale*)0) ) + { + if ( nHandle == MID_DOCINFO_CHARLOCALE ) + { + lang::Locale aLocale; + aValue >>= aLocale; + lang::Locale oldLocale = _pImp->m_xDocProps->getLanguage(); + if ( aLocale.Language != oldLocale.Language || + aLocale.Country != oldLocale.Country || + aLocale.Variant != oldLocale.Variant ) + { + _pImp->m_xDocProps->setLanguage(aLocale); + } + } + } +} + +//----------------------------------------------------------------------------- + +::com::sun::star::uno::Any SAL_CALL SfxDocumentInfoObject::getFastPropertyValue(sal_Int32 nHandle) throw( + uno::RuntimeException, beans::UnknownPropertyException, + lang::WrappedTargetException) +{ + // Attention: Only fix properties should be provided by this method. + // Dynamic properties has no handle in real ... because it cant be used inside multithreaded environments :-) + + ::osl::MutexGuard aGuard( _pImp->_aMutex ); + ::com::sun::star::uno::Any aValue; + switch ( nHandle ) + { + case SID_APPLICATION : + aValue <<= _pImp->m_xDocProps->getGenerator(); + break; + case WID_CONTENT_TYPE : +// FIXME this is not available anymore + aValue <<= ::rtl::OUString(); + break; + case MID_DOCINFO_REVISION : + aValue <<= _pImp->m_xDocProps->getEditingCycles(); + break; + case MID_DOCINFO_EDITTIME : + aValue <<= _pImp->m_xDocProps->getEditingDuration(); + break; + case WID_FROM : + aValue <<= _pImp->m_xDocProps->getAuthor(); + break; + case WID_DATE_CREATED : + if ( IsValidDateTime( _pImp->m_xDocProps->getCreationDate() ) ) + aValue <<= _pImp->m_xDocProps->getCreationDate(); + break; + case WID_TITLE : + aValue <<= _pImp->m_xDocProps->getTitle(); + break; + case MID_DOCINFO_SUBJECT: + aValue <<= _pImp->m_xDocProps->getSubject(); + break; + case MID_DOCINFO_MODIFICATIONAUTHOR: + aValue <<= _pImp->m_xDocProps->getModifiedBy(); + break; + case WID_DATE_MODIFIED : + if ( IsValidDateTime( _pImp->m_xDocProps->getModificationDate() ) ) + aValue <<= _pImp->m_xDocProps->getModificationDate(); + break; + case MID_DOCINFO_PRINTEDBY: + aValue <<= _pImp->m_xDocProps->getPrintedBy(); + break; + case MID_DOCINFO_PRINTDATE: + if ( IsValidDateTime( _pImp->m_xDocProps->getPrintDate() ) ) + aValue <<= _pImp->m_xDocProps->getPrintDate(); + break; + case WID_KEYWORDS : + aValue <<= ::comphelper::string::convertCommaSeparated( + _pImp->m_xDocProps->getKeywords()); + break; + case MID_DOCINFO_DESCRIPTION: + aValue <<= _pImp->m_xDocProps->getDescription(); + break; + case MID_DOCINFO_TEMPLATE: + aValue <<= _pImp->m_xDocProps->getTemplateName(); + break; + case SID_TEMPLATE_NAME: + aValue <<= _pImp->m_xDocProps->getTemplateURL(); + break; + case MID_DOCINFO_TEMPLATEDATE: + if ( IsValidDateTime( _pImp->m_xDocProps->getTemplateDate() ) ) + aValue <<= _pImp->m_xDocProps->getTemplateDate(); + break; + case MID_DOCINFO_AUTOLOADENABLED: + aValue <<= static_cast<sal_Bool> + ( (_pImp->m_xDocProps->getAutoloadSecs() != 0) + || !(_pImp->m_xDocProps->getAutoloadURL().equalsAscii(""))); + break; + case MID_DOCINFO_AUTOLOADURL: + aValue <<= _pImp->m_xDocProps->getAutoloadURL(); + break; + case MID_DOCINFO_AUTOLOADSECS: + aValue <<= _pImp->m_xDocProps->getAutoloadSecs(); + break; + case MID_DOCINFO_DEFAULTTARGET: + aValue <<= _pImp->m_xDocProps->getDefaultTarget(); + break; + case MID_DOCINFO_STATISTIC: + aValue <<= _pImp->m_xDocProps->getDocumentStatistics(); + break; + case MID_DOCINFO_CHARLOCALE: + aValue <<= _pImp->m_xDocProps->getLanguage(); + break; + default: + aValue <<= ::rtl::OUString(); + break; + } + + return aValue; +} + +//----------------------------------------------------------------------------- + +sal_Int16 SAL_CALL SfxDocumentInfoObject::getUserFieldCount() throw( ::com::sun::star::uno::RuntimeException ) +{ +// uno::Reference<beans::XPropertyAccess> xPropSet( +// _pImp->m_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); +// return xPropSet->getPropertyValues().getLength(); + return FOUR; +} + +//----------------------------------------------------------------------------- + +::rtl::OUString SAL_CALL SfxDocumentInfoObject::getUserFieldName(sal_Int16 nIndex) throw( ::com::sun::star::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( _pImp->_aMutex ); + if (nIndex < FOUR) + return _pImp->m_UserDefined[nIndex]; + else + return ::rtl::OUString(); +} + +//----------------------------------------------------------------------------- + +::rtl::OUString SAL_CALL SfxDocumentInfoObject::getUserFieldValue(sal_Int16 nIndex) throw( ::com::sun::star::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( _pImp->_aMutex ); + if (nIndex < FOUR) { + ::rtl::OUString name = _pImp->m_UserDefined[nIndex]; + uno::Reference<beans::XPropertySet> xPropSet( + _pImp->m_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); + ::rtl::OUString val; + try { + xPropSet->getPropertyValue(name) >>= val; + return val; + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception &) { + return ::rtl::OUString(); // ignore + } + } else + return ::rtl::OUString(); +} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxDocumentInfoObject::setUserFieldName(sal_Int16 nIndex, const ::rtl::OUString& aName ) throw( ::com::sun::star::uno::RuntimeException ) +{ + ::osl::ClearableMutexGuard aGuard( _pImp->_aMutex ); + if (nIndex < FOUR) // yes, four! + { + // FIXME this is full of race conditions because the PropertyBag + // can be accessed from clients of the DocumentProperties! + ::rtl::OUString name = _pImp->m_UserDefined[nIndex]; + if (name != aName) { + uno::Reference<beans::XPropertySet> xPropSet( + _pImp->m_xDocProps->getUserDefinedProperties(), + uno::UNO_QUERY_THROW); + uno::Reference<beans::XPropertyContainer> xPropContainer( + _pImp->m_xDocProps->getUserDefinedProperties(), + uno::UNO_QUERY_THROW); + uno::Any value; + try { + value = xPropSet->getPropertyValue(name); + xPropContainer->removeProperty(name); + xPropContainer->addProperty(aName, + beans::PropertyAttribute::REMOVEABLE, value); + _pImp->m_UserDefined[nIndex] = aName; + } catch (beans::UnknownPropertyException) { + try { + xPropContainer->addProperty(aName, + beans::PropertyAttribute::REMOVEABLE, + uno::makeAny(::rtl::OUString::createFromAscii(""))); + _pImp->m_UserDefined[nIndex] = aName; + } catch (beans::PropertyExistException) { + _pImp->m_UserDefined[nIndex] = aName; + // ignore + } + } catch (beans::PropertyExistException) { + try { + xPropContainer->addProperty(name, + beans::PropertyAttribute::REMOVEABLE, value); + } catch (beans::PropertyExistException) { + // bugger... + } + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception &) { + // ignore everything else; xPropSet _may_ be corrupted + } + } + } +} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxDocumentInfoObject::setUserFieldValue( sal_Int16 nIndex, const ::rtl::OUString& aValue ) throw( ::com::sun::star::uno::RuntimeException ) +{ + ::osl::ClearableMutexGuard aGuard( _pImp->_aMutex ); + if (nIndex < FOUR) // yes, four! + { + ::rtl::OUString name = _pImp->m_UserDefined[nIndex]; + uno::Reference<beans::XPropertySet> xPropSet( + _pImp->m_xDocProps->getUserDefinedProperties(), + uno::UNO_QUERY_THROW); + uno::Reference<beans::XPropertyContainer> xPropContainer( + _pImp->m_xDocProps->getUserDefinedProperties(), + uno::UNO_QUERY_THROW); + uno::Any aAny; + aAny <<= aValue; + try { + uno::Any value = xPropSet->getPropertyValue(name); + if (value != aAny) { + xPropSet->setPropertyValue(name, aAny); + } + } catch (beans::UnknownPropertyException) { + try { + // someone removed it, add it back again + xPropContainer->addProperty(name, + beans::PropertyAttribute::REMOVEABLE, aAny); + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception &) { + // ignore everything else + } + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception &) { + // ignore everything else + } + } +} + +//----------------------------------------------------------------------------- +SFX_IMPL_XINTERFACE_2( SfxStandaloneDocumentInfoObject, SfxDocumentInfoObject, ::com::sun::star::lang::XServiceInfo, ::com::sun::star::document::XStandaloneDocumentInfo ) +SFX_IMPL_XTYPEPROVIDER_10( SfxStandaloneDocumentInfoObject, ::com::sun::star::document::XDocumentInfo, ::com::sun::star::lang::XComponent, + ::com::sun::star::beans::XPropertySet, ::com::sun::star::beans::XFastPropertySet, ::com::sun::star::beans::XPropertyAccess, + ::com::sun::star::beans::XPropertyContainer, ::com::sun::star::util::XModifiable, ::com::sun::star::util::XModifyBroadcaster, + ::com::sun::star::document::XStandaloneDocumentInfo, ::com::sun::star::lang::XServiceInfo ) + +SFX_IMPL_XSERVICEINFO( SfxStandaloneDocumentInfoObject, "com.sun.star.document.StandaloneDocumentInfo", "com.sun.star.comp.sfx2.StandaloneDocumentInfo" ) +SFX_IMPL_SINGLEFACTORY( SfxStandaloneDocumentInfoObject ) + +SfxStandaloneDocumentInfoObject::SfxStandaloneDocumentInfoObject( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xFactory ) + : SfxDocumentInfoObject() + , _xFactory( xFactory ) +{ + uno::Reference< lang::XInitialization > xDocProps( + _xFactory->createInstance( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.document.DocumentProperties"))), uno::UNO_QUERY_THROW); +// xDocProps->initialize(uno::Sequence<uno::Any>()); + uno::Any a; + a <<= xDocProps; + uno::Sequence<uno::Any> args(1); + args[0] = a; + initialize(args); +} + +//----------------------------------------------------------------------------- + +SfxStandaloneDocumentInfoObject::~SfxStandaloneDocumentInfoObject() +{ +} + +//----------------------------------------------------------------------------- + +uno::Reference< embed::XStorage > GetStorage_Impl( const ::rtl::OUString& rName, sal_Bool bWrite, uno::Reference < lang::XMultiServiceFactory >& xFactory ) +{ + // catch unexpected exceptions under solaris + // Client code checks the returned reference but is not interested on error details. + try + { + ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + return ::comphelper::OStorageHelper::GetStorageFromURL( + rName, + bWrite ? embed::ElementModes::READWRITE : embed::ElementModes::READ, + xFactory ); + } + catch(const uno::Exception&) + {} + + return uno::Reference< embed::XStorage >(); +} + +//----------------------------------------------------------------------------- + +sal_Int16 SAL_CALL SfxStandaloneDocumentInfoObject::getUserFieldCount() throw( ::com::sun::star::uno::RuntimeException ) +{ + return SfxDocumentInfoObject::getUserFieldCount(); +} + +//----------------------------------------------------------------------------- + +::rtl::OUString SAL_CALL SfxStandaloneDocumentInfoObject::getUserFieldName(sal_Int16 nIndex) throw( ::com::sun::star::uno::RuntimeException ) +{ + return SfxDocumentInfoObject::getUserFieldName(nIndex); +} + +//----------------------------------------------------------------------------- + +::rtl::OUString SAL_CALL SfxStandaloneDocumentInfoObject::getUserFieldValue(sal_Int16 nIndex) throw( ::com::sun::star::uno::RuntimeException ) +{ + return SfxDocumentInfoObject::getUserFieldValue(nIndex); +} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxStandaloneDocumentInfoObject::setUserFieldName(sal_Int16 nIndex, const ::rtl::OUString& aName ) throw( ::com::sun::star::uno::RuntimeException ) +{ + SfxDocumentInfoObject::setUserFieldName( nIndex, aName ); +} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxStandaloneDocumentInfoObject::setUserFieldValue( sal_Int16 nIndex, const ::rtl::OUString& aValue ) throw( ::com::sun::star::uno::RuntimeException ) +{ + SfxDocumentInfoObject::setUserFieldValue( nIndex, aValue ); +} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxStandaloneDocumentInfoObject::loadFromURL(const ::rtl::OUString& aURL) + throw( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException ) +{ + sal_Bool bOK = sal_False; + + ::osl::ClearableMutexGuard aGuard( _pImp->_aMutex ); + uno::Reference< document::XDocumentProperties > xDocProps( + _xFactory->createInstance( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.document.DocumentProperties"))), uno::UNO_QUERY_THROW); +// uno::Reference< lang::XInitialization > xInit(xDocProps, uno::UNO_QUERY_THROW); +// xInit->initialize(uno::Sequence<uno::Any>()); + _pImp->Reset(xDocProps); + aGuard.clear(); + + uno::Reference< embed::XStorage > xStorage = GetStorage_Impl( aURL, sal_False, _xFactory ); + if ( xStorage.is() ) + { + try + { + uno::Sequence<beans::PropertyValue> medium(2); + medium[0].Name = ::rtl::OUString::createFromAscii("DocumentBaseURL"); + medium[0].Value <<= aURL; + medium[1].Name = ::rtl::OUString::createFromAscii("URL"); + medium[1].Value <<= aURL; + _pImp->m_xDocProps->loadFromStorage(xStorage, medium); + _pImp->Reset(_pImp->m_xDocProps); + bOK = sal_True; + } + catch( uno::Exception& ) + { + } + } + else + { + uno::Reference < document::XStandaloneDocumentInfo > xBinary( _xFactory->createInstance( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.BinaryStandaloneDocumentInfo" ) ) ), uno::UNO_QUERY ); + if ( xBinary.is() ) + { + xBinary->loadFromURL( aURL ); + bOK = sal_True; + uno::Reference < document::XStandaloneDocumentInfo > xTarget( static_cast < document::XStandaloneDocumentInfo*> (this), uno::UNO_QUERY ); + Copy( xBinary, xTarget ); + } + } + + if ( !bOK ) + throw task::ErrorCodeIOException( ::rtl::OUString(), uno::Reference< uno::XInterface >(), ERRCODE_IO_CANTREAD ); +} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxStandaloneDocumentInfoObject::storeIntoURL(const ::rtl::OUString& aURL) throw( ::com::sun::star::io::IOException ) +{ + sal_Bool bOK = sal_False; + uno::Reference< embed::XStorage > xStorage = GetStorage_Impl( aURL, sal_True, _xFactory ); + if ( xStorage.is() ) + { + try + { + uno::Sequence<beans::PropertyValue> medium(2); + medium[0].Name = ::rtl::OUString::createFromAscii("DocumentBaseURL"); + medium[0].Value <<= aURL; + medium[1].Name = ::rtl::OUString::createFromAscii("URL"); + medium[1].Value <<= aURL; + + _pImp->m_xDocProps->storeToStorage(xStorage, medium); + bOK = sal_True; + } + catch( io::IOException & ) + { + throw; + } + catch( uno::RuntimeException& ) + { + throw; + } + catch( uno::Exception& ) + { + } + } + else + { + uno::Reference < document::XStandaloneDocumentInfo > xBinary( _xFactory->createInstance( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.BinaryStandaloneDocumentInfo" ) ) ), uno::UNO_QUERY ); + if ( xBinary.is() ) + { + Copy( this, xBinary ); + xBinary->storeIntoURL( aURL ); + bOK = sal_True; + } + } + + if ( !bOK ) + throw task::ErrorCodeIOException( ::rtl::OUString(), uno::Reference< uno::XInterface >(), ERRCODE_IO_CANTWRITE ); +} + diff --git a/sfx2/source/doc/objxtor.cxx b/sfx2/source/doc/objxtor.cxx new file mode 100644 index 000000000000..b7567b89f02f --- /dev/null +++ b/sfx2/source/doc/objxtor.cxx @@ -0,0 +1,1125 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include "arrdecl.hxx" + +#include <cppuhelper/implbase1.hxx> + +#include <com/sun/star/util/XCloseable.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/util/XCloseBroadcaster.hpp> +#include <com/sun/star/util/XCloseListener.hpp> +#include <com/sun/star/util/XModifyBroadcaster.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XTitle.hpp> +#include <vos/mutex.hxx> + +#ifndef _SV_RESARY_HXX +#include <tools/resary.hxx> +#endif +#ifndef _MSGBOX_HXX //autogen +#include <vcl/msgbox.hxx> +#endif +#ifndef _WRKWIN_HXX //autogen +#include <vcl/wrkwin.hxx> +#endif +#include <vcl/svapp.hxx> +#include <svl/eitem.hxx> +#include <tools/rtti.hxx> +#include <svl/lstner.hxx> +#include <sfxhelp.hxx> +#include <basic/sbstar.hxx> +#include <svl/stritem.hxx> +#include <basic/sbx.hxx> +#include <unotools/eventcfg.hxx> + +#include <sfx2/objsh.hxx> +#include <sfx2/signaturestate.hxx> +#include <sfx2/sfxmodelfactory.hxx> + +#ifndef _BASIC_SBUNO_HXX +#include <basic/sbuno.hxx> +#endif +#include <svtools/sfxecode.hxx> +#include <svtools/ehdl.hxx> +#include <unotools/printwarningoptions.hxx> +#ifndef _UNOTOOLS_PROCESSFACTORY_HXX +#include <comphelper/processfactory.hxx> +#endif + +#include <com/sun/star/document/XStorageBasedDocument.hpp> +#include <com/sun/star/script/DocumentDialogLibraryContainer.hpp> +#include <com/sun/star/script/DocumentScriptLibraryContainer.hpp> +#include <com/sun/star/document/XEmbeddedScripts.hpp> +#include <com/sun/star/document/XScriptInvocationContext.hpp> + +#include <svl/urihelper.hxx> +#include <unotools/pathoptions.hxx> +#include <svl/sharecontrolfile.hxx> +#include <unotools/localfilehelper.hxx> +#include <unotools/ucbhelper.hxx> +#include <svtools/asynclink.hxx> +#include <tools/diagnose_ex.h> +#include <sot/clsids.hxx> + +#include <sfx2/app.hxx> +#include <sfx2/docfac.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/event.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/viewfrm.hxx> +#include "sfxresid.hxx" +#include "objshimp.hxx" +#include "appbas.hxx" +#include "sfxtypes.hxx" +#include <sfx2/evntconf.hxx> +#include <sfx2/request.hxx> +#include "doc.hrc" +#include "sfxlocal.hrc" +#include "appdata.hxx" +#include <sfx2/appuno.hxx> +#include <sfx2/sfxsids.hrc> +#include "basmgr.hxx" +#include "QuerySaveDocument.hxx" +#include "helpid.hrc" +#include <sfx2/msg.hxx> +#include "appbaslib.hxx" +#include <sfx2/sfxbasemodel.hxx> + +#include <basic/basicmanagerrepository.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::script; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::document; + +using ::basic::BasicManagerRepository; +#include <uno/mapping.hxx> + +//==================================================================== + +DBG_NAME(SfxObjectShell) + +#define DocumentInfo +#include "sfxslots.hxx" + +static WeakReference< XInterface > s_xCurrentComponent; + +//========================================================================= + + +//========================================================================= + +class SfxModelListener_Impl : public ::cppu::WeakImplHelper1< ::com::sun::star::util::XCloseListener > +{ + SfxObjectShell* mpDoc; +public: + SfxModelListener_Impl( SfxObjectShell* pDoc ) : mpDoc(pDoc) {}; + virtual void SAL_CALL queryClosing( const com::sun::star::lang::EventObject& aEvent, sal_Bool bDeliverOwnership ) + throw ( com::sun::star::uno::RuntimeException, com::sun::star::util::CloseVetoException) ; + virtual void SAL_CALL notifyClosing( const com::sun::star::lang::EventObject& aEvent ) throw ( com::sun::star::uno::RuntimeException ) ; + virtual void SAL_CALL disposing( const com::sun::star::lang::EventObject& aEvent ) throw ( com::sun::star::uno::RuntimeException ) ; + +}; + +void SAL_CALL SfxModelListener_Impl::queryClosing( const com::sun::star::lang::EventObject& , sal_Bool ) + throw ( com::sun::star::uno::RuntimeException, com::sun::star::util::CloseVetoException) +{ +} + +void SAL_CALL SfxModelListener_Impl::notifyClosing( const com::sun::star::lang::EventObject& ) throw ( com::sun::star::uno::RuntimeException ) +{ + ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + mpDoc->Broadcast( SfxSimpleHint(SFX_HINT_DEINITIALIZING) ); +} + +void SAL_CALL SfxModelListener_Impl::disposing( const com::sun::star::lang::EventObject& _rEvent ) throw ( com::sun::star::uno::RuntimeException ) +{ + // am I ThisComponent in AppBasic? + ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + if ( SfxObjectShell::GetCurrentComponent() == _rEvent.Source ) + { + // remove ThisComponent reference from AppBasic + SfxObjectShell::SetCurrentComponent( Reference< XInterface >() ); + } + + if ( mpDoc->Get_Impl()->bHiddenLockedByAPI ) + { + mpDoc->Get_Impl()->bHiddenLockedByAPI = FALSE; + mpDoc->OwnerLock(FALSE); + } + else if ( !mpDoc->Get_Impl()->bClosing ) + // GCC stuerzt ab, wenn schon im dtor, also vorher Flag abfragen + mpDoc->DoClose(); +} + +TYPEINIT1(SfxObjectShell, SfxShell); + +//-------------------------------------------------------------------- +SfxObjectShell_Impl::SfxObjectShell_Impl( SfxObjectShell& _rDocShell ) + :mpObjectContainer(0) + ,pBasicManager( new SfxBasicManagerHolder ) + ,rDocShell( _rDocShell ) + ,aMacroMode( *this ) + ,pProgress( 0) + ,nTime() + ,nVisualDocumentNumber( USHRT_MAX) + ,nDocumentSignatureState( SIGNATURESTATE_UNKNOWN ) + ,nScriptingSignatureState( SIGNATURESTATE_UNKNOWN ) + ,bInList( sal_False) + ,bClosing( sal_False) + ,bIsSaving( sal_False) + ,bPasswd( sal_False) + ,bIsTmp( sal_False) + ,bIsNamedVisible( sal_False) + ,bIsTemplate(sal_False) + ,bIsAbortingImport ( sal_False) + ,bImportDone ( sal_False) + ,bInPrepareClose( sal_False ) + ,bPreparedForClose( sal_False ) + ,bWaitingForPicklist( sal_True ) + ,bForbidReload( sal_False ) + ,bBasicInitialized( sal_False ) + ,bIsPrintJobCancelable( sal_True ) + ,bOwnsStorage( sal_True ) + ,bNoBaseURL( sal_False ) + ,bInitialized( sal_False ) + ,bSignatureErrorIsShown( sal_False ) + ,bModelInitialized( sal_False ) + ,bPreserveVersions( sal_True ) + ,m_bMacroSignBroken( sal_False ) + ,m_bNoBasicCapabilities( sal_False ) + ,m_bDocRecoverySupport( sal_True ) + ,bQueryLoadTemplate( sal_True ) + ,bLoadReadonly( sal_False ) + ,bUseUserData( sal_True ) + ,bSaveVersionOnClose( sal_False ) + ,m_bSharedXMLFlag( sal_False ) + ,m_bAllowShareControlFileClean( sal_True ) + ,lErr(ERRCODE_NONE) + ,nEventId ( 0) + ,pReloadTimer ( 0) + ,pMarkData( 0 ) + ,nLoadedFlags ( SFX_LOADED_ALL ) + ,nFlagsInProgress( 0 ) + ,bModalMode( sal_False ) + ,bRunningMacro( sal_False ) + ,bReloadAvailable( sal_False ) + ,nAutoLoadLocks( 0 ) + ,pModule( 0 ) + ,eFlags( SFXOBJECTSHELL_UNDEFINED ) + ,bReadOnlyUI( sal_False ) + ,bHiddenLockedByAPI( sal_False ) + ,nStyleFilter( 0 ) + ,bDisposing( sal_False ) + ,m_bEnableSetModified( sal_True ) + ,m_bIsModified( sal_False ) + ,m_nMapUnit( MAP_100TH_MM ) + ,m_bCreateTempStor( sal_False ) + ,m_bIsInit( sal_False ) + ,m_bIncomplEncrWarnShown( sal_False ) + ,m_nModifyPasswordHash( 0 ) + ,m_bModifyPasswordEntered( sal_False ) +{ + SfxObjectShell* pDoc = &_rDocShell; + SfxObjectShellArr_Impl &rArr = SFX_APP()->GetObjectShells_Impl(); + rArr.C40_INSERT( SfxObjectShell, pDoc, rArr.Count() ); + bInList = sal_True; +} + +//-------------------------------------------------------------------- + +SfxObjectShell_Impl::~SfxObjectShell_Impl() +{ + delete pBasicManager; +} + +//-------------------------------------------------------------------- + +SfxObjectShell::SfxObjectShell( const sal_uInt64 i_nCreationFlags ) + : pImp( new SfxObjectShell_Impl( *this ) ) + , pMedium(0) + , pStyleSheetPool(0) + , eCreateMode( ( i_nCreationFlags & SFXMODEL_EMBEDDED_OBJECT ) ? SFX_CREATE_MODE_EMBEDDED : SFX_CREATE_MODE_STANDARD ) + , bHasName( sal_False ) +{ + DBG_CTOR(SfxObjectShell, 0); + + const bool bScriptSupport = ( i_nCreationFlags & SFXMODEL_DISABLE_EMBEDDED_SCRIPTS ) == 0; + if ( !bScriptSupport ) + SetHasNoBasic(); + + const bool bDocRecovery = ( i_nCreationFlags & SFXMODEL_DISABLE_DOCUMENT_RECOVERY ) == 0; + if ( !bDocRecovery ) + pImp->m_bDocRecoverySupport = sal_False; +} + +//-------------------------------------------------------------------- + +// initializes a document from a file-description + +SfxObjectShell::SfxObjectShell +( + SfxObjectCreateMode eMode /* Zweck, zu dem die SfxObjectShell + erzeugt wird: + + SFX_CREATE_MODE_EMBEDDED (default) + als SO-Server aus einem anderen + Dokument heraus + + SFX_CREATE_MODE_STANDARD, + als normales, selbst"aendig ge"offnetes + Dokument + + SFX_CREATE_MODE_PREVIEW + um ein Preview durchzuf"uhren, + ggf. werden weniger Daten ben"otigt + + SFX_CREATE_MODE_ORGANIZER + um im Organizer dargestellt zu + werden, hier werden keine Inhalte + ben"otigt */ +) + +/* [Beschreibung] + + Konstruktor der Klasse SfxObjectShell. +*/ + +: pImp( new SfxObjectShell_Impl( *this ) ), + pMedium(0), + pStyleSheetPool(0), + eCreateMode(eMode), + bHasName( sal_False ) +{ + DBG_CTOR(SfxObjectShell, 0); +} + +//-------------------------------------------------------------------- + +// virtual dtor of typical base-class SfxObjectShell + +SfxObjectShell::~SfxObjectShell() +{ + DBG_DTOR(SfxObjectShell, 0); + + if ( IsEnableSetModified() ) + EnableSetModified( sal_False ); + + // Niemals GetInPlaceObject() aufrufen, der Zugriff auf den + // Ableitungszweig SfxInternObject ist wegen eines Compiler Bugs nicht + // erlaubt + SfxObjectShell::Close(); + pImp->pBaseModel.set( NULL ); + + DELETEX(pImp->pReloadTimer ); + + SfxApplication *pSfxApp = SFX_APP(); + if ( USHRT_MAX != pImp->nVisualDocumentNumber ) + pSfxApp->ReleaseIndex(pImp->nVisualDocumentNumber); + + // Basic-Manager zerst"oren + pImp->pBasicManager->reset( NULL ); + + if ( pSfxApp->GetDdeService() ) + pSfxApp->RemoveDdeTopic( this ); + + pImp->pBaseModel.set( NULL ); + + // don't call GetStorage() here, in case of Load Failure it's possible that a storage was never assigned! + if ( pMedium && pMedium->HasStorage_Impl() && pMedium->GetStorage( sal_False ) == pImp->m_xDocStorage ) + pMedium->CanDisposeStorage_Impl( sal_False ); + + if ( pImp->mpObjectContainer ) + { + pImp->mpObjectContainer->CloseEmbeddedObjects(); + delete pImp->mpObjectContainer; + } + + if ( pImp->bOwnsStorage && pImp->m_xDocStorage.is() ) + pImp->m_xDocStorage->dispose(); + + if ( pMedium ) + { + pMedium->CloseAndReleaseStreams_Impl(); + + if ( IsDocShared() ) + FreeSharedFile(); + + DELETEX( pMedium ); + } + + // The removing of the temporary file must be done as the latest step in the document destruction + if ( pImp->aTempName.Len() ) + { + String aTmp; + ::utl::LocalFileHelper::ConvertPhysicalNameToURL( pImp->aTempName, aTmp ); + ::utl::UCBContentHelper::Kill( aTmp ); + } + + delete pImp; +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::Stamp_SetPrintCancelState(sal_Bool bState) +{ + pImp->bIsPrintJobCancelable = bState; +} + +//-------------------------------------------------------------------- + +sal_Bool SfxObjectShell::Stamp_GetPrintCancelState() const +{ + return pImp->bIsPrintJobCancelable; +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::ViewAssigned() + +/* [Beschreibung] + + Diese Methode wird gerufen, wenn eine View zugewiesen wird. +*/ + +{ +} + +//-------------------------------------------------------------------- +// closes the Object and all its views + +sal_Bool SfxObjectShell::Close() +{ + {DBG_CHKTHIS(SfxObjectShell, 0);} + SfxObjectShellRef aRef(this); + if ( !pImp->bClosing ) + { + // falls noch ein Progress l"auft, nicht schlie\sen + if ( !pImp->bDisposing && GetProgress() ) + return sal_False; + + pImp->bClosing = sal_True; + Reference< util::XCloseable > xCloseable( GetBaseModel(), UNO_QUERY ); + + if ( xCloseable.is() ) + { + try + { + xCloseable->close( sal_True ); + } + catch( Exception& ) + { + pImp->bClosing = sal_False; + } + } + + if ( pImp->bClosing ) + { + // aus Document-Liste austragen + SfxApplication *pSfxApp = SFX_APP(); + SfxObjectShellArr_Impl &rDocs = pSfxApp->GetObjectShells_Impl(); + const SfxObjectShell *pThis = this; + sal_uInt16 nPos = rDocs.GetPos(pThis); + if ( nPos < rDocs.Count() ) + rDocs.Remove( nPos ); + pImp->bInList = sal_False; + } + } + + return sal_True; +} + +//-------------------------------------------------------------------- + +// returns a pointer the first SfxDocument of specified type + +SfxObjectShell* SfxObjectShell::GetFirst +( + const TypeId* pType , + sal_Bool bOnlyVisible +) +{ + SfxObjectShellArr_Impl &rDocs = SFX_APP()->GetObjectShells_Impl(); + + // seach for a SfxDocument of the specified type + for ( sal_uInt16 nPos = 0; nPos < rDocs.Count(); ++nPos ) + { + SfxObjectShell* pSh = rDocs.GetObject( nPos ); + if ( bOnlyVisible && pSh->IsPreview() && pSh->IsReadOnly() ) + continue; + + if ( ( !pType || pSh->IsA(*pType) ) && + ( !bOnlyVisible || SfxViewFrame::GetFirst( pSh, sal_True ))) + return pSh; + } + + return 0; +} +//-------------------------------------------------------------------- + +// returns a pointer to the next SfxDocument of specified type behind *pDoc + +SfxObjectShell* SfxObjectShell::GetNext +( + const SfxObjectShell& rPrev, + const TypeId* pType, + sal_Bool bOnlyVisible +) +{ + SfxObjectShellArr_Impl &rDocs = SFX_APP()->GetObjectShells_Impl(); + + // refind the specified predecessor + sal_uInt16 nPos; + for ( nPos = 0; nPos < rDocs.Count(); ++nPos ) + if ( rDocs.GetObject(nPos) == &rPrev ) + break; + + // search for the next SfxDocument of the specified type + for ( ++nPos; nPos < rDocs.Count(); ++nPos ) + { + SfxObjectShell* pSh = rDocs.GetObject( nPos ); + if ( bOnlyVisible && pSh->IsPreview() && pSh->IsReadOnly() ) + continue; + + if ( ( !pType || pSh->IsA(*pType) ) && + ( !bOnlyVisible || SfxViewFrame::GetFirst( pSh, sal_True ))) + return pSh; + } + return 0; +} + +//-------------------------------------------------------------------- + +SfxObjectShell* SfxObjectShell::Current() +{ + SfxViewFrame *pFrame = SfxViewFrame::Current(); + return pFrame ? pFrame->GetObjectShell() : 0; +} + +//------------------------------------------------------------------------- + +sal_Bool SfxObjectShell::IsInPrepareClose() const +{ + return pImp->bInPrepareClose; +} + +//------------------------------------------------------------------------ + +struct BoolEnv_Impl +{ + SfxObjectShell_Impl* pImp; + BoolEnv_Impl( SfxObjectShell_Impl* pImpP) : pImp( pImpP ) + { pImpP->bInPrepareClose = sal_True; } + ~BoolEnv_Impl() { pImp->bInPrepareClose = sal_False; } +}; + + +sal_uInt16 SfxObjectShell::PrepareClose +( + sal_Bool bUI, // sal_True: Dialoge etc. erlaubt, sal_False: silent-mode + sal_Bool bForBrowsing +) +{ + if( pImp->bInPrepareClose || pImp->bPreparedForClose ) + return sal_True; + BoolEnv_Impl aBoolEnv( pImp ); + + // DocModalDialog? + if ( IsInModalMode() ) + return sal_False; + + SfxViewFrame* pFirst = SfxViewFrame::GetFirst( this ); + if( pFirst && !pFirst->GetFrame().PrepareClose_Impl( bUI, bForBrowsing ) ) + return sal_False; + + // prepare views for closing + for ( SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this ); + pFrm; pFrm = SfxViewFrame::GetNext( *pFrm, this ) ) + { + DBG_ASSERT(pFrm->GetViewShell(),"KeineShell"); + if ( pFrm->GetViewShell() ) + { + sal_uInt16 nRet = pFrm->GetViewShell()->PrepareClose( bUI, bForBrowsing ); + if ( nRet != sal_True ) + return nRet; + } + } + + SfxApplication *pSfxApp = SFX_APP(); + pSfxApp->NotifyEvent( SfxEventHint(SFX_EVENT_PREPARECLOSEDOC, GlobalEventConfig::GetEventName(STR_EVENT_PREPARECLOSEDOC), this) ); + + if( GetCreateMode() == SFX_CREATE_MODE_EMBEDDED ) + { + pImp->bPreparedForClose = sal_True; + return sal_True; + } + + // ggf. nachfragen, ob gespeichert werden soll + // nur fuer in sichtbaren Fenstern dargestellte Dokumente fragen + SfxViewFrame *pFrame = SfxObjectShell::Current() == this + ? SfxViewFrame::Current() : SfxViewFrame::GetFirst( this ); + + sal_Bool bClose = sal_False; + if ( bUI && IsModified() && pFrame ) + { + // minimierte restoren + SfxFrame& rTop = pFrame->GetTopFrame(); + SfxViewFrame::SetViewFrame( rTop.GetCurrentViewFrame() ); + pFrame->GetFrame().Appear(); + + // fragen, ob gespeichert werden soll + short nRet = RET_YES; + //TODO/CLEANUP + //brauchen wir UI=2 noch? + //if( SfxApplication::IsPlugin() == sal_False || bUI == 2 ) + { + //initiate help agent to inform about "print modifies the document" + SvtPrintWarningOptions aPrintOptions; + if (aPrintOptions.IsModifyDocumentOnPrintingAllowed() && + HasName() && getDocProperties()->getPrintDate().Month > 0) + { + SfxHelp::OpenHelpAgent( &pFirst->GetFrame(), HID_CLOSE_WARNING ); + } + const Reference< XTitle > xTitle( *pImp->pBaseModel.get(), UNO_QUERY_THROW ); + const ::rtl::OUString sTitle = xTitle->getTitle (); + nRet = ExecuteQuerySaveDocument(&pFrame->GetWindow(),sTitle); + } + /*HACK for plugin::destroy()*/ + + if ( RET_YES == nRet ) + { + // per Dispatcher speichern + const SfxPoolItem *pPoolItem; + if ( IsSaveVersionOnClose() ) + { + SfxStringItem aItem( SID_DOCINFO_COMMENTS, String( SfxResId( STR_AUTOMATICVERSION ) ) ); + SfxBoolItem aWarnItem( SID_FAIL_ON_WARNING, bUI ); + const SfxPoolItem* ppArgs[] = { &aItem, &aWarnItem, 0 }; + pPoolItem = pFrame->GetBindings().ExecuteSynchron( SID_SAVEDOC, ppArgs ); + } + else + { + SfxBoolItem aWarnItem( SID_FAIL_ON_WARNING, bUI ); + const SfxPoolItem* ppArgs[] = { &aWarnItem, 0 }; + pPoolItem = pFrame->GetBindings().ExecuteSynchron( SID_SAVEDOC, ppArgs ); + } + + if ( !pPoolItem || pPoolItem->ISA(SfxVoidItem) || ( pPoolItem->ISA(SfxBoolItem) && !( (const SfxBoolItem*) pPoolItem )->GetValue() ) ) + return sal_False; + else + bClose = sal_True; + } + else if ( RET_CANCEL == nRet ) + // abgebrochen + return sal_False; + else if ( RET_NEWTASK == nRet ) + { + return RET_NEWTASK; + } + else + { + // Bei Nein nicht noch Informationlost + bClose = sal_True; + } + } + + pImp->bPreparedForClose = sal_True; + return sal_True; +} + +//-------------------------------------------------------------------- +namespace +{ + static BasicManager* lcl_getBasicManagerForDocument( const SfxObjectShell& _rDocument ) + { + if ( !_rDocument.Get_Impl()->m_bNoBasicCapabilities ) + { + if ( !_rDocument.Get_Impl()->bBasicInitialized ) + const_cast< SfxObjectShell& >( _rDocument ).InitBasicManager_Impl(); + return _rDocument.Get_Impl()->pBasicManager->get(); + } + + // assume we do not have Basic ourself, but we can refer to another + // document which does (by our model's XScriptInvocationContext::getScriptContainer). + // In this case, we return the BasicManager of this other document. + + OSL_ENSURE( !Reference< XEmbeddedScripts >( _rDocument.GetModel(), UNO_QUERY ).is(), + "lcl_getBasicManagerForDocument: inconsistency: no Basic, but an XEmbeddedScripts?" ); + Reference< XModel > xForeignDocument; + Reference< XScriptInvocationContext > xContext( _rDocument.GetModel(), UNO_QUERY ); + if ( xContext.is() ) + { + xForeignDocument.set( xContext->getScriptContainer(), UNO_QUERY ); + OSL_ENSURE( xForeignDocument.is() && xForeignDocument != _rDocument.GetModel(), + "lcl_getBasicManagerForDocument: no Basic, but providing ourself as script container?" ); + } + + BasicManager* pBasMgr = NULL; + if ( xForeignDocument.is() ) + pBasMgr = ::basic::BasicManagerRepository::getDocumentBasicManager( xForeignDocument ); + + return pBasMgr; + } +} + +//-------------------------------------------------------------------- + +BasicManager* SfxObjectShell::GetBasicManager() const +{ + BasicManager* pBasMgr = lcl_getBasicManagerForDocument( *this ); + if ( !pBasMgr ) + pBasMgr = SFX_APP()->GetBasicManager(); + return pBasMgr; +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::SetHasNoBasic() +{ + pImp->m_bNoBasicCapabilities = sal_True; +} + +//-------------------------------------------------------------------- + +sal_Bool SfxObjectShell::HasBasic() const +{ + if ( pImp->m_bNoBasicCapabilities ) + return sal_False; + + if ( !pImp->bBasicInitialized ) + const_cast< SfxObjectShell* >( this )->InitBasicManager_Impl(); + + return pImp->pBasicManager->isValid(); +} + +//-------------------------------------------------------------------- +namespace +{ + const Reference< XLibraryContainer >& + lcl_getOrCreateLibraryContainer( bool _bScript, Reference< XLibraryContainer >& _rxContainer, + const Reference< XModel >& _rxDocument ) + { + if ( !_rxContainer.is() ) + { + try + { + Reference< XStorageBasedDocument > xStorageDoc( _rxDocument, UNO_QUERY ); + const Reference< XComponentContext > xContext( + ::comphelper::getProcessComponentContext() ); + _rxContainer.set ( _bScript + ? DocumentScriptLibraryContainer::create( + xContext, xStorageDoc ) + : DocumentDialogLibraryContainer::create( + xContext, xStorageDoc ) + , UNO_QUERY_THROW ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + return _rxContainer; + } +} + +//-------------------------------------------------------------------- + +Reference< XLibraryContainer > SfxObjectShell::GetDialogContainer() +{ + if ( !pImp->m_bNoBasicCapabilities ) + return lcl_getOrCreateLibraryContainer( false, pImp->xDialogLibraries, GetModel() ); + + BasicManager* pBasMgr = lcl_getBasicManagerForDocument( *this ); + if ( pBasMgr ) + return pBasMgr->GetDialogLibraryContainer().get(); + + OSL_ENSURE( false, "SfxObjectShell::GetDialogContainer: falling back to the application - is this really expected here?" ); + return SFX_APP()->GetDialogContainer(); +} + +//-------------------------------------------------------------------- + +Reference< XLibraryContainer > SfxObjectShell::GetBasicContainer() +{ + if ( !pImp->m_bNoBasicCapabilities ) + return lcl_getOrCreateLibraryContainer( true, pImp->xBasicLibraries, GetModel() ); + + BasicManager* pBasMgr = lcl_getBasicManagerForDocument( *this ); + if ( pBasMgr ) + return pBasMgr->GetScriptLibraryContainer().get(); + + OSL_ENSURE( false, "SfxObjectShell::GetBasicContainer: falling back to the application - is this really expected here?" ); + return SFX_APP()->GetBasicContainer(); +} + +//-------------------------------------------------------------------- + +StarBASIC* SfxObjectShell::GetBasic() const +{ + return GetBasicManager()->GetLib(0); +} + +//-------------------------------------------------------------------- + +void SfxObjectShell::InitBasicManager_Impl() +/* [Beschreibung] + + creates a document's BasicManager and loads it, if we are already based on + a storage. + + [Anmerkung] + + Diese Methode mu"s aus den "Uberladungen von <SvPersist::Load()> (mit + dem pStor aus dem Parameter von Load()) sowie aus der "Uberladung + von <SvPersist::InitNew()> (mit pStor = 0) gerufen werden. +*/ + +{ + DBG_ASSERT( !pImp->bBasicInitialized && !pImp->pBasicManager->isValid(), "Lokaler BasicManager bereits vorhanden"); + pImp->bBasicInitialized = TRUE; + + pImp->pBasicManager->reset( BasicManagerRepository::getDocumentBasicManager( GetModel() ) ); + DBG_ASSERT( pImp->pBasicManager->isValid(), "SfxObjectShell::InitBasicManager_Impl: did not get a BasicManager!" ); +} + +//-------------------------------------------------------------------- +#if 0 //(mba) +SotObjectRef SfxObjectShell::CreateAggObj( const SotFactory* pFact ) +{ + // SvDispatch? + SotFactory* pDispFact = SvDispatch::ClassFactory(); + if( pFact == pDispFact ) + return( (SfxShellObject*)GetSbxObject() ); + + // sonst unbekannte Aggregation + DBG_ERROR("unkekannte Factory"); + SotObjectRef aSvObjectRef; + return aSvObjectRef; +} +#endif + +//-------------------------------------------------------------------- + +sal_uInt16 SfxObjectShell::Count() +{ + return SFX_APP()->GetObjectShells_Impl().Count(); +} + +//-------------------------------------------------------------------- + +sal_Bool SfxObjectShell::DoClose() +{ + return Close(); +} + +//-------------------------------------------------------------------- + +SfxObjectShell* SfxObjectShell::GetObjectShell() +{ + return this; +} + +//-------------------------------------------------------------------- + +SEQUENCE< OUSTRING > SfxObjectShell::GetEventNames() +{ + static uno::Sequence< ::rtl::OUString >* pEventNameContainer = NULL; + + if ( !pEventNameContainer ) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( !pEventNameContainer ) + { + static uno::Sequence< ::rtl::OUString > aEventNameContainer = GlobalEventConfig().getElementNames(); + pEventNameContainer = &aEventNameContainer; + } + } + + return *pEventNameContainer; +} + +//-------------------------------------------------------------------- + +::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel > SfxObjectShell::GetModel() const +{ + return GetBaseModel(); +} + +void SfxObjectShell::SetBaseModel( SfxBaseModel* pModel ) +{ + OSL_ENSURE( !pImp->pBaseModel.is() || pModel == NULL, "Model already set!" ); + pImp->pBaseModel.set( pModel ); + if ( pImp->pBaseModel.is() ) + { + pImp->pBaseModel->addCloseListener( new SfxModelListener_Impl(this) ); + } +} + +//-------------------------------------------------------------------- + +::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel > SfxObjectShell::GetBaseModel() const +{ + return pImp->pBaseModel.get(); +} +/* -----------------------------10.09.2001 15:56------------------------------ + + ---------------------------------------------------------------------------*/ +void SfxObjectShell::SetAutoStyleFilterIndex(sal_uInt16 nSet) +{ + pImp->nStyleFilter = nSet; +} + +sal_uInt16 SfxObjectShell::GetAutoStyleFilterIndex() +{ + return pImp->nStyleFilter; +} + + +void SfxObjectShell::SetCurrentComponent( const Reference< XInterface >& _rxComponent ) +{ + Reference< XInterface > xTest(s_xCurrentComponent); + if ( _rxComponent == xTest ) + // nothing to do + return; + // note that "_rxComponent.get() == s_xCurrentComponent.get().get()" is /sufficient/, but not + // /required/ for "_rxComponent == s_xCurrentComponent.get()". + // In other words, it's still possible that we here do something which is not necessary, + // but we should have filtered quite some unnecessary calls already. + + BasicManager* pAppMgr = SFX_APP()->GetBasicManager(); + s_xCurrentComponent = _rxComponent; + if ( pAppMgr ) + pAppMgr->SetGlobalUNOConstant( "ThisComponent", makeAny( _rxComponent ) ); + +#if OSL_DEBUG_LEVEL > 0 + const char* pComponentImplName = _rxComponent.get() ? typeid( *_rxComponent.get() ).name() : "void"; + OSL_TRACE( "current component is a %s\n", pComponentImplName ); +#endif +} + +Reference< XInterface > SfxObjectShell::GetCurrentComponent() +{ + return s_xCurrentComponent; +} + + +String SfxObjectShell::GetServiceNameFromFactory( const String& rFact ) +{ + //! Remove everything behind name! + String aFact( rFact ); + String aPrefix = String::CreateFromAscii( "private:factory/" ); + if ( aPrefix.Len() == aFact.Match( aPrefix ) ) + aFact.Erase( 0, aPrefix.Len() ); + USHORT nPos = aFact.Search( '?' ); + String aParam; + if ( nPos != STRING_NOTFOUND ) + { + aParam = aFact.Copy( nPos, aFact.Len() ); + aFact.Erase( nPos, aFact.Len() ); + aParam.Erase(0,1); + } + aFact.EraseAllChars('4').ToLowerAscii(); + + // HACK: sometimes a real document service name is given here instead of + // a factory short name. Set return value directly to this service name as fallback + // in case next lines of code does nothing ... + // use rFact instead of normed aFact value ! + ::rtl::OUString aServiceName = rFact; + + if ( aFact.EqualsAscii("swriter") ) + { + aServiceName = ::rtl::OUString::createFromAscii("com.sun.star.text.TextDocument"); + } + else if ( aFact.EqualsAscii("sweb") || aFact.EqualsAscii("swriter/web") ) + { + aServiceName = ::rtl::OUString::createFromAscii("com.sun.star.text.WebDocument"); + } + else if ( aFact.EqualsAscii("sglobal") || aFact.EqualsAscii("swriter/globaldocument") ) + { + aServiceName = ::rtl::OUString::createFromAscii("com.sun.star.text.GlobalDocument"); + } + else if ( aFact.EqualsAscii("scalc") ) + { + aServiceName = ::rtl::OUString::createFromAscii("com.sun.star.sheet.SpreadsheetDocument"); + } + else if ( aFact.EqualsAscii("sdraw") ) + { + aServiceName = ::rtl::OUString::createFromAscii("com.sun.star.drawing.DrawingDocument"); + } + else if ( aFact.EqualsAscii("simpress") ) + { + aServiceName = ::rtl::OUString::createFromAscii("com.sun.star.presentation.PresentationDocument"); + } + else if ( aFact.EqualsAscii("schart") ) + { + aServiceName = ::rtl::OUString::createFromAscii("com.sun.star.chart.ChartDocument"); + } + else if ( aFact.EqualsAscii("smath") ) + { + aServiceName = ::rtl::OUString::createFromAscii("com.sun.star.formula.FormulaProperties"); + } + else if ( aFact.EqualsAscii("sbasic") ) + { + aServiceName = ::rtl::OUString::createFromAscii("com.sun.star.script.BasicIDE"); + } + else if ( aFact.EqualsAscii("sdatabase") ) + { + aServiceName = ::rtl::OUString::createFromAscii("com.sun.star.sdb.OfficeDatabaseDocument"); + } + + return aServiceName; +} + +SfxObjectShell* SfxObjectShell::CreateObjectByFactoryName( const String& rFact, SfxObjectCreateMode eMode ) +{ + return CreateObject( GetServiceNameFromFactory( rFact ), eMode ); +} + + +SfxObjectShell* SfxObjectShell::CreateObject( const String& rServiceName, SfxObjectCreateMode eCreateMode ) +{ + if ( rServiceName.Len() ) + { + ::com::sun::star::uno::Reference < ::com::sun::star::frame::XModel > xDoc( + ::comphelper::getProcessServiceFactory()->createInstance( rServiceName ), UNO_QUERY ); + if ( xDoc.is() ) + { + ::com::sun::star::uno::Reference < ::com::sun::star::lang::XUnoTunnel > xObj( xDoc, UNO_QUERY ); + ::com::sun::star::uno::Sequence < sal_Int8 > aSeq( SvGlobalName( SFX_GLOBAL_CLASSID ).GetByteSequence() ); + sal_Int64 nHandle = xObj->getSomething( aSeq ); + if ( nHandle ) + { + SfxObjectShell* pRet = reinterpret_cast< SfxObjectShell* >( sal::static_int_cast< sal_IntPtr >( nHandle )); + pRet->SetCreateMode_Impl( eCreateMode ); + return pRet; + } + } + } + + return 0; +} + +SfxObjectShell* SfxObjectShell::CreateAndLoadObject( const SfxItemSet& rSet, SfxFrame* pFrame ) +{ + uno::Sequence < beans::PropertyValue > aProps; + TransformItems( SID_OPENDOC, rSet, aProps ); + SFX_ITEMSET_ARG(&rSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, FALSE); + SFX_ITEMSET_ARG(&rSet, pTargetItem, SfxStringItem, SID_TARGETNAME, FALSE); + ::rtl::OUString aURL; + ::rtl::OUString aTarget = rtl::OUString::createFromAscii("_blank"); + if ( pFileNameItem ) + aURL = pFileNameItem->GetValue(); + if ( pTargetItem ) + aTarget = pTargetItem->GetValue(); + + uno::Reference < frame::XComponentLoader > xLoader; + if ( pFrame ) + { + xLoader = uno::Reference < frame::XComponentLoader >( pFrame->GetFrameInterface(), uno::UNO_QUERY ); + } + else + xLoader = uno::Reference < frame::XComponentLoader >( comphelper::getProcessServiceFactory()->createInstance( + ::rtl::OUString::createFromAscii("com.sun.star.frame.Desktop") ), uno::UNO_QUERY ); + + uno::Reference < lang::XUnoTunnel > xObj; + try + { + xObj = uno::Reference< lang::XUnoTunnel >( xLoader->loadComponentFromURL( aURL, aTarget, 0, aProps ), uno::UNO_QUERY ); + } + catch( uno::Exception& ) + {} + + if ( xObj.is() ) + { + ::com::sun::star::uno::Sequence < sal_Int8 > aSeq( SvGlobalName( SFX_GLOBAL_CLASSID ).GetByteSequence() ); + sal_Int64 nHandle = xObj->getSomething( aSeq ); + if ( nHandle ) + return reinterpret_cast< SfxObjectShell* >(sal::static_int_cast< sal_IntPtr >( nHandle )); + } + + return NULL; +} + +void SfxObjectShell::SetInitialized_Impl( const bool i_fromInitNew ) +{ + pImp->bInitialized = sal_True; + if ( i_fromInitNew ) + { + SetActivateEvent_Impl( SFX_EVENT_CREATEDOC ); + SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_DOCCREATED, GlobalEventConfig::GetEventName(STR_EVENT_DOCCREATED), this ) ); + } + else + { + SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_LOADFINISHED, GlobalEventConfig::GetEventName(STR_EVENT_LOADFINISHED), this ) ); + } +} + + +bool SfxObjectShell::IsChangeRecording() const +{ + // currently this function needs to be overwritten by Writer and Calc only + DBG_ASSERT( 0, "function not implemented" ); + return false; +} + + +bool SfxObjectShell::HasChangeRecordProtection() const +{ + // currently this function needs to be overwritten by Writer and Calc only + DBG_ASSERT( 0, "function not implemented" ); + return false; +} + + +void SfxObjectShell::SetChangeRecording( bool /*bActivate*/ ) +{ + // currently this function needs to be overwritten by Writer and Calc only + DBG_ASSERT( 0, "function not implemented" ); +} + + +bool SfxObjectShell::SetProtectionPassword( const String & /*rPassword*/ ) +{ + // currently this function needs to be overwritten by Writer and Calc only + DBG_ASSERT( 0, "function not implemented" ); + return false; +} + + +bool SfxObjectShell::GetProtectionHash( /*out*/ ::com::sun::star::uno::Sequence< sal_Int8 > & /*rPasswordHash*/ ) +{ + // currently this function needs to be overwritten by Writer and Calc only + DBG_ASSERT( 0, "function not implemented" ); + return false; +} + diff --git a/sfx2/source/doc/oleprops.cxx b/sfx2/source/doc/oleprops.cxx new file mode 100755 index 000000000000..d6192542d1a1 --- /dev/null +++ b/sfx2/source/doc/oleprops.cxx @@ -0,0 +1,1227 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include "oleprops.hxx" + +#include <comphelper/types.hxx> +#include <tools/debug.hxx> +#include <tools/datetime.hxx> +#include <rtl/tencinfo.h> + +// ============================================================================ + + +// ============================================================================ + +#define VERSION 11 +#define STREAM_BUFFER_SIZE 2048 + +// usings +using ::rtl::OUString; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::makeAny; + +using namespace ::com::sun::star; + +#define TIMESTAMP_INVALID_DATETIME ( DateTime ( Date ( 1, 1, 1601 ), Time ( 0, 0, 0 ) ) ) /// Invalid value for date and time to create invalid instance of TimeStamp. +#define TIMESTAMP_INVALID_UTILDATETIME ( util::DateTime ( 0, 0, 0, 0, 1, 1, 1601 ) ) /// Invalid value for date and time to create invalid instance of TimeStamp. + +static +bool operator==(const util::DateTime &i_rLeft, const util::DateTime &i_rRight) +{ + return i_rLeft.Year == i_rRight.Year + && i_rLeft.Month == i_rRight.Month + && i_rLeft.Day == i_rRight.Day + && i_rLeft.Hours == i_rRight.Hours + && i_rLeft.Minutes == i_rRight.Minutes + && i_rLeft.Seconds == i_rRight.Seconds + && i_rLeft.HundredthSeconds == i_rRight.HundredthSeconds; +} + +// ============================================================================ + +/** Property representing a signed 32-bit integer value. */ +class SfxOleInt32Property : public SfxOlePropertyBase +{ +public: + explicit SfxOleInt32Property( sal_Int32 nPropId, sal_Int32 nValue = 0 ); + + inline sal_Int32 GetValue() const { return mnValue; } + inline void SetValue( sal_Int32 nValue ) { mnValue = nValue; } + +private: + virtual void ImplLoad( SvStream& rStrm ); + virtual void ImplSave( SvStream& rStrm ); + +private: + sal_Int32 mnValue; +}; + +// ============================================================================ + +/** Property representing a floating-point value. */ +class SfxOleDoubleProperty : public SfxOlePropertyBase +{ +public: + explicit SfxOleDoubleProperty( sal_Int32 nPropId, double fValue = 0.0 ); + + inline double GetValue() const { return mfValue; } + inline void SetValue( double fValue ) { mfValue = fValue; } + +private: + virtual void ImplLoad( SvStream& rStrm ); + virtual void ImplSave( SvStream& rStrm ); + +private: + double mfValue; +}; + +// ============================================================================ + +/** Property representing a boolean value. */ +class SfxOleBoolProperty : public SfxOlePropertyBase +{ +public: + explicit SfxOleBoolProperty( sal_Int32 nPropId, bool bValue = false ); + + inline bool GetValue() const { return mbValue; } + inline void SetValue( bool bValue ) { mbValue = bValue; } + +private: + virtual void ImplLoad( SvStream& rStrm ); + virtual void ImplSave( SvStream& rStrm ); + +private: + bool mbValue; +}; + +// ============================================================================ + +/** Base class for properties that contain a single string value. */ +class SfxOleStringPropertyBase : public SfxOlePropertyBase, public SfxOleStringHelper +{ +public: + explicit SfxOleStringPropertyBase( + sal_Int32 nPropId, sal_Int32 nPropType, + const SfxOleTextEncoding& rTextEnc ); + explicit SfxOleStringPropertyBase( + sal_Int32 nPropId, sal_Int32 nPropType, + const SfxOleTextEncoding& rTextEnc, const String& rValue ); + explicit SfxOleStringPropertyBase( + sal_Int32 nPropId, sal_Int32 nPropType, + rtl_TextEncoding eTextEnc ); + explicit SfxOleStringPropertyBase( + sal_Int32 nPropId, sal_Int32 nPropType, + rtl_TextEncoding eTextEnc, const String& rValue ); + + inline const String& GetValue() const { return maValue; } + inline void SetValue( const String& rValue ) { maValue = rValue; } + +private: + String maValue; +}; + +// ============================================================================ + +/** Property representing a bytestring value. */ +class SfxOleString8Property : public SfxOleStringPropertyBase +{ +public: + explicit SfxOleString8Property( + sal_Int32 nPropId, const SfxOleTextEncoding& rTextEnc ); + explicit SfxOleString8Property( + sal_Int32 nPropId, const SfxOleTextEncoding& rTextEnc, + const String& rValue ); + +private: + virtual void ImplLoad( SvStream& rStrm ); + virtual void ImplSave( SvStream& rStrm ); +}; + +// ============================================================================ + +/** Property representing a Unicode string value. */ +class SfxOleString16Property : public SfxOleStringPropertyBase +{ +public: + explicit SfxOleString16Property( sal_Int32 nPropId ); + explicit SfxOleString16Property( sal_Int32 nPropId, const String& rValue ); + +private: + virtual void ImplLoad( SvStream& rStrm ); + virtual void ImplSave( SvStream& rStrm ); +}; + +// ============================================================================ + +/** Property representing a filetime value as defined by the Windows API. */ +class SfxOleFileTimeProperty : public SfxOlePropertyBase +{ +public: + explicit SfxOleFileTimeProperty( sal_Int32 nPropId ); + /** @param rDateTime Date and time as LOCAL time. */ + explicit SfxOleFileTimeProperty( sal_Int32 nPropId, const util::DateTime& rDateTime ); + + /** Returns the time value as LOCAL time. */ + inline const util::DateTime& GetValue() const { return maDateTime; } + /** @param rDateTime Date and time as LOCAL time. */ + inline void SetValue( const util::DateTime& rDateTime ) { maDateTime = rDateTime; } + +private: + virtual void ImplLoad( SvStream& rStrm ); + virtual void ImplSave( SvStream& rStrm ); + +private: + util::DateTime maDateTime; +}; + +// ============================================================================ + +/** Property representing a thumbnail picture. + + Currently, only saving this property is implemented. + */ +class SfxOleThumbnailProperty : public SfxOlePropertyBase +{ +public: + explicit SfxOleThumbnailProperty( sal_Int32 nPropId, + const uno::Sequence<sal_uInt8> & i_rData); + + inline bool IsValid() const { return mData.getLength() > 0; } + +private: + virtual void ImplLoad( SvStream& rStrm ); + virtual void ImplSave( SvStream& rStrm ); + +private: + uno::Sequence<sal_uInt8> mData; +}; + +// ============================================================================ + +/** Property representing a BLOB (which presumably stands for binary large + object). + + Currently, only saving this property is implemented. + */ +class SfxOleBlobProperty : public SfxOlePropertyBase +{ +public: + explicit SfxOleBlobProperty( sal_Int32 nPropId, + const uno::Sequence<sal_uInt8> & i_rData); + inline bool IsValid() const { return mData.getLength() > 0; } + +private: + virtual void ImplLoad( SvStream& rStrm ); + virtual void ImplSave( SvStream& rStrm ); + +private: + uno::Sequence<sal_uInt8> mData; +}; + +// ============================================================================ + +sal_uInt16 SfxOleTextEncoding::GetCodePage() const +{ + sal_uInt16 nCodePage = IsUnicode() ? CODEPAGE_UNICODE : + static_cast< sal_uInt16 >( rtl_getWindowsCodePageFromTextEncoding( *mxTextEnc ) ); + return (nCodePage == CODEPAGE_UNKNOWN) ? CODEPAGE_UTF8 : nCodePage; +} + +void SfxOleTextEncoding::SetCodePage( sal_uInt16 nCodePage ) +{ + if( nCodePage == CODEPAGE_UNICODE ) + SetUnicode(); + else + { + rtl_TextEncoding eTextEnc = rtl_getTextEncodingFromWindowsCodePage( nCodePage ); + if( eTextEnc != RTL_TEXTENCODING_DONTKNOW ) + *mxTextEnc = eTextEnc; + } +} + +// ---------------------------------------------------------------------------- + +String SfxOleStringHelper::LoadString8( SvStream& rStrm ) const +{ + return IsUnicode() ? ImplLoadString16( rStrm ) : ImplLoadString8( rStrm ); +} + +void SfxOleStringHelper::SaveString8( SvStream& rStrm, const String& rValue ) const +{ + if( IsUnicode() ) + ImplSaveString16( rStrm, rValue ); + else + ImplSaveString8( rStrm, rValue ); +} + +String SfxOleStringHelper::LoadString16( SvStream& rStrm ) const +{ + return ImplLoadString16( rStrm ); +} + +void SfxOleStringHelper::SaveString16( SvStream& rStrm, const String& rValue ) const +{ + ImplSaveString16( rStrm, rValue ); +} + +String SfxOleStringHelper::ImplLoadString8( SvStream& rStrm ) const +{ + String aValue; + // read size field (signed 32-bit) + sal_Int32 nSize; + rStrm >> nSize; + // size field includes trailing NUL character + DBG_ASSERT( (0 < nSize) && (nSize <= 0xFFFF), "SfxOleStringHelper::ImplLoadString8 - invalid string" ); + if( (0 < nSize) && (nSize <= 0xFFFF) ) + { + // load character buffer + ::std::vector< sal_Char > aBuffer( static_cast< size_t >( nSize + 1 ), 0 ); + rStrm.Read( &aBuffer.front(), static_cast< sal_Size >( nSize ) ); + // create string from encoded character array + aValue = String( &aBuffer.front(), GetTextEncoding() ); + } + return aValue; +} + +String SfxOleStringHelper::ImplLoadString16( SvStream& rStrm ) const +{ + String aValue; + // read size field (signed 32-bit), may be buffer size or character count + sal_Int32 nSize; + rStrm >> nSize; + DBG_ASSERT( (0 < nSize) && (nSize <= 0xFFFF), "SfxOleStringHelper::ImplLoadString16 - invalid string" ); + // size field includes trailing NUL character + if( (0 < nSize) && (nSize <= 0xFFFF) ) + { + // load character buffer + ::std::vector< sal_Unicode > aBuffer; + aBuffer.reserve( static_cast< size_t >( nSize + 1 ) ); + sal_uInt16 cChar; + for( sal_Int32 nIdx = 0; nIdx < nSize; ++nIdx ) + { + rStrm >> cChar; + aBuffer.push_back( static_cast< sal_Unicode >( cChar ) ); + } + // stream is always padded to 32-bit boundary, skip 2 bytes on odd character count + if( (nSize & 1) == 1 ) + rStrm.SeekRel( 2 ); + // create string from character array + aBuffer.push_back( 0 ); + aValue = String( &aBuffer.front() ); + } + return aValue; +} + +void SfxOleStringHelper::ImplSaveString8( SvStream& rStrm, const String& rValue ) const +{ + // encode to byte string + ByteString aEncoded( rValue, GetTextEncoding() ); + // write size field (including trailing NUL character) + sal_Int32 nSize = static_cast< sal_Int32 >( aEncoded.Len() + 1 ); + rStrm << nSize; + // write character array with trailing NUL character + rStrm.Write( aEncoded.GetBuffer(), aEncoded.Len() ); + rStrm << sal_uInt8( 0 ); +} + +void SfxOleStringHelper::ImplSaveString16( SvStream& rStrm, const String& rValue ) const +{ + // write size field (including trailing NUL character) + sal_Int32 nSize = static_cast< sal_Int32 >( rValue.Len() + 1 ); + rStrm << nSize; + // write character array with trailing NUL character + for( xub_StrLen nIdx = 0; nIdx < rValue.Len(); ++nIdx ) + rStrm << static_cast< sal_uInt16 >( rValue.GetChar( nIdx ) ); + rStrm << sal_uInt16( 0 ); + // stream is always padded to 32-bit boundary, add 2 bytes on odd character count + if( (nSize & 1) == 1 ) + rStrm << sal_uInt16( 0 ); +} + +// ---------------------------------------------------------------------------- + +SfxOleObjectBase::~SfxOleObjectBase() +{ +} + +ErrCode SfxOleObjectBase::Load( SvStream& rStrm ) +{ + mnErrCode = ERRCODE_NONE; + ImplLoad( rStrm ); + SetError( rStrm.GetErrorCode() ); + return GetError(); +} + +ErrCode SfxOleObjectBase::Save( SvStream& rStrm ) +{ + mnErrCode = ERRCODE_NONE; + ImplSave( rStrm ); + SetError( rStrm.GetErrorCode() ); + return GetError(); +} + +void SfxOleObjectBase::LoadObject( SvStream& rStrm, SfxOleObjectBase& rObj ) +{ + SetError( rObj.Load( rStrm ) ); +} + +void SfxOleObjectBase::SaveObject( SvStream& rStrm, SfxOleObjectBase& rObj ) +{ + SetError( rObj.Save( rStrm ) ); +} + +// ---------------------------------------------------------------------------- + +SfxOleCodePageProperty::SfxOleCodePageProperty() : + SfxOlePropertyBase( PROPID_CODEPAGE, PROPTYPE_INT16 ) +{ +} + +void SfxOleCodePageProperty::ImplLoad( SvStream& rStrm ) +{ + // property type is signed int16, but we use always unsigned int16 for codepages + sal_uInt16 nCodePage; + rStrm >> nCodePage; + SetCodePage( nCodePage ); +} + +void SfxOleCodePageProperty::ImplSave( SvStream& rStrm ) +{ + // property type is signed int16, but we use always unsigned int16 for codepages + rStrm << GetCodePage(); +} + +// ---------------------------------------------------------------------------- + +SfxOleInt32Property::SfxOleInt32Property( sal_Int32 nPropId, sal_Int32 nValue ) : + SfxOlePropertyBase( nPropId, PROPTYPE_INT32 ), + mnValue( nValue ) +{ +} + +void SfxOleInt32Property::ImplLoad( SvStream& rStrm ) +{ + rStrm >> mnValue; +} + +void SfxOleInt32Property::ImplSave( SvStream& rStrm ) +{ + rStrm << mnValue; +} + +// ---------------------------------------------------------------------------- + +SfxOleDoubleProperty::SfxOleDoubleProperty( sal_Int32 nPropId, double fValue ) : + SfxOlePropertyBase( nPropId, PROPTYPE_DOUBLE ), + mfValue( fValue ) +{ +} + +void SfxOleDoubleProperty::ImplLoad( SvStream& rStrm ) +{ + rStrm >> mfValue; +} + +void SfxOleDoubleProperty::ImplSave( SvStream& rStrm ) +{ + rStrm << mfValue; +} + +// ---------------------------------------------------------------------------- + +SfxOleBoolProperty::SfxOleBoolProperty( sal_Int32 nPropId, bool bValue ) : + SfxOlePropertyBase( nPropId, PROPTYPE_BOOL ), + mbValue( bValue ) +{ +} + +void SfxOleBoolProperty::ImplLoad( SvStream& rStrm ) +{ + sal_Int16 nValue; + rStrm >> nValue; + mbValue = nValue != 0; +} + +void SfxOleBoolProperty::ImplSave( SvStream& rStrm ) +{ + rStrm << static_cast< sal_Int16 >( mbValue ? -1 : 0 ); +} + +// ---------------------------------------------------------------------------- + +SfxOleStringPropertyBase::SfxOleStringPropertyBase( + sal_Int32 nPropId, sal_Int32 nPropType, const SfxOleTextEncoding& rTextEnc ) : + SfxOlePropertyBase( nPropId, nPropType ), + SfxOleStringHelper( rTextEnc ) +{ +} + +SfxOleStringPropertyBase::SfxOleStringPropertyBase( + sal_Int32 nPropId, sal_Int32 nPropType, const SfxOleTextEncoding& rTextEnc, const String& rValue ) : + SfxOlePropertyBase( nPropId, nPropType ), + SfxOleStringHelper( rTextEnc ), + maValue( rValue ) +{ +} + +SfxOleStringPropertyBase::SfxOleStringPropertyBase( + sal_Int32 nPropId, sal_Int32 nPropType, rtl_TextEncoding eTextEnc ) : + SfxOlePropertyBase( nPropId, nPropType ), + SfxOleStringHelper( eTextEnc ) +{ +} + +SfxOleStringPropertyBase::SfxOleStringPropertyBase( + sal_Int32 nPropId, sal_Int32 nPropType, rtl_TextEncoding eTextEnc, const String& rValue ) : + SfxOlePropertyBase( nPropId, nPropType ), + SfxOleStringHelper( eTextEnc ), + maValue( rValue ) +{ +} + +// ---------------------------------------------------------------------------- + +SfxOleString8Property::SfxOleString8Property( + sal_Int32 nPropId, const SfxOleTextEncoding& rTextEnc ) : + SfxOleStringPropertyBase( nPropId, PROPTYPE_STRING8, rTextEnc ) +{ +} + +SfxOleString8Property::SfxOleString8Property( + sal_Int32 nPropId, const SfxOleTextEncoding& rTextEnc, const String& rValue ) : + SfxOleStringPropertyBase( nPropId, PROPTYPE_STRING8, rTextEnc, rValue ) +{ +} + +void SfxOleString8Property::ImplLoad( SvStream& rStrm ) +{ + SetValue( LoadString8( rStrm ) ); +} + +void SfxOleString8Property::ImplSave( SvStream& rStrm ) +{ + SaveString8( rStrm, GetValue() ); +} + +// ---------------------------------------------------------------------------- + +SfxOleString16Property::SfxOleString16Property( sal_Int32 nPropId ) : + SfxOleStringPropertyBase( nPropId, PROPTYPE_STRING16, RTL_TEXTENCODING_UCS2 ) +{ +} + +SfxOleString16Property::SfxOleString16Property( sal_Int32 nPropId, const String& rValue ) : + SfxOleStringPropertyBase( nPropId, PROPTYPE_STRING16, RTL_TEXTENCODING_UCS2, rValue ) +{ +} + +void SfxOleString16Property::ImplLoad( SvStream& rStrm ) +{ + SetValue( LoadString16( rStrm ) ); +} + +void SfxOleString16Property::ImplSave( SvStream& rStrm ) +{ + SaveString16( rStrm, GetValue() ); +} + +// ---------------------------------------------------------------------------- + +SfxOleFileTimeProperty::SfxOleFileTimeProperty( sal_Int32 nPropId ) : + SfxOlePropertyBase( nPropId, PROPTYPE_FILETIME ) +{ +} + +SfxOleFileTimeProperty::SfxOleFileTimeProperty( sal_Int32 nPropId, const util::DateTime& rDateTime ) : + SfxOlePropertyBase( nPropId, PROPTYPE_FILETIME ), + maDateTime( rDateTime ) +{ +} + +void SfxOleFileTimeProperty::ImplLoad( SvStream& rStrm ) +{ + sal_uInt32 nLower, nUpper; + rStrm >> nLower >> nUpper; + ::DateTime aDateTime = DateTime::CreateFromWin32FileDateTime( nLower, nUpper ); + // note: editing duration is stored as offset to TIMESTAMP_INVALID_DATETIME + // of course we should not convert the time zone of a duration! + // heuristic to detect editing durations (which we assume to be < 1 year): + // check only the year, not the entire date + if ( aDateTime.GetYear() != TIMESTAMP_INVALID_DATETIME.GetYear() ) + aDateTime.ConvertToLocalTime(); + maDateTime.Year = aDateTime.GetYear(); + maDateTime.Month = aDateTime.GetMonth(); + maDateTime.Day = aDateTime.GetDay(); + maDateTime.Hours = aDateTime.GetHour(); + maDateTime.Minutes = aDateTime.GetMin(); + maDateTime.Seconds = aDateTime.GetSec(); + maDateTime.HundredthSeconds = aDateTime.Get100Sec(); +} + +void SfxOleFileTimeProperty::ImplSave( SvStream& rStrm ) +{ + DateTime aDateTimeUtc( + Date( + static_cast< USHORT >( maDateTime.Day ), + static_cast< USHORT >( maDateTime.Month ), + static_cast< USHORT >( maDateTime.Year ) ), + Time( + static_cast< ULONG >( maDateTime.Hours ), + static_cast< ULONG >( maDateTime.Minutes ), + static_cast< ULONG >( maDateTime.Seconds ), + static_cast< ULONG >( maDateTime.HundredthSeconds ) ) ); + // invalid time stamp is not converted to UTC + // heuristic to detect editing durations (which we assume to be < 1 year): + // check only the year, not the entire date + if( aDateTimeUtc.IsValid() + && aDateTimeUtc.GetYear() != TIMESTAMP_INVALID_DATETIME.GetYear() ) { + aDateTimeUtc.ConvertToUTC(); + } + sal_uInt32 nLower, nUpper; + aDateTimeUtc.GetWin32FileDateTime( nLower, nUpper ); + rStrm << nLower << nUpper; +} + +// ---------------------------------------------------------------------------- + +SfxOleThumbnailProperty::SfxOleThumbnailProperty( + sal_Int32 nPropId, const uno::Sequence<sal_uInt8> & i_rData) : + SfxOlePropertyBase( nPropId, PROPTYPE_CLIPFMT ), + mData(i_rData) +{ +} + +void SfxOleThumbnailProperty::ImplLoad( SvStream& ) +{ + DBG_ERRORFILE( "SfxOleThumbnailProperty::ImplLoad - not implemented" ); + SetError( SVSTREAM_INVALID_ACCESS ); +} + +void SfxOleThumbnailProperty::ImplSave( SvStream& rStrm ) +{ + /* Type Contents + ----------------------------------------------------------------------- + int32 size of following data + int32 clipboard format tag (see below) + byte[] clipboard data (see below) + + Clipboard format tag: + -1 = Windows clipboard format + -2 = Macintosh clipboard format + -3 = GUID that contains a format identifier (FMTID) + >0 = custom clipboard format name plus data (see msdn site below) + 0 = no data + + References: + http://msdn.microsoft.com/library/default.asp?url=/library/en-us/stg/stg/propvariant.asp + http://jakarta.apache.org/poi/hpsf/thumbnails.html + http://linux.com.hk/docs/poi/org/apache/poi/hpsf/Thumbnail.html + http://sparks.discreet.com/knowledgebase/public/solutions/ExtractThumbnailImg.htm + */ + if( IsValid() ) + { + // clipboard size: clip_format_tag + data_format_tag + bitmap_len + sal_Int32 nClipSize = static_cast< sal_Int32 >( 4 + 4 + mData.getLength() ); + rStrm << nClipSize << CLIPFMT_WIN << CLIPDATAFMT_DIB; + rStrm.Write( mData.getConstArray(), mData.getLength() ); + } + else + { + DBG_ERRORFILE( "SfxOleThumbnailProperty::ImplSave - invalid thumbnail property" ); + SetError( SVSTREAM_INVALID_ACCESS ); + } +} + +// ---------------------------------------------------------------------------- + +SfxOleBlobProperty::SfxOleBlobProperty( sal_Int32 nPropId, + const uno::Sequence<sal_uInt8> & i_rData) : + SfxOlePropertyBase( nPropId, PROPTYPE_BLOB ), + mData(i_rData) +{ +} + +void SfxOleBlobProperty::ImplLoad( SvStream& ) +{ + DBG_ERRORFILE( "SfxOleBlobProperty::ImplLoad - not implemented" ); + SetError( SVSTREAM_INVALID_ACCESS ); +} + +void SfxOleBlobProperty::ImplSave( SvStream& rStrm ) +{ + if (IsValid()) { + rStrm.Write( mData.getConstArray(), mData.getLength() ); + } else { + DBG_ERRORFILE( "SfxOleBlobProperty::ImplSave - invalid BLOB property" ); + SetError( SVSTREAM_INVALID_ACCESS ); + } +} + +// ---------------------------------------------------------------------------- + +SfxOleDictionaryProperty::SfxOleDictionaryProperty( const SfxOleTextEncoding& rTextEnc ) : + SfxOlePropertyBase( PROPID_DICTIONARY, 0 ), + SfxOleStringHelper( rTextEnc ) +{ +} + +const String& SfxOleDictionaryProperty::GetPropertyName( sal_Int32 nPropId ) const +{ + SfxOlePropNameMap::const_iterator aIt = maPropNameMap.find( nPropId ); + return (aIt == maPropNameMap.end()) ? String::EmptyString() : aIt->second; +} + +void SfxOleDictionaryProperty::SetPropertyName( sal_Int32 nPropId, const String& rPropName ) +{ + maPropNameMap[ nPropId ] = rPropName; + // dictionary property contains number of pairs in property type field + SetPropType( static_cast< sal_Int32 >( maPropNameMap.size() ) ); +} + +void SfxOleDictionaryProperty::ImplLoad( SvStream& rStrm ) +{ + // dictionary property contains number of pairs in property type field + sal_Int32 nNameCount = GetPropType(); + // read property ID/name pairs + maPropNameMap.clear(); + for( sal_Int32 nIdx = 0; (nIdx < nNameCount) && (rStrm.GetErrorCode() == SVSTREAM_OK) && !rStrm.IsEof(); ++nIdx ) + { + sal_Int32 nPropId; + rStrm >> nPropId; + // name always stored as byte string + maPropNameMap[ nPropId ] = LoadString8( rStrm ); + } +} + +void SfxOleDictionaryProperty::ImplSave( SvStream& rStrm ) +{ + // write property ID/name pairs + for( SfxOlePropNameMap::const_iterator aIt = maPropNameMap.begin(), aEnd = maPropNameMap.end(); aIt != aEnd; ++aIt ) + { + rStrm << aIt->first; + // name always stored as byte string + SaveString8( rStrm, aIt->second ); + } +} + +// ---------------------------------------------------------------------------- + +SfxOleSection::SfxOleSection( bool bSupportsDict ) : + maDictProp( maCodePageProp ), + mnStartPos( 0 ), + mbSupportsDict( bSupportsDict ) +{ +} + +SfxOlePropertyRef SfxOleSection::GetProperty( sal_Int32 nPropId ) const +{ + SfxOlePropertyRef xProp; + SfxOlePropMap::const_iterator aIt = maPropMap.find( nPropId ); + if( aIt != maPropMap.end() ) + xProp = aIt->second; + return xProp; +} + +bool SfxOleSection::GetInt32Value( sal_Int32& rnValue, sal_Int32 nPropId ) const +{ + SfxOlePropertyRef xProp = GetProperty( nPropId ); + const SfxOleInt32Property* pProp = + dynamic_cast< const SfxOleInt32Property* >( xProp.get() ); + if( pProp ) + rnValue = pProp->GetValue(); + return pProp != 0; +} + +bool SfxOleSection::GetDoubleValue( double& rfValue, sal_Int32 nPropId ) const +{ + SfxOlePropertyRef xProp = GetProperty( nPropId ); + const SfxOleDoubleProperty* pProp = + dynamic_cast< const SfxOleDoubleProperty* >( xProp.get() ); + if( pProp ) + rfValue = pProp->GetValue(); + return pProp != 0; +} + +bool SfxOleSection::GetBoolValue( bool& rbValue, sal_Int32 nPropId ) const +{ + SfxOlePropertyRef xProp = GetProperty( nPropId ); + const SfxOleBoolProperty* pProp = + dynamic_cast< const SfxOleBoolProperty* >( xProp.get() ); + if( pProp ) + rbValue = pProp->GetValue(); + return pProp != 0; +} + +bool SfxOleSection::GetStringValue( String& rValue, sal_Int32 nPropId ) const +{ + SfxOlePropertyRef xProp = GetProperty( nPropId ); + const SfxOleStringPropertyBase* pProp = + dynamic_cast< const SfxOleStringPropertyBase* >( xProp.get() ); + if( pProp ) + rValue = pProp->GetValue(); + return pProp != 0; +} + +bool SfxOleSection::GetFileTimeValue( util::DateTime& rValue, sal_Int32 nPropId ) const +{ + SfxOlePropertyRef xProp = GetProperty( nPropId ); + const SfxOleFileTimeProperty* pProp = + dynamic_cast< const SfxOleFileTimeProperty* >( xProp.get() ); + if( pProp ) + { + if ( pProp->GetValue() == TIMESTAMP_INVALID_UTILDATETIME ) + rValue = util::DateTime(); + else + rValue = pProp->GetValue(); + } + return pProp != 0; +} + +void SfxOleSection::SetProperty( SfxOlePropertyRef xProp ) +{ + if( xProp.get() ) + maPropMap[ xProp->GetPropId() ] = xProp; +} + +void SfxOleSection::SetInt32Value( sal_Int32 nPropId, sal_Int32 nValue ) +{ + SetProperty( SfxOlePropertyRef( new SfxOleInt32Property( nPropId, nValue ) ) ); +} + +void SfxOleSection::SetDoubleValue( sal_Int32 nPropId, double fValue ) +{ + SetProperty( SfxOlePropertyRef( new SfxOleDoubleProperty( nPropId, fValue ) ) ); +} + +void SfxOleSection::SetBoolValue( sal_Int32 nPropId, bool bValue ) +{ + SetProperty( SfxOlePropertyRef( new SfxOleBoolProperty( nPropId, bValue ) ) ); +} + +bool SfxOleSection::SetStringValue( sal_Int32 nPropId, const String& rValue, bool bSkipEmpty ) +{ + bool bInserted = !bSkipEmpty || (rValue.Len() > 0); + if( bInserted ) + SetProperty( SfxOlePropertyRef( new SfxOleString8Property( nPropId, maCodePageProp, rValue ) ) ); + return bInserted; +} + +void SfxOleSection::SetFileTimeValue( sal_Int32 nPropId, const util::DateTime& rValue ) +{ + if ( rValue.Year == 0 || rValue.Month == 0 || rValue.Day == 0 ) + SetProperty( SfxOlePropertyRef( new SfxOleFileTimeProperty( nPropId, TIMESTAMP_INVALID_UTILDATETIME ) ) ); + else + SetProperty( SfxOlePropertyRef( new SfxOleFileTimeProperty( nPropId, rValue ) ) ); +} + +void SfxOleSection::SetThumbnailValue( sal_Int32 nPropId, + const uno::Sequence<sal_uInt8> & i_rData) +{ + SfxOleThumbnailProperty* pThumbnail = new SfxOleThumbnailProperty( nPropId, i_rData ); + SfxOlePropertyRef xProp( pThumbnail ); // take ownership + if( pThumbnail->IsValid() ) + SetProperty( xProp ); +} + +void SfxOleSection::SetBlobValue( sal_Int32 nPropId, + const uno::Sequence<sal_uInt8> & i_rData) +{ + SfxOleBlobProperty* pBlob( new SfxOleBlobProperty( nPropId, i_rData ) ); + SfxOlePropertyRef xProp( pBlob ); + if( pBlob->IsValid() ) { + SetProperty( xProp ); + } +} + +Any SfxOleSection::GetAnyValue( sal_Int32 nPropId ) const +{ + Any aValue; + sal_Int32 nInt32 = 0; + double fDouble = 0.0; + bool bBool = false; + String aString; + ::com::sun::star::util::DateTime aApiDateTime; + + if( GetInt32Value( nInt32, nPropId ) ) + aValue <<= nInt32; + else if( GetDoubleValue( fDouble, nPropId ) ) + aValue <<= fDouble; + else if( GetBoolValue( bBool, nPropId ) ) + ::comphelper::setBOOL( aValue, bBool ? sal_True : sal_False ); + else if( GetStringValue( aString, nPropId ) ) + aValue <<= OUString( aString ); + else if( GetFileTimeValue( aApiDateTime, nPropId ) ) + { + aValue <<= aApiDateTime; + } + return aValue; +} + +bool SfxOleSection::SetAnyValue( sal_Int32 nPropId, const Any& rValue ) +{ + bool bInserted = true; + sal_Int32 nInt32 = 0; + double fDouble = 0.0; + OUString aString; + ::com::sun::star::util::DateTime aApiDateTime; + + if( rValue.getValueType() == ::getBooleanCppuType() ) + SetBoolValue( nPropId, ::comphelper::getBOOL( rValue ) == sal_True ); + else if( rValue >>= nInt32 ) + SetInt32Value( nPropId, nInt32 ); + else if( rValue >>= fDouble ) + SetDoubleValue( nPropId, fDouble ); + else if( rValue >>= aString ) + bInserted = SetStringValue( nPropId, aString ); + else if( rValue >>= aApiDateTime ) + { + SetFileTimeValue( nPropId, aApiDateTime ); + } + else + bInserted = false; + return bInserted; +} + +const String& SfxOleSection::GetPropertyName( sal_Int32 nPropId ) const +{ + return maDictProp.GetPropertyName( nPropId ); +} + +void SfxOleSection::SetPropertyName( sal_Int32 nPropId, const String& rPropName ) +{ + maDictProp.SetPropertyName( nPropId, rPropName ); +} + +void SfxOleSection::GetPropertyIds( ::std::vector< sal_Int32 >& rPropIds ) const +{ + rPropIds.clear(); + for( SfxOlePropMap::const_iterator aIt = maPropMap.begin(), aEnd = maPropMap.end(); aIt != aEnd; ++aIt ) + rPropIds.push_back( aIt->first ); +} + +sal_Int32 SfxOleSection::GetFreePropertyId() const +{ + return maPropMap.empty() ? PROPID_FIRSTCUSTOM : (maPropMap.rbegin()->first + 1); +} + +void SfxOleSection::ImplLoad( SvStream& rStrm ) +{ + // read section header + mnStartPos = rStrm.Tell(); + sal_uInt32 nSize; + sal_Int32 nPropCount; + rStrm >> nSize >> nPropCount; + + // read property ID/position pairs + typedef ::std::map< sal_Int32, sal_uInt32 > SfxOlePropPosMap; + SfxOlePropPosMap aPropPosMap; + for( sal_Int32 nPropIdx = 0; (nPropIdx < nPropCount) && (rStrm.GetErrorCode() == SVSTREAM_OK) && !rStrm.IsEof(); ++nPropIdx ) + { + sal_Int32 nPropId; + sal_uInt32 nPropPos; + rStrm >> nPropId >> nPropPos; + aPropPosMap[ nPropId ] = nPropPos; + } + + // read codepage property + SfxOlePropPosMap::iterator aCodePageIt = aPropPosMap.find( PROPID_CODEPAGE ); + if( (aCodePageIt != aPropPosMap.end()) && SeekToPropertyPos( rStrm, aCodePageIt->second ) ) + { + // codepage property must be of type signed int-16 + sal_Int32 nPropType; + rStrm >> nPropType; + if( nPropType == PROPTYPE_INT16 ) + LoadObject( rStrm, maCodePageProp ); + // remove property position + aPropPosMap.erase( aCodePageIt ); + } + + // read dictionary property + SfxOlePropPosMap::iterator aDictIt = aPropPosMap.find( PROPID_DICTIONARY ); + if( (aDictIt != aPropPosMap.end()) && SeekToPropertyPos( rStrm, aDictIt->second ) ) + { + // #i66214# #i66428# applications may write broken dictionary properties in wrong sections + if( mbSupportsDict ) + { + // dictionary property contains number of pairs in property type field + sal_Int32 nNameCount; + rStrm >> nNameCount; + maDictProp.SetNameCount( nNameCount ); + LoadObject( rStrm, maDictProp ); + } + // always remove position of dictionary property (do not try to read it again below) + aPropPosMap.erase( aDictIt ); + } + + // read other properties + maPropMap.clear(); + for( SfxOlePropPosMap::const_iterator aIt = aPropPosMap.begin(), aEnd = aPropPosMap.end(); aIt != aEnd; ++aIt ) + if( SeekToPropertyPos( rStrm, aIt->second ) ) + LoadProperty( rStrm, aIt->first ); +} + +void SfxOleSection::ImplSave( SvStream& rStrm ) +{ + /* Always export with UTF-8 encoding. All dependent properties (bytestring + and dictionary) will be updated automatically. */ + maCodePageProp.SetTextEncoding( RTL_TEXTENCODING_UTF8 ); + + // write section header + mnStartPos = rStrm.Tell(); + sal_Int32 nPropCount = static_cast< sal_Int32 >( maPropMap.size() + 1 ); + if( maDictProp.HasPropertyNames() ) + ++nPropCount; + rStrm << sal_uInt32( 0 ) << nPropCount; + + // write placeholders for property ID/position pairs + sal_Size nPropPosPos = rStrm.Tell(); + rStrm.SeekRel( static_cast< sal_sSize >( 8 * nPropCount ) ); + + // write dictionary property + if( maDictProp.HasPropertyNames() ) + SaveProperty( rStrm, maDictProp, nPropPosPos ); + // write codepage property + SaveProperty( rStrm, maCodePageProp, nPropPosPos ); + // write other properties + for( SfxOlePropMap::const_iterator aIt = maPropMap.begin(), aEnd = maPropMap.end(); aIt != aEnd; ++aIt ) + SaveProperty( rStrm, *aIt->second, nPropPosPos ); + + // write section size (first field in section header) + rStrm.Seek( STREAM_SEEK_TO_END ); + sal_uInt32 nSectSize = static_cast< sal_uInt32 >( rStrm.Tell() - mnStartPos ); + rStrm.Seek( mnStartPos ); + rStrm << nSectSize; +} + +bool SfxOleSection::SeekToPropertyPos( SvStream& rStrm, sal_uInt32 nPropPos ) const +{ + rStrm.Seek( static_cast< sal_Size >( mnStartPos + nPropPos ) ); + return rStrm.GetErrorCode() == SVSTREAM_OK; +} + +void SfxOleSection::LoadProperty( SvStream& rStrm, sal_Int32 nPropId ) +{ + // property data type + sal_Int32 nPropType; + rStrm >> nPropType; + // create empty property object + SfxOlePropertyRef xProp; + switch( nPropType ) + { + case PROPTYPE_INT32: + xProp.reset( new SfxOleInt32Property( nPropId ) ); + break; + case PROPTYPE_DOUBLE: + xProp.reset( new SfxOleDoubleProperty( nPropId ) ); + break; + case PROPTYPE_BOOL: + xProp.reset( new SfxOleBoolProperty( nPropId ) ); + break; + case PROPTYPE_STRING8: + xProp.reset( new SfxOleString8Property( nPropId, maCodePageProp ) ); + break; + case PROPTYPE_STRING16: + xProp.reset( new SfxOleString16Property( nPropId ) ); + break; + case PROPTYPE_FILETIME: + xProp.reset( new SfxOleFileTimeProperty( nPropId ) ); + break; + } + // load property contents + if( xProp.get() ) + { + SetError( xProp->Load( rStrm ) ); + maPropMap[ nPropId ] = xProp; + } +} + +void SfxOleSection::SaveProperty( SvStream& rStrm, SfxOlePropertyBase& rProp, sal_Size& rnPropPosPos ) +{ + rStrm.Seek( STREAM_SEEK_TO_END ); + sal_uInt32 nPropPos = static_cast< sal_uInt32 >( rStrm.Tell() - mnStartPos ); + // property data type + rStrm << rProp.GetPropType(); + // write property contents + SaveObject( rStrm, rProp ); + // align to 32-bit + while( (rStrm.Tell() & 3) != 0 ) + rStrm << sal_uInt8( 0 ); + // write property ID/position pair + rStrm.Seek( rnPropPosPos ); + rStrm << rProp.GetPropId() << nPropPos; + rnPropPosPos = rStrm.Tell(); +} + +// ---------------------------------------------------------------------------- + +ErrCode SfxOlePropertySet::LoadPropertySet( SotStorage* pStrg, const String& rStrmName ) +{ + if( pStrg ) + { + SotStorageStreamRef xStrm = pStrg->OpenSotStream( rStrmName, STREAM_STD_READ ); + if( xStrm.Is() && (xStrm->GetError() == SVSTREAM_OK) ) + { + xStrm->SetBufferSize( STREAM_BUFFER_SIZE ); + Load( *xStrm ); + } + else + SetError( ERRCODE_IO_ACCESSDENIED ); + } + else + SetError( ERRCODE_IO_ACCESSDENIED ); + return GetError(); +} + +ErrCode SfxOlePropertySet::SavePropertySet( SotStorage* pStrg, const String& rStrmName ) +{ + if( pStrg ) + { + SotStorageStreamRef xStrm = pStrg->OpenSotStream( rStrmName, STREAM_TRUNC | STREAM_STD_WRITE ); + if( xStrm.Is() ) + Save( *xStrm ); + else + SetError( ERRCODE_IO_ACCESSDENIED ); + } + else + SetError( ERRCODE_IO_ACCESSDENIED ); + return GetError(); +} + +SfxOleSectionRef SfxOlePropertySet::GetSection( SfxOleSectionType eSection ) const +{ + return GetSection( GetSectionGuid( eSection ) ); +} + +SfxOleSectionRef SfxOlePropertySet::GetSection( const SvGlobalName& rSectionGuid ) const +{ + SfxOleSectionRef xSection; + SfxOleSectionMap::const_iterator aIt = maSectionMap.find( rSectionGuid ); + if( aIt != maSectionMap.end() ) + xSection = aIt->second; + return xSection; +} + +SfxOleSection& SfxOlePropertySet::AddSection( SfxOleSectionType eSection ) +{ + return AddSection( GetSectionGuid( eSection ) ); +} + +SfxOleSection& SfxOlePropertySet::AddSection( const SvGlobalName& rSectionGuid ) +{ + SfxOleSectionRef xSection = GetSection( rSectionGuid ); + if( !xSection ) + { + // #i66214# #i66428# applications may write broken dictionary properties in wrong sections + bool bSupportsDict = rSectionGuid == GetSectionGuid( SECTION_CUSTOM ); + xSection.reset( new SfxOleSection( bSupportsDict ) ); + maSectionMap[ rSectionGuid ] = xSection; + } + return *xSection; +} + +void SfxOlePropertySet::ImplLoad( SvStream& rStrm ) +{ + // read property set header + sal_uInt16 nByteOrder; + sal_uInt16 nVersion; + sal_uInt16 nOsMinor; + sal_uInt16 nOsType; + SvGlobalName aGuid; + sal_Int32 nSectCount; + rStrm >> nByteOrder >> nVersion >> nOsMinor >> nOsType >> aGuid >> nSectCount; + + // read sections + sal_Size nSectPosPos = rStrm.Tell(); + for( sal_Int32 nSectIdx = 0; (nSectIdx < nSectCount) && (rStrm.GetErrorCode() == SVSTREAM_OK) && !rStrm.IsEof(); ++nSectIdx ) + { + // read section guid/position pair + rStrm.Seek( nSectPosPos ); + SvGlobalName aSectGuid; + sal_uInt32 nSectPos; + rStrm >> aSectGuid >> nSectPos; + nSectPosPos = rStrm.Tell(); + // read section + rStrm.Seek( static_cast< sal_Size >( nSectPos ) ); + if( rStrm.GetErrorCode() == SVSTREAM_OK ) + LoadObject( rStrm, AddSection( aSectGuid ) ); + } +} + +void SfxOlePropertySet::ImplSave( SvStream& rStrm ) +{ + // write property set header + SvGlobalName aGuid; + sal_Int32 nSectCount = static_cast< sal_Int32 >( maSectionMap.size() ); + rStrm << sal_uInt16( 0xFFFE ) // byte order + << sal_uInt16( 0 ) // version + << sal_uInt16( 1 ) // OS minor version + << sal_uInt16( 2 ) // OS type always windows for text encoding + << aGuid // unused guid + << nSectCount; // number of sections + + // write placeholders for section guid/position pairs + sal_Size nSectPosPos = rStrm.Tell(); + rStrm.SeekRel( static_cast< sal_sSize >( 20 * nSectCount ) ); + + // write sections + for( SfxOleSectionMap::const_iterator aIt = maSectionMap.begin(), aEnd = maSectionMap.end(); aIt != aEnd; ++aIt ) + { + SfxOleSection& rSection = *aIt->second; + rStrm.Seek( STREAM_SEEK_TO_END ); + sal_uInt32 nSectPos = static_cast< sal_uInt32 >( rStrm.Tell() ); + // write the section + SaveObject( rStrm, rSection ); + // write section guid/position pair + rStrm.Seek( nSectPosPos ); + rStrm << aIt->first << nSectPos; + nSectPosPos = rStrm.Tell(); + } +} + +const SvGlobalName& SfxOlePropertySet::GetSectionGuid( SfxOleSectionType eSection ) +{ + static const SvGlobalName saGlobalGuid( 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9 ); + static const SvGlobalName saBuiltInGuid( 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE ); + static const SvGlobalName saCustomGuid( 0xD5CDD505, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE ); + static const SvGlobalName saEmptyGuid; + switch( eSection ) + { + case SECTION_GLOBAL: return saGlobalGuid; + case SECTION_BUILTIN: return saBuiltInGuid; + case SECTION_CUSTOM: return saCustomGuid; + default: DBG_ERRORFILE( "SfxOlePropertySet::GetSectionGuid - unknown section type" ); + } + return saEmptyGuid; +} + +// ============================================================================ + +//} // namespace diff --git a/sfx2/source/doc/oleprops.hxx b/sfx2/source/doc/oleprops.hxx new file mode 100755 index 000000000000..5bd586576ac8 --- /dev/null +++ b/sfx2/source/doc/oleprops.hxx @@ -0,0 +1,404 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <map> +#include <boost/shared_ptr.hpp> +#include <sot/storage.hxx> +#include <vcl/bitmapex.hxx> + +#include <com/sun/star/util/DateTime.hpp> + + +// ============================================================================ + +//namespace { + +// ============================================================================ +// property type IDs +const sal_Int32 PROPTYPE_INT16 = 2; +const sal_Int32 PROPTYPE_INT32 = 3; +const sal_Int32 PROPTYPE_FLOAT = 4; +const sal_Int32 PROPTYPE_DOUBLE = 5; +const sal_Int32 PROPTYPE_DATE = 7; +const sal_Int32 PROPTYPE_STRING = 8; +const sal_Int32 PROPTYPE_STATUS = 10; +const sal_Int32 PROPTYPE_BOOL = 11; +const sal_Int32 PROPTYPE_VARIANT = 12; +const sal_Int32 PROPTYPE_INT8 = 16; +const sal_Int32 PROPTYPE_UINT8 = 17; +const sal_Int32 PROPTYPE_UINT16 = 18; +const sal_Int32 PROPTYPE_UINT32 = 19; +const sal_Int32 PROPTYPE_INT64 = 20; +const sal_Int32 PROPTYPE_UINT64 = 21; +const sal_Int32 PROPTYPE_STRING8 = 30; +const sal_Int32 PROPTYPE_STRING16 = 31; +const sal_Int32 PROPTYPE_FILETIME = 64; +const sal_Int32 PROPTYPE_BLOB = 65; +const sal_Int32 PROPTYPE_CLIPFMT = 71; + +// static property IDs +const sal_Int32 PROPID_DICTIONARY = 0; +const sal_Int32 PROPID_CODEPAGE = 1; +const sal_Int32 PROPID_FIRSTCUSTOM = 2; + +// property IDs for GlobalDocPropertySet +const sal_Int32 PROPID_TITLE = 2; +const sal_Int32 PROPID_SUBJECT = 3; +const sal_Int32 PROPID_AUTHOR = 4; +const sal_Int32 PROPID_KEYWORDS = 5; +const sal_Int32 PROPID_COMMENTS = 6; +const sal_Int32 PROPID_TEMPLATE = 7; +const sal_Int32 PROPID_LASTAUTHOR = 8; +const sal_Int32 PROPID_REVNUMBER = 9; +const sal_Int32 PROPID_EDITTIME = 10; +const sal_Int32 PROPID_LASTPRINTED = 11; +const sal_Int32 PROPID_CREATED = 12; +const sal_Int32 PROPID_LASTSAVED = 13; +const sal_Int32 PROPID_THUMBNAIL = 17; + +// predefined codepages +const sal_uInt16 CODEPAGE_UNKNOWN = 0; +const sal_uInt16 CODEPAGE_UNICODE = 1200; +const sal_uInt16 CODEPAGE_UTF8 = 65001; + +// predefined clipboard format IDs +const sal_Int32 CLIPFMT_WIN = -1; + +// predefined clipboard data format IDs +const sal_Int32 CLIPDATAFMT_DIB = 8; + +// ============================================================================ +// ============================================================================ + +/** Helper for classes that need text encoding settings. + + Classes derived from this class will include functions to store and use + text encoding settings and to convert Windows codepage constants. + */ +class SfxOleTextEncoding +{ +public: + inline explicit SfxOleTextEncoding() : + mxTextEnc( new rtl_TextEncoding( gsl_getSystemTextEncoding() ) ) {} + inline explicit SfxOleTextEncoding( rtl_TextEncoding eTextEnc ) : + mxTextEnc( new rtl_TextEncoding( eTextEnc ) ) {} + inline explicit SfxOleTextEncoding( sal_Int16 nCodePage ) : + mxTextEnc( new rtl_TextEncoding ) { SetCodePage( nCodePage ); } + + /** Returns the current text encoding identifier. */ + inline rtl_TextEncoding GetTextEncoding() const { return *mxTextEnc; } + /** Sets the passed text encoding. */ + inline void SetTextEncoding( rtl_TextEncoding eTextEnc ) { *mxTextEnc = eTextEnc; } + + /** Returns true, if this object contains Unicode text encoding. */ + inline bool IsUnicode() const { return GetTextEncoding() == RTL_TEXTENCODING_UCS2; } + /** Sets Unicode text encoding to this object. */ + inline void SetUnicode() { SetTextEncoding( RTL_TEXTENCODING_UCS2 ); } + + /** Converts the current settings to a Windows codepage identifier. */ + sal_uInt16 GetCodePage() const; + /** Sets the current text encoding from a Windows codepage identifier. */ + void SetCodePage( sal_uInt16 nCodePage ); + +private: + typedef ::boost::shared_ptr< rtl_TextEncoding > TextEncRef; + TextEncRef mxTextEnc; +}; + +// ============================================================================ + +/** Helper for classes that need to load or save string values. + + Classes derived from this class contain functions to load and save string + values with the text encoding passed in the constructor. + */ +class SfxOleStringHelper : public SfxOleTextEncoding +{ +public: + /** Creates a string helper object depending on an external text encoding. */ + inline explicit SfxOleStringHelper( const SfxOleTextEncoding& rTextEnc ) : + SfxOleTextEncoding( rTextEnc ) {} + /** Creates a string helper object with own text encoding. */ + inline explicit SfxOleStringHelper( rtl_TextEncoding eTextEnc ) : + SfxOleTextEncoding( eTextEnc ) {} + + /** Loads a string from the passed stream with current encoding (maybe Unicode). */ + String LoadString8( SvStream& rStrm ) const; + /** Saves a string to the passed stream with current encoding (maybe Unicode). */ + void SaveString8( SvStream& rStrm, const String& rValue ) const; + + /** Loads a Unicode string from the passed stream, ignores own encoding. */ + String LoadString16( SvStream& rStrm ) const; + /** Saves a Unicode string to the passed stream, ignores own encoding. */ + void SaveString16( SvStream& rStrm, const String& rValue ) const; + +private: + String ImplLoadString8( SvStream& rStrm ) const; + String ImplLoadString16( SvStream& rStrm ) const; + void ImplSaveString8( SvStream& rStrm, const String& rValue ) const; + void ImplSaveString16( SvStream& rStrm, const String& rValue ) const; +}; + + +// ============================================================================ +// ============================================================================ + +/** Base class for all classes related to OLE property sets. + + Derived calsses have to implement the pure virtual functions ImplLoad() and + ImplSave(). + */ +class SfxOleObjectBase +{ +public: + inline explicit SfxOleObjectBase() : mnErrCode( ERRCODE_NONE ) {} + virtual ~SfxOleObjectBase(); + + /** Returns true, if an error code (other than ERRCODE_NONE) is set. */ + inline bool HasError() const { return mnErrCode != ERRCODE_NONE; } + /** Returns the current error code. */ + inline ErrCode GetError() const { return mnErrCode; } + + /** Loads this object from the passed stream. Calls virtual ImplLoad(). */ + ErrCode Load( SvStream& rStrm ); + /** Saves this object to the passed stream. Calls virtual ImplSave(). */ + ErrCode Save( SvStream& rStrm ); + +protected: + /** Sets the passed error code. Will be returned by Load() and Save() functions. + Always the first error code is stored. Multiple calls have no effect. */ + inline void SetError( ErrCode nErrCode ) { if( !HasError() ) mnErrCode = nErrCode; } + /** Loads the passed object from the stream. Sets returned error code as own error. */ + void LoadObject( SvStream& rStrm, SfxOleObjectBase& rObj ); + /** Saves the passed object to the stream. Sets returned error code as own error. */ + void SaveObject( SvStream& rStrm, SfxOleObjectBase& rObj ); + +private: + /** Derived classes implement loading the object from the passed steam. */ + virtual void ImplLoad( SvStream& rStrm ) = 0; + /** Derived classes implement saving the object to the passed steam. */ + virtual void ImplSave( SvStream& rStrm ) = 0; + +private: + ErrCode mnErrCode; /// Current error code. +}; + +// ============================================================================ +// ============================================================================ + +/** Base class for all OLE property objects. */ +class SfxOlePropertyBase : public SfxOleObjectBase +{ +public: + inline explicit SfxOlePropertyBase( sal_Int32 nPropId, sal_Int32 nPropType ) : + mnPropId( nPropId ), mnPropType( nPropType ) {} + + inline sal_Int32 GetPropId() const { return mnPropId; } + inline sal_Int32 GetPropType() const { return mnPropType; } + +protected: + inline void SetPropId( sal_Int32 nPropId ) { mnPropId = nPropId; } + inline void SetPropType( sal_Int32 nPropType ) { mnPropType = nPropType; } + +private: + sal_Int32 mnPropId; + sal_Int32 mnPropType; +}; + +typedef ::boost::shared_ptr< SfxOlePropertyBase > SfxOlePropertyRef; + +// ============================================================================ +/** Property representing the codepage used to encode bytestrings in the entire property set. */ +class SfxOleCodePageProperty : public SfxOlePropertyBase, public SfxOleTextEncoding +{ +public: + explicit SfxOleCodePageProperty(); + +private: + virtual void ImplLoad( SvStream& rStrm ); + virtual void ImplSave( SvStream& rStrm ); +}; + +// ============================================================================ +// ============================================================================ + +/** Property containing custom names for other properties in the property set. */ +class SfxOleDictionaryProperty : public SfxOlePropertyBase, public SfxOleStringHelper +{ +public: + explicit SfxOleDictionaryProperty( const SfxOleTextEncoding& rTextEnc ); + + /** Returns true, if the property contains at least one custom property name. */ + inline bool HasPropertyNames() const { return !maPropNameMap.empty(); } + /** Prepares the property for loading. Does not affect contained names for its own. */ + inline void SetNameCount( sal_Int32 nNameCount ) { SetPropType( nNameCount ); } + + /** Returns the custom name for the passed property ID, or an empty string, if name not found. */ + const String& GetPropertyName( sal_Int32 nPropId ) const; + /** Sets a custom name for the passed property ID. */ + void SetPropertyName( sal_Int32 nPropId, const String& rPropName ); + +private: + virtual void ImplLoad( SvStream& rStrm ); + virtual void ImplSave( SvStream& rStrm ); + +private: + typedef ::std::map< sal_Int32, String > SfxOlePropNameMap; + SfxOlePropNameMap maPropNameMap; +}; + +// ============================================================================ +// ============================================================================ + +/** A section in a property set. Contains properties with unique identifiers. */ +class SfxOleSection : public SfxOleObjectBase +{ +private: + typedef ::std::map< sal_Int32, SfxOlePropertyRef > SfxOlePropMap; + +public: + explicit SfxOleSection( bool bSupportsDict ); + + /** Returns the property with the passed ID, or an empty reference, if nothing found. */ + SfxOlePropertyRef GetProperty( sal_Int32 nPropId ) const; + /** Returns the value of a signed int32 property with the passed ID in rnValue. + @return true = Property found, rnValue is valid; false = Property not found. */ + bool GetInt32Value( sal_Int32& rnValue, sal_Int32 nPropId ) const; + /** Returns the value of a floating-point property with the passed ID in rfValue. + @return true = Property found, rfValue is valid; false = Property not found. */ + bool GetDoubleValue( double& rfValue, sal_Int32 nPropId ) const; + /** Returns the value of a boolean property with the passed ID in rbValue. + @return true = Property found, rbValue is valid; false = Property not found. */ + bool GetBoolValue( bool& rbValue, sal_Int32 nPropId ) const; + /** Returns the value of a string property with the passed ID in rValue. + @return true = Property found, rValue is valid; false = Property not found. */ + bool GetStringValue( String& rValue, sal_Int32 nPropId ) const; + /** Returns the value of a time stamp property with the passed ID in rValue. + @return true = Property found, rValue is valid; false = Property not found. */ + bool GetFileTimeValue( ::com::sun::star::util::DateTime& rValue, sal_Int32 nPropId ) const; + + /** Adds the passed property to the property set. Drops an existing old property. */ + void SetProperty( SfxOlePropertyRef xProp ); + /** Inserts a signed int32 property with the passed value. */ + void SetInt32Value( sal_Int32 nPropId, sal_Int32 nValue ); + /** Inserts a foating-point property with the passed value. */ + void SetDoubleValue( sal_Int32 nPropId, double fValue ); + /** Inserts a boolean property with the passed value. */ + void SetBoolValue( sal_Int32 nPropId, bool bValue ); + /** Inserts a string property with the passed value. + @return true = Property inserted; false = String was empty, property not inserted. */ + bool SetStringValue( sal_Int32 nPropId, const String& rValue, bool bSkipEmpty = true ); + /** Inserts a time stamp property with the passed value. */ + void SetFileTimeValue( sal_Int32 nPropId, const ::com::sun::star::util::DateTime& rValue ); + /** Inserts a thumbnail property from the passed meta file. */ + void SetThumbnailValue( sal_Int32 nPropId, + const ::com::sun::star::uno::Sequence<sal_uInt8> & i_rData); + /** Inserts a BLOB property with the passed data. */ + void SetBlobValue( sal_Int32 nPropId, + const ::com::sun::star::uno::Sequence<sal_uInt8> & i_rData); + + /** Returns the value of the property with the passed ID in a UNO any. */ + com::sun::star::uno::Any GetAnyValue( sal_Int32 nPropId ) const; + /** Inserts a property created from the passed any. + @return true = Property converted and inserted; false = Property type not supported. */ + bool SetAnyValue( sal_Int32 nPropId, const com::sun::star::uno::Any& rValue ); + + /** Returns the custom name for the passed property ID, or an empty string, if name not found. */ + const String& GetPropertyName( sal_Int32 nPropId ) const; + /** Sets a custom name for the passed property ID. */ + void SetPropertyName( sal_Int32 nPropId, const String& rPropName ); + + /** Returns the identifiers of all existing properties in the passed vector. */ + void GetPropertyIds( ::std::vector< sal_Int32 >& rPropIds ) const; + /** Returns a property identifier not used in this section. */ + sal_Int32 GetFreePropertyId() const; + +private: + virtual void ImplLoad( SvStream& rStrm ); + virtual void ImplSave( SvStream& rStrm ); + + bool SeekToPropertyPos( SvStream& rStrm, sal_uInt32 nPropPos ) const; + void LoadProperty( SvStream& rStrm, sal_Int32 nPropId ); + void SaveProperty( SvStream& rStrm, SfxOlePropertyBase& rProp, sal_Size& rnPropPosPos ); + +private: + SfxOlePropMap maPropMap; /// All properties in this section, by identifier. + SfxOleCodePageProperty maCodePageProp; /// The codepage property. + SfxOleDictionaryProperty maDictProp; /// The dictionary property. + sal_Size mnStartPos; /// Start stream position of the section. + bool mbSupportsDict; /// true = section supports dictionary. +}; + +typedef ::boost::shared_ptr< SfxOleSection > SfxOleSectionRef; + +// ============================================================================ +// ============================================================================ + +/** Enumerates different section types in OLE property sets. */ +enum SfxOleSectionType +{ + SECTION_GLOBAL, /// Globally defined properties. + SECTION_BUILTIN, /// Properties built into MS Office. + SECTION_CUSTOM /// Custom properties. +}; + +// ============================================================================ + +/** Represents a complete property set, may consist of several property sections. */ +class SfxOlePropertySet : public SfxOleObjectBase +{ +public: + inline explicit SfxOlePropertySet() {} + + /** Loads this object from the passed storage. */ + ErrCode LoadPropertySet( SotStorage* pStrg, const String& rStrmName ); + /** Saves this object to the passed storage. */ + ErrCode SavePropertySet( SotStorage* pStrg, const String& rStrmName ); + + /** Returns the specified section, or an empty reference, if nothing found. */ + SfxOleSectionRef GetSection( SfxOleSectionType eSection ) const; + /** Returns the specified section, or an empty reference, if nothing found. */ + SfxOleSectionRef GetSection( const SvGlobalName& rSectionGuid ) const; + + /** Creates and returns the specified section, or just returns it if it already exists. */ + SfxOleSection& AddSection( SfxOleSectionType eSection ); + /** Creates and returns the specified section, or just returns it if it already exists. */ + SfxOleSection& AddSection( const SvGlobalName& rSectionGuid ); + +private: + virtual void ImplLoad( SvStream& rStrm ); + virtual void ImplSave( SvStream& rStrm ); + + /** Returns the GUID for the specified section. */ + static const SvGlobalName& GetSectionGuid( SfxOleSectionType eSection ); + +private: + typedef ::std::map< SvGlobalName, SfxOleSectionRef > SfxOleSectionMap; + SfxOleSectionMap maSectionMap; +}; + +//}; diff --git a/sfx2/source/doc/ownsubfilterservice.cxx b/sfx2/source/doc/ownsubfilterservice.cxx new file mode 100644 index 000000000000..9cab42889b6e --- /dev/null +++ b/sfx2/source/doc/ownsubfilterservice.cxx @@ -0,0 +1,165 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" +#include <com/sun/star/frame/DoubleInitializationException.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> + +#include <ownsubfilterservice.hxx> +#include <sfx2/objsh.hxx> + +using namespace ::com::sun::star; + +namespace sfx2 { + +//------------------------------------------------------------------------- +OwnSubFilterService::OwnSubFilterService( const uno::Reference < lang::XMultiServiceFactory >& xFactory ) +: m_xFactory( xFactory ) +, m_pObjectShell( NULL ) +{ +} + +//------------------------------------------------------------------------- +OwnSubFilterService::~OwnSubFilterService() +{ +} + +//------------------------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OwnSubFilterService::impl_getStaticSupportedServiceNames() +{ + uno::Sequence< ::rtl::OUString > aRet(2); + aRet[0] = ::rtl::OUString::createFromAscii("com.sun.star.document.OwnSubFilter"); + aRet[1] = ::rtl::OUString::createFromAscii("com.sun.star.comp.document.OwnSubFilter"); + return aRet; +} + +//------------------------------------------------------------------------- +::rtl::OUString SAL_CALL OwnSubFilterService::impl_getStaticImplementationName() +{ + return ::rtl::OUString::createFromAscii("com.sun.star.comp.document.OwnSubFilter"); +} + +//------------------------------------------------------------------------- +uno::Reference< uno::XInterface > SAL_CALL OwnSubFilterService::impl_staticCreateSelfInstance( + const uno::Reference< lang::XMultiServiceFactory >& xServiceManager ) +{ + return uno::Reference< uno::XInterface >( *new OwnSubFilterService( xServiceManager ) ); +} + +//------------------------------------------------------------------------- +uno::Reference< lang::XSingleServiceFactory > SAL_CALL OwnSubFilterService::impl_createFactory( + const uno::Reference< lang::XMultiServiceFactory >& xServiceManager ) +{ + return ::cppu::createSingleFactory( xServiceManager, + OwnSubFilterService::impl_getStaticImplementationName(), + OwnSubFilterService::impl_staticCreateSelfInstance, + OwnSubFilterService::impl_getStaticSupportedServiceNames() ); +} + + +// XFilter + +//------------------------------------------------------------------------- +sal_Bool SAL_CALL OwnSubFilterService::filter( const uno::Sequence< beans::PropertyValue >& aDescriptor ) + throw (uno::RuntimeException) +{ + if ( !m_pObjectShell ) + throw uno::RuntimeException(); + + return m_pObjectShell->ImportFromGeneratedStream_Impl( m_xStream, aDescriptor ); +} + +//------------------------------------------------------------------------- +void SAL_CALL OwnSubFilterService::cancel() + throw (uno::RuntimeException) +{ + // not implemented +} + + +// XInitialization + +//------------------------------------------------------------------------- +void SAL_CALL OwnSubFilterService::initialize( const uno::Sequence< uno::Any >& aArguments ) + throw (uno::Exception, uno::RuntimeException) +{ + if ( !m_xFactory.is() ) + throw uno::RuntimeException(); + + if ( aArguments.getLength() != 2 ) + throw lang::IllegalArgumentException(); + + if ( m_pObjectShell ) + throw frame::DoubleInitializationException(); + + if ( ( aArguments[1] >>= m_xStream ) && m_xStream.is() + && ( aArguments[0] >>= m_xModel ) && m_xModel.is() ) + { + ::com::sun::star::uno::Reference < ::com::sun::star::lang::XUnoTunnel > xObj( m_xModel, uno::UNO_QUERY_THROW ); + ::com::sun::star::uno::Sequence < sal_Int8 > aSeq( SvGlobalName( SFX_GLOBAL_CLASSID ).GetByteSequence() ); + sal_Int64 nHandle = xObj->getSomething( aSeq ); + if ( nHandle ) + m_pObjectShell = reinterpret_cast< SfxObjectShell* >( sal::static_int_cast< sal_IntPtr >( nHandle )); + } + + if ( !m_pObjectShell ) + throw lang::IllegalArgumentException(); +} + + +// XServiceInfo + +//------------------------------------------------------------------------- +::rtl::OUString SAL_CALL OwnSubFilterService::getImplementationName() + throw ( uno::RuntimeException ) +{ + return impl_getStaticImplementationName(); +} + +//------------------------------------------------------------------------- +sal_Bool SAL_CALL OwnSubFilterService::supportsService( const ::rtl::OUString& ServiceName ) + throw ( uno::RuntimeException ) +{ + uno::Sequence< ::rtl::OUString > aSeq = impl_getStaticSupportedServiceNames(); + + for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ ) + if ( ServiceName.compareTo( aSeq[nInd] ) == 0 ) + return sal_True; + + return sal_False; +} + +//------------------------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OwnSubFilterService::getSupportedServiceNames() + throw ( uno::RuntimeException ) +{ + return impl_getStaticSupportedServiceNames(); +} + +} // namespace sfx2 + diff --git a/sfx2/source/doc/plugin.cxx b/sfx2/source/doc/plugin.cxx new file mode 100644 index 000000000000..9ff8c73acbf6 --- /dev/null +++ b/sfx2/source/doc/plugin.cxx @@ -0,0 +1,266 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include "plugin.hxx" +#include <com/sun/star/plugin/XPluginManager.hpp> +#include <com/sun/star/plugin/PluginMode.hpp> +#include <com/sun/star/awt/XControl.hpp> + +#include <tools/debug.hxx> +#include <rtl/ustring.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <svtools/miscopt.hxx> +#include <vcl/window.hxx> + +using namespace ::com::sun::star; + +namespace sfx2 +{ + +class PluginWindow_Impl : public Window +{ +public: + uno::Reference < awt::XWindow > xWindow; + PluginWindow_Impl( Window* pParent ) + : Window( pParent, WB_CLIPCHILDREN ) + {} + + virtual void Resize(); +}; + +void PluginWindow_Impl::Resize() +{ + Size aSize( GetOutputSizePixel() ); + if ( xWindow.is() ) + xWindow->setPosSize( 0, 0, aSize.Width(), aSize.Height(), WINDOW_POSSIZE_SIZE ); +} + +#define PROPERTY_UNBOUND 0 + +#define WID_COMMANDS 1 +#define WID_MIMETYPE 2 +#define WID_URL 3 +const SfxItemPropertyMapEntry* lcl_GetPluginPropertyMap_Impl() +{ + static SfxItemPropertyMapEntry aPluginPropertyMap_Impl[] = + { + { MAP_CHAR_LEN("PluginCommands"), WID_COMMANDS, &::getCppuType((::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >*)0), PROPERTY_UNBOUND, 0}, + { MAP_CHAR_LEN("PluginMimeType"), WID_MIMETYPE, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + { MAP_CHAR_LEN("PluginURL"), WID_URL , &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 }, + {0,0,0,0,0,0} + }; + return aPluginPropertyMap_Impl; +} + +SFX_IMPL_XSERVICEINFO( PluginObject, "com.sun.star.embed.SpecialEmbeddedObject", "com.sun.star.comp.sfx2.PluginObject" ) +SFX_IMPL_SINGLEFACTORY( PluginObject ); + +PluginObject::PluginObject( const uno::Reference < lang::XMultiServiceFactory >& rFact ) + : mxFact( rFact ) + , maPropMap( lcl_GetPluginPropertyMap_Impl() ) +{ +} + +PluginObject::~PluginObject() +{ +} + +void SAL_CALL PluginObject::initialize( const uno::Sequence< uno::Any >& aArguments ) throw ( uno::Exception, uno::RuntimeException ) +{ + if ( aArguments.getLength() ) + aArguments[0] >>= mxObj; +} + +sal_Bool SAL_CALL PluginObject::load( + const uno::Sequence < com::sun::star::beans::PropertyValue >& /*lDescriptor*/, + const uno::Reference < frame::XFrame >& xFrame ) +throw( uno::RuntimeException ) +{ + uno::Reference< plugin::XPluginManager > xPMgr( mxFact->createInstance( ::rtl::OUString::createFromAscii("com.sun.star.plugin.PluginManager") ), uno::UNO_QUERY ); + if (!xPMgr.is() ) + return FALSE; + + if ( SvtMiscOptions().IsPluginsEnabled() ) + { + Window* pParent = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() ); + PluginWindow_Impl* pWin = new PluginWindow_Impl( pParent ); + pWin->SetSizePixel( pParent->GetOutputSizePixel() ); + pWin->SetBackground(); + pWin->Show(); + + ULONG nCount = maCmdList.Count(); + uno::Sequence < ::rtl::OUString > aCmds( nCount ), aArgs( nCount ); + ::rtl::OUString *pCmds = aCmds.getArray(), *pArgs = aArgs.getArray(); + for( ULONG i = 0; i < nCount; i++ ) + { + SvCommand & rCmd = maCmdList.GetObject( i ); + pCmds[i] = rCmd.GetCommand(); + pArgs[i] = rCmd.GetArgument(); + } + + mxPlugin = xPMgr->createPluginFromURL( + xPMgr->createPluginContext(), plugin::PluginMode::EMBED, aCmds, aArgs, uno::Reference< awt::XToolkit >(), + uno::Reference< awt::XWindowPeer >( pWin->GetComponentInterface() ), maURL ); + + if ( mxPlugin.is() ) + { + uno::Reference< awt::XWindow > xWindow( mxPlugin, uno::UNO_QUERY ); + if ( xWindow.is() ) + { + pWin->xWindow = xWindow; + pWin->Resize(); + xWindow->setVisible( TRUE ); + } + + try + { + uno::Reference< awt::XControl > xControl( mxPlugin, uno::UNO_QUERY ); + if( xControl.is() ) + { + uno::Reference< awt::XControlModel > xModel = xControl->getModel(); + uno::Reference< beans::XPropertySet > xProp( xModel, ::uno::UNO_QUERY ); + if( xProp.is() ) + { + uno::Any aValue = xProp->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) ) ); + aValue >>= maURL; + aValue = xProp->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TYPE" ) ) ); + aValue >>= maMimeType; + } + } + } + catch( uno::Exception& ) + { + } + } + + uno::Reference < awt::XWindow > xWindow( pWin->GetComponentInterface(), uno::UNO_QUERY ); + + // we must destroy the plugin before the parent is destroyed + xWindow->addEventListener( this ); + xFrame->setComponent( xWindow, uno::Reference < frame::XController >() ); + return mxPlugin.is() ? TRUE : FALSE; + } + + return FALSE; +} + +void SAL_CALL PluginObject::cancel() throw( com::sun::star::uno::RuntimeException ) +{ + uno::Reference< lang::XComponent > xComp( mxPlugin, uno::UNO_QUERY ); + if (xComp.is()) + xComp->dispose(); + mxPlugin = 0; +} + +void SAL_CALL PluginObject::close( sal_Bool /*bDeliverOwnership*/ ) throw( com::sun::star::util::CloseVetoException, com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL PluginObject::addCloseListener( const com::sun::star::uno::Reference < com::sun::star::util::XCloseListener >& ) throw( com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL PluginObject::removeCloseListener( const com::sun::star::uno::Reference < com::sun::star::util::XCloseListener >& ) throw( com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL PluginObject::disposing( const com::sun::star::lang::EventObject& ) throw (com::sun::star::uno::RuntimeException) +{ + cancel(); +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL PluginObject::getPropertySetInfo() throw( ::com::sun::star::uno::RuntimeException ) +{ + static uno::Reference< beans::XPropertySetInfo > xInfo = new SfxItemPropertySetInfo( &maPropMap ); + return xInfo; +} + +void SAL_CALL PluginObject::setPropertyValue(const ::rtl::OUString& aPropertyName, const uno::Any& aAny) + throw ( beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException) +{ + if ( aPropertyName.equalsAscii("PluginURL") ) + { + aAny >>= maURL; + } + else if ( aPropertyName.equalsAscii("PluginMimeType") ) + { + aAny >>= maMimeType; + } + else if ( aPropertyName.equalsAscii("PluginCommands") ) + { + maCmdList.Clear(); + uno::Sequence < beans::PropertyValue > aCommandSequence; + if( aAny >>= aCommandSequence ) + maCmdList.FillFromSequence( aCommandSequence ); + } + else + throw beans::UnknownPropertyException(); +} + +uno::Any SAL_CALL PluginObject::getPropertyValue(const ::rtl::OUString& aPropertyName) + throw ( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + uno::Any aAny; + if ( aPropertyName.equalsAscii("PluginURL") ) + { + aAny <<= maURL; + } + else if ( aPropertyName.equalsAscii("PluginMimeType") ) + { + aAny <<= maMimeType; + } + else if ( aPropertyName.equalsAscii("PluginCommands") ) + { + uno::Sequence< beans::PropertyValue > aCommandSequence; + maCmdList.FillSequence( aCommandSequence ); + aAny <<= aCommandSequence; + } + else + throw beans::UnknownPropertyException(); + return aAny; +} + +void SAL_CALL PluginObject::addPropertyChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL PluginObject::removePropertyChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL PluginObject::addVetoableChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException ) +{ +} + +void SAL_CALL PluginObject::removeVetoableChangeListener(const ::rtl::OUString&, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener > & ) throw( ::com::sun::star::uno::RuntimeException ) +{ +} + +} diff --git a/sfx2/source/doc/printhelper.cxx b/sfx2/source/doc/printhelper.cxx new file mode 100755 index 000000000000..2cd195976832 --- /dev/null +++ b/sfx2/source/doc/printhelper.cxx @@ -0,0 +1,906 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include "printhelper.hxx" + +#include <com/sun/star/view/XPrintJob.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/view/PaperFormat.hpp> +#include <com/sun/star/view/PaperOrientation.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/EventObject.hpp> +#include <com/sun/star/view/DuplexMode.hpp> + +#include <svl/lstner.hxx> +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <svl/eitem.hxx> +#include <unotools/tempfile.hxx> +#include <unotools/localfilehelper.hxx> +#include <osl/file.hxx> +#include <osl/thread.hxx> +#include <tools/urlobj.hxx> +#include <ucbhelper/content.hxx> +#include <cppuhelper/interfacecontainer.hxx> +#include <vos/mutex.hxx> +#include <svtools/printdlg.hxx> +#include <cppuhelper/implbase1.hxx> + +#include <sfx2/viewfrm.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/request.hxx> +#include <sfx2/printer.hxx> +#include <sfx2/app.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/event.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +struct IMPL_PrintListener_DataContainer : public SfxListener +{ + SfxObjectShellRef m_pObjectShell; + ::cppu::OMultiTypeInterfaceContainerHelper m_aInterfaceContainer; + uno::Reference< com::sun::star::view::XPrintJob> m_xPrintJob; + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > m_aPrintOptions; + + IMPL_PrintListener_DataContainer( ::osl::Mutex& aMutex) + : m_pObjectShell ( 0 ) + , m_aInterfaceContainer ( aMutex ) + { + } + + + void Notify( SfxBroadcaster& aBC , + const SfxHint& aHint ) ; +}; + +awt::Size impl_Size_Object2Struct( const Size& aSize ) +{ + awt::Size aReturnValue; + aReturnValue.Width = aSize.Width() ; + aReturnValue.Height = aSize.Height() ; + return aReturnValue ; +} + +Size impl_Size_Struct2Object( const awt::Size& aSize ) +{ + Size aReturnValue; + aReturnValue.Width() = aSize.Width ; + aReturnValue.Height() = aSize.Height ; + return aReturnValue ; +} + +class SfxPrintJob_Impl : public cppu::WeakImplHelper1 +< + com::sun::star::view::XPrintJob +> +{ + IMPL_PrintListener_DataContainer* m_pData; + +public: + SfxPrintJob_Impl( IMPL_PrintListener_DataContainer* pData ); + virtual Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getPrintOptions( ) throw (RuntimeException); + virtual Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getPrinter( ) throw (RuntimeException); + virtual Reference< ::com::sun::star::view::XPrintable > SAL_CALL getPrintable( ) throw (RuntimeException); + virtual void SAL_CALL cancelJob() throw (RuntimeException); +}; + +SfxPrintJob_Impl::SfxPrintJob_Impl( IMPL_PrintListener_DataContainer* pData ) + : m_pData( pData ) +{ +} + +Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL SfxPrintJob_Impl::getPrintOptions() throw (RuntimeException) +{ + return m_pData->m_aPrintOptions; +} + +Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL SfxPrintJob_Impl::getPrinter() throw (RuntimeException) +{ + if( m_pData->m_pObjectShell.Is() ) + { + Reference < view::XPrintable > xPrintable( m_pData->m_pObjectShell->GetModel(), UNO_QUERY ); + if ( xPrintable.is() ) + return xPrintable->getPrinter(); + } + return Sequence< ::com::sun::star::beans::PropertyValue >(); +} + +Reference< ::com::sun::star::view::XPrintable > SAL_CALL SfxPrintJob_Impl::getPrintable() throw (RuntimeException) +{ + Reference < view::XPrintable > xPrintable( m_pData->m_pObjectShell.Is() ? m_pData->m_pObjectShell->GetModel() : NULL, UNO_QUERY ); + return xPrintable; +} + +void SAL_CALL SfxPrintJob_Impl::cancelJob() throw (RuntimeException) +{ + // FIXME: how to cancel PrintJob via API?! + if( m_pData->m_pObjectShell.Is() ) + m_pData->m_pObjectShell->Broadcast( SfxPrintingHint( -2 ) ); +} + +SfxPrintHelper::SfxPrintHelper() +{ + m_pData = new IMPL_PrintListener_DataContainer(m_aMutex); +} + +void SAL_CALL SfxPrintHelper::initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException) +{ + if ( aArguments.getLength() ) + { + com::sun::star::uno::Reference < com::sun::star::frame::XModel > xModel; + aArguments[0] >>= xModel; + uno::Reference < lang::XUnoTunnel > xObj( xModel, uno::UNO_QUERY ); + uno::Sequence < sal_Int8 > aSeq( SvGlobalName( SFX_GLOBAL_CLASSID ).GetByteSequence() ); + sal_Int64 nHandle = xObj->getSomething( aSeq ); + if ( nHandle ) + { + m_pData->m_pObjectShell = reinterpret_cast< SfxObjectShell* >( sal::static_int_cast< sal_IntPtr >( nHandle )); + m_pData->StartListening(*m_pData->m_pObjectShell); + } + } +} + +SfxPrintHelper::~SfxPrintHelper() +{ + delete m_pData; +} + +namespace +{ + view::PaperFormat convertToPaperFormat(Paper eFormat) + { + view::PaperFormat eRet; + switch (eFormat) + { + case PAPER_A3: + eRet = view::PaperFormat_A3; + break; + case PAPER_A4: + eRet = view::PaperFormat_A4; + break; + case PAPER_A5: + eRet = view::PaperFormat_A5; + break; + case PAPER_B4_ISO: + eRet = view::PaperFormat_B4; + break; + case PAPER_B5_ISO: + eRet = view::PaperFormat_B5; + break; + case PAPER_LETTER: + eRet = view::PaperFormat_LETTER; + break; + case PAPER_LEGAL: + eRet = view::PaperFormat_LEGAL; + break; + case PAPER_TABLOID: + eRet = view::PaperFormat_TABLOID; + break; + case PAPER_USER: + default: + eRet = view::PaperFormat_USER; + break; + } + return eRet; + } + + Paper convertToPaper(view::PaperFormat eFormat) + { + Paper eRet(PAPER_USER); + switch (eFormat) + { + case view::PaperFormat_A3: + eRet = PAPER_A3; + break; + case view::PaperFormat_A4: + eRet = PAPER_A4; + break; + case view::PaperFormat_A5: + eRet = PAPER_A5; + break; + case view::PaperFormat_B4: + eRet = PAPER_B4_ISO; + break; + case view::PaperFormat_B5: + eRet = PAPER_B5_ISO; + break; + case view::PaperFormat_LETTER: + eRet = PAPER_LETTER; + break; + case view::PaperFormat_LEGAL: + eRet = PAPER_LEGAL; + break; + case view::PaperFormat_TABLOID: + eRet = PAPER_TABLOID; + break; + case view::PaperFormat_USER: + eRet = PAPER_USER; + break; + case view::PaperFormat_MAKE_FIXED_SIZE: + break; + //deliberate no default to force warn on a new papersize + } + return eRet; + } +} + +//________________________________________________________________________________________________________ +// XPrintable +//________________________________________________________________________________________________________ + +uno::Sequence< beans::PropertyValue > SAL_CALL SfxPrintHelper::getPrinter() throw(::com::sun::star::uno::RuntimeException) +{ + // object already disposed? + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + // search for any view of this document that is currently printing + const Printer *pPrinter = NULL; + SfxViewFrame *pViewFrm = m_pData->m_pObjectShell.Is() ? SfxViewFrame::GetFirst( m_pData->m_pObjectShell, sal_False ) : 0; + SfxViewFrame* pFirst = pViewFrm; + while ( pViewFrm && !pPrinter ) + { + pPrinter = pViewFrm->GetViewShell()->GetActivePrinter(); + pViewFrm = SfxViewFrame::GetNext( *pViewFrm, m_pData->m_pObjectShell, sal_False ); + } + + // if no view is printing currently, use the permanent SfxPrinter instance + if ( !pPrinter && pFirst ) + pPrinter = pFirst->GetViewShell()->GetPrinter(sal_True); + + if ( !pPrinter ) + return uno::Sequence< beans::PropertyValue >(); + + uno::Sequence< beans::PropertyValue > aPrinter(8); + + aPrinter.getArray()[7].Name = DEFINE_CONST_UNICODE( "CanSetPaperSize" ); + aPrinter.getArray()[7].Value <<= ( pPrinter->HasSupport( SUPPORT_SET_PAPERSIZE ) ); + + aPrinter.getArray()[6].Name = DEFINE_CONST_UNICODE( "CanSetPaperFormat" ); + aPrinter.getArray()[6].Value <<= ( pPrinter->HasSupport( SUPPORT_SET_PAPER ) ); + + aPrinter.getArray()[5].Name = DEFINE_CONST_UNICODE( "CanSetPaperOrientation" ); + aPrinter.getArray()[5].Value <<= ( pPrinter->HasSupport( SUPPORT_SET_ORIENTATION ) ); + + aPrinter.getArray()[4].Name = DEFINE_CONST_UNICODE( "IsBusy" ); + aPrinter.getArray()[4].Value <<= ( pPrinter->IsPrinting() ); + + aPrinter.getArray()[3].Name = DEFINE_CONST_UNICODE( "PaperSize" ); + awt::Size aSize = impl_Size_Object2Struct(pPrinter->GetPaperSize() ); + aPrinter.getArray()[3].Value <<= aSize; + + aPrinter.getArray()[2].Name = DEFINE_CONST_UNICODE( "PaperFormat" ); + view::PaperFormat eFormat = convertToPaperFormat(pPrinter->GetPaper()); + aPrinter.getArray()[2].Value <<= eFormat; + + aPrinter.getArray()[1].Name = DEFINE_CONST_UNICODE( "PaperOrientation" ); + view::PaperOrientation eOrient = (view::PaperOrientation)pPrinter->GetOrientation(); + aPrinter.getArray()[1].Value <<= eOrient; + + aPrinter.getArray()[0].Name = DEFINE_CONST_UNICODE( "Name" ); + String sStringTemp = pPrinter->GetName() ; + aPrinter.getArray()[0].Value <<= ::rtl::OUString( sStringTemp ); + + return aPrinter; +} + +//________________________________________________________________________________________________________ +// XPrintable +//________________________________________________________________________________________________________ + +void SfxPrintHelper::impl_setPrinter(const uno::Sequence< beans::PropertyValue >& rPrinter,SfxPrinter*& pPrinter,sal_uInt16& nChangeFlags,SfxViewShell*& pViewSh) + +{ + // alten Printer beschaffen + SfxViewFrame *pViewFrm = m_pData->m_pObjectShell.Is() ? + SfxViewFrame::GetFirst( m_pData->m_pObjectShell, sal_False ) : 0; + if ( !pViewFrm ) + return; + + pViewSh = pViewFrm->GetViewShell(); + pPrinter = pViewSh->GetPrinter(sal_True); + if ( !pPrinter ) + return; + + // new Printer-Name available? + nChangeFlags = 0; + sal_Int32 lDummy = 0; + for ( int n = 0; n < rPrinter.getLength(); ++n ) + { + // get Property-Value from printer description + const beans::PropertyValue &rProp = rPrinter.getConstArray()[n]; + + // Name-Property? + if ( rProp.Name.compareToAscii( "Name" ) == 0 ) + { + OUSTRING sTemp; + if ( ( rProp.Value >>= sTemp ) == sal_False ) + throw ::com::sun::star::lang::IllegalArgumentException(); + + String aPrinterName( sTemp ) ; + if ( aPrinterName != pPrinter->GetName() ) + { + pPrinter = new SfxPrinter( pPrinter->GetOptions().Clone(), aPrinterName ); + nChangeFlags = SFX_PRINTER_PRINTER; + } + break; + } + } + + Size aSetPaperSize( 0, 0); + view::PaperFormat nPaperFormat = view::PaperFormat_USER; + + // other properties + for ( int i = 0; i < rPrinter.getLength(); ++i ) + { + // get Property-Value from printer description + const beans::PropertyValue &rProp = rPrinter.getConstArray()[i]; + + // PaperOrientation-Property? + if ( rProp.Name.compareToAscii( "PaperOrientation" ) == 0 ) + { + view::PaperOrientation eOrient; + if ( ( rProp.Value >>= eOrient ) == sal_False ) + { + if ( ( rProp.Value >>= lDummy ) == sal_False ) + throw ::com::sun::star::lang::IllegalArgumentException(); + eOrient = ( view::PaperOrientation) lDummy; + } + + if ( (Orientation) eOrient != pPrinter->GetOrientation() ) + { + pPrinter->SetOrientation( (Orientation) eOrient ); + nChangeFlags |= SFX_PRINTER_CHG_ORIENTATION; + } + } + + // PaperFormat-Property? + else if ( rProp.Name.compareToAscii( "PaperFormat" ) == 0 ) + { + if ( ( rProp.Value >>= nPaperFormat ) == sal_False ) + { + if ( ( rProp.Value >>= lDummy ) == sal_False ) + throw ::com::sun::star::lang::IllegalArgumentException(); + nPaperFormat = ( view::PaperFormat ) lDummy; + } + + if ( convertToPaper(nPaperFormat) != pPrinter->GetPaper() ) + { + pPrinter->SetPaper( convertToPaper(nPaperFormat) ); + nChangeFlags |= SFX_PRINTER_CHG_SIZE; + } + } + + // PaperSize-Property? + else if ( rProp.Name.compareToAscii( "PaperSize" ) == 0 ) + { + awt::Size aTempSize ; + if ( ( rProp.Value >>= aTempSize ) == sal_False ) + { + throw ::com::sun::star::lang::IllegalArgumentException(); + } + else + { + aSetPaperSize = impl_Size_Struct2Object(aTempSize); + } + } + + // PrinterTray-Property + else if ( rProp.Name.compareToAscii( "PrinterPaperTray" ) == 0 ) + { + rtl::OUString aTmp; + if ( ( rProp.Value >>= aTmp ) == sal_False ) + throw ::com::sun::star::lang::IllegalArgumentException(); + USHORT nCount = pPrinter->GetPaperBinCount(); + for (USHORT nBin=0; nBin<nCount; nBin++) + { + ::rtl::OUString aName( pPrinter->GetPaperBinName(nBin) ); + if ( aName == aTmp ) + { + pPrinter->SetPaperBin(nBin); + break; + } + } + } + } + + //os 12.11.98: die PaperSize darf nur gesetzt werden, wenn tatsaechlich + //PAPER_USER gilt, sonst koennte vom Treiber ein falsches Format gewaehlt werden + if(nPaperFormat == view::PaperFormat_USER && aSetPaperSize.Width()) + { + //JP 23.09.98 - Bug 56929 - MapMode von 100mm in die am + // Device gesetzten umrechnen. Zusaetzlich nur dann + // setzen, wenn sie wirklich veraendert wurden. + aSetPaperSize = pPrinter->LogicToPixel( aSetPaperSize, MAP_100TH_MM ); + if( aSetPaperSize != pPrinter->GetPaperSizePixel() ) + { + pPrinter->SetPaperSizeUser( pPrinter->PixelToLogic( aSetPaperSize ) ); + nChangeFlags |= SFX_PRINTER_CHG_SIZE; + } + } + + // #96772#: wait until printing is done + SfxPrinter* pDocPrinter = pViewSh->GetPrinter(); + while ( pDocPrinter->IsPrinting() ) + Application::Yield(); +} + +void SAL_CALL SfxPrintHelper::setPrinter(const uno::Sequence< beans::PropertyValue >& rPrinter) + throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) +{ + // object already disposed? + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + SfxViewShell* pViewSh = NULL; + SfxPrinter* pPrinter = NULL; + sal_uInt16 nChangeFlags = 0; + impl_setPrinter(rPrinter,pPrinter,nChangeFlags,pViewSh); + // set new printer + if ( pViewSh && pPrinter ) + pViewSh->SetPrinter( pPrinter, nChangeFlags, false ); +} + +//________________________________________________________________________________________________________ +// ImplPrintWatch thread for asynchronous printing with moving temp. file to ucb location +//________________________________________________________________________________________________________ + +/* This implements a thread which will be started to wait for asynchronous + print jobs to temp. localy files. If they finish we move the temp. files + to her right locations by using the ucb. + */ +class ImplUCBPrintWatcher : public ::osl::Thread +{ + private: + /// of course we must know the printer which execute the job + SfxPrinter* m_pPrinter; + /// this describes the target location for the printed temp file + String m_sTargetURL; + /// it holds the temp file alive, till the print job will finish and remove it from disk automaticly if the object die + ::utl::TempFile* m_pTempFile; + + public: + /* initialize this watcher but don't start it */ + ImplUCBPrintWatcher( SfxPrinter* pPrinter, ::utl::TempFile* pTempFile, const String& sTargetURL ) + : m_pPrinter ( pPrinter ) + , m_sTargetURL( sTargetURL ) + , m_pTempFile ( pTempFile ) + {} + + /* waits for finishing of the print job and moves the temp file afterwards + Note: Starting of the job is done outside this thread! + But we have to free some of the given ressources on heap! + */ + void SAL_CALL run() + { + /* SAFE { */ + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + while( m_pPrinter->IsPrinting() ) + Application::Yield(); + m_pPrinter = NULL; // don't delete it! It's borrowed only :-) + } + /* } SAFE */ + + // lock for further using of our member isn't neccessary - because + // we truns alone by defenition. Nobody join for us nor use us ... + ImplUCBPrintWatcher::moveAndDeleteTemp(&m_pTempFile,m_sTargetURL); + + // finishing of this run() method will call onTerminate() automaticly + // kill this thread there! + } + + /* nobody wait for this thread. We must kill ourself ... + */ + void SAL_CALL onTerminated() + { + delete this; + } + + /* static helper to move the temp. file to the target location by using the ucb + It's static to be useable from outside too. So it's not realy neccessary to start + the thread, if finishing of the job was detected outside this thread. + But it must be called without using a corresponding thread for the given parameter! + */ + static void moveAndDeleteTemp( ::utl::TempFile** ppTempFile, const String& sTargetURL ) + { + // move the file + try + { + INetURLObject aSplitter(sTargetURL); + String sFileName = aSplitter.getName( + INetURLObject::LAST_SEGMENT, + true, + INetURLObject::DECODE_WITH_CHARSET); + if (aSplitter.removeSegment() && sFileName.Len()>0) + { + ::ucbhelper::Content aSource( + ::rtl::OUString((*ppTempFile)->GetURL()), + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >()); + + ::ucbhelper::Content aTarget( + ::rtl::OUString(aSplitter.GetMainURL(INetURLObject::NO_DECODE)), + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >()); + + aTarget.transferContent( + aSource, + ::ucbhelper::InsertOperation_COPY, + ::rtl::OUString(sFileName), + ::com::sun::star::ucb::NameClash::OVERWRITE); + } + } + catch( ::com::sun::star::ucb::ContentCreationException& ) { DBG_ERROR("content create exception"); } + catch( ::com::sun::star::ucb::CommandAbortedException& ) { DBG_ERROR("command abort exception"); } + catch( ::com::sun::star::uno::RuntimeException& ) { DBG_ERROR("runtime exception"); } + catch( ::com::sun::star::uno::Exception& ) { DBG_ERROR("unknown exception"); } + + // kill the temp file! + delete *ppTempFile; + *ppTempFile = NULL; + } +}; + +//------------------------------------------------ + +//________________________________________________________________________________________________________ +// XPrintable +//________________________________________________________________________________________________________ +void SAL_CALL SfxPrintHelper::print(const uno::Sequence< beans::PropertyValue >& rOptions) + throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) +{ + if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() ) + return; + + // object already disposed? + // object already disposed? + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + // get view for sfx printing capabilities + SfxViewFrame *pViewFrm = m_pData->m_pObjectShell.Is() ? + SfxViewFrame::GetFirst( m_pData->m_pObjectShell, sal_False ) : 0; + if ( !pViewFrm ) + return; + SfxViewShell* pView = pViewFrm->GetViewShell(); + if ( !pView ) + return; + +// SfxAllItemSet aArgs( pView->GetPool() ); + sal_Bool bMonitor = sal_False; + // We need this information at the end of this method, if we start the vcl printer + // by executing the slot. Because if it is a ucb relevant URL we must wait for + // finishing the print job and move the temporary local file by using the ucb + // to the right location. But in case of no file name is given or it is already + // a local one we can supress this special handling. Because then vcl makes all + // right for us. + String sUcbUrl; + ::utl::TempFile* pUCBPrintTempFile = NULL; + + uno::Sequence < beans::PropertyValue > aCheckedArgs( rOptions.getLength() ); + sal_Int32 nProps = 0; + sal_Bool bWaitUntilEnd = sal_False; + sal_Int16 nDuplexMode = ::com::sun::star::view::DuplexMode::UNKNOWN; + for ( int n = 0; n < rOptions.getLength(); ++n ) + { + // get Property-Value from options + const beans::PropertyValue &rProp = rOptions.getConstArray()[n]; + + // FileName-Property? + if ( rProp.Name.compareToAscii( "FileName" ) == 0 ) + { + // unpack th URL and check for a valid and well known protocol + OUSTRING sTemp; + if ( + ( rProp.Value.getValueType()!=::getCppuType((const OUSTRING*)0)) || + (!(rProp.Value>>=sTemp)) + ) + { + throw ::com::sun::star::lang::IllegalArgumentException(); + } + + String sPath ; + String sURL (sTemp); + INetURLObject aCheck(sURL ); + if (aCheck.GetProtocol()==INET_PROT_NOT_VALID) + { + // OK - it's not a valid URL. But may it's a simple + // system path directly. It will be supported for historical + // reasons. Otherwhise we break to much external code ... + // We try to convert it to a file URL. If its possible + // we put the system path to the item set and let vcl work with it. + // No ucb or thread will be neccessary then. In case it couldnt be + // converted its not an URL nor a system path. Then we can't accept + // this parameter and have to throw an exception. + ::rtl::OUString sSystemPath(sTemp); + ::rtl::OUString sFileURL; + if (::osl::FileBase::getFileURLFromSystemPath(sSystemPath,sFileURL)!=::osl::FileBase::E_None) + throw ::com::sun::star::lang::IllegalArgumentException(); + aCheckedArgs[nProps].Name = rProp.Name; + aCheckedArgs[nProps++].Value <<= sFileURL; + // and append the local filename + aCheckedArgs.realloc( aCheckedArgs.getLength()+1 ); + aCheckedArgs[nProps].Name = rtl::OUString::createFromAscii("LocalFileName"); + aCheckedArgs[nProps++].Value <<= ::rtl::OUString( sTemp ); + } + else + // It's a valid URL. but now we must know, if it is a local one or not. + // It's a question of using ucb or not! + if (::utl::LocalFileHelper::ConvertURLToSystemPath(sURL,sPath)) + { + // it's a local file, we can use vcl without special handling + // And we have to use the system notation of the incoming URL. + // But it into the descriptor and let the slot be executed at + // the end of this method. + aCheckedArgs[nProps].Name = rProp.Name; + aCheckedArgs[nProps++].Value <<= sTemp; + // and append the local filename + aCheckedArgs.realloc( aCheckedArgs.getLength()+1 ); + aCheckedArgs[nProps].Name = rtl::OUString::createFromAscii("LocalFileName"); + aCheckedArgs[nProps++].Value <<= ::rtl::OUString( sPath ); + } + else + { + // it's an ucb target. So we must use a temp. file for vcl + // and move it after printing by using the ucb. + // Create a temp file on the heap (because it must delete the + // real file on disk automaticly if it die - bt we have to share it with + // some other sources ... e.g. the ImplUCBPrintWatcher). + // And we put the name of this temp file to the descriptor instead + // of the URL. The URL we save for later using seperatly. + // Execution of the print job will be done later by executing + // a slot ... + pUCBPrintTempFile = new ::utl::TempFile(); + pUCBPrintTempFile->EnableKillingFile(); + + //FIXME: does it work? + aCheckedArgs[nProps].Name = rtl::OUString::createFromAscii("LocalFileName"); + aCheckedArgs[nProps++].Value <<= ::rtl::OUString( pUCBPrintTempFile->GetFileName() ); + sUcbUrl = sURL; + } + } + + // CopyCount-Property + else if ( rProp.Name.compareToAscii( "CopyCount" ) == 0 ) + { + sal_Int32 nCopies = 0; + if ( ( rProp.Value >>= nCopies ) == sal_False ) + throw ::com::sun::star::lang::IllegalArgumentException(); + + aCheckedArgs[nProps].Name = rProp.Name; + aCheckedArgs[nProps++].Value <<= nCopies; + } + + // Collate-Property + // Sort-Property (deprecated) + else if ( rProp.Name.compareToAscii( "Collate" ) == 0 || + ( rProp.Name.compareToAscii( "Sort" ) == 0 ) ) + { + sal_Bool bTemp = sal_Bool(); + if ( rProp.Value >>= bTemp ) + { + aCheckedArgs[nProps].Name = rtl::OUString::createFromAscii("Collate"); + aCheckedArgs[nProps++].Value <<= bTemp; + } + else + throw ::com::sun::star::lang::IllegalArgumentException(); + } + + // Pages-Property + else if ( rProp.Name.compareToAscii( "Pages" ) == 0 ) + { + OUSTRING sTemp; + if( rProp.Value >>= sTemp ) + { + aCheckedArgs[nProps].Name = rProp.Name; + aCheckedArgs[nProps++].Value <<= sTemp; + } + else + throw ::com::sun::star::lang::IllegalArgumentException(); + } + + // MonitorVisible + else if ( rProp.Name.compareToAscii( "MonitorVisible" ) == 0 ) + { + if( !(rProp.Value >>= bMonitor) ) + throw ::com::sun::star::lang::IllegalArgumentException(); + aCheckedArgs[nProps].Name = rProp.Name; + aCheckedArgs[nProps++].Value <<= bMonitor; + } + + // Wait + else if ( rProp.Name.compareToAscii( "Wait" ) == 0 ) + { + if ( !(rProp.Value >>= bWaitUntilEnd) ) + throw ::com::sun::star::lang::IllegalArgumentException(); + aCheckedArgs[nProps].Name = rProp.Name; + aCheckedArgs[nProps++].Value <<= bWaitUntilEnd; + } + + else if ( rProp.Name.compareToAscii( "DuplexMode" ) == 0 ) + { + if ( !(rProp.Value >>= nDuplexMode ) ) + throw ::com::sun::star::lang::IllegalArgumentException(); + aCheckedArgs[nProps].Name = rProp.Name; + aCheckedArgs[nProps++].Value <<= nDuplexMode; + } + } + + if ( nProps != aCheckedArgs.getLength() ) + aCheckedArgs.realloc(nProps); + + // Execute the print request every time. + // It doesn'tmatter if it is a real printer used or we print to a local file + // nor if we print to a temp file and move it afterwards by using the ucb. + // That will be handled later. see pUCBPrintFile below! + pView->ExecPrint( aCheckedArgs, sal_True, sal_False ); + + // Ok - may be execution before has finished (or started!) printing. + // And may it was a printing to a file. + // Now we have to check if we can move the file (if neccessary) via ucb to his right location. + // Cases: + // a) printing finished => move the file directly and forget the watcher thread + // b) printing is asynchron and runs currently => start watcher thread and exit this method + // This thread make all neccessary things by itself. + if (pUCBPrintTempFile!=NULL) + { + // a) + SfxPrinter* pPrinter = pView->GetPrinter(); + if ( ! pPrinter->IsPrinting() ) + ImplUCBPrintWatcher::moveAndDeleteTemp(&pUCBPrintTempFile,sUcbUrl); + // b) + else + { + // Note: we create(d) some ressource on the heap. (thread and tep file) + // They will be delected by the thread automaticly if he finish his run() method. + ImplUCBPrintWatcher* pWatcher = new ImplUCBPrintWatcher( pPrinter, pUCBPrintTempFile, sUcbUrl ); + pWatcher->create(); + } + } +} + +void IMPL_PrintListener_DataContainer::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + if ( &rBC == m_pObjectShell ) + { + SfxPrintingHint* pPrintHint = PTR_CAST( SfxPrintingHint, &rHint ); + if ( pPrintHint ) + { + if ( pPrintHint->GetWhich() == com::sun::star::view::PrintableState_JOB_STARTED ) + { + if ( !m_xPrintJob.is() ) + m_xPrintJob = new SfxPrintJob_Impl( this ); +/* + PrintDialog* pDlg = pPrintHint->GetPrintDialog(); + Printer* pPrinter = pPrintHint->GetPrinter(); + ::rtl::OUString aPrintFile ( ( pPrinter && pPrinter->IsPrintFileEnabled() ) ? pPrinter->GetPrintFile() : String() ); + ::rtl::OUString aRangeText ( ( pDlg && pDlg->IsRangeChecked(PRINTDIALOG_RANGE) ) ? pDlg->GetRangeText() : String() ); + sal_Bool bSelectionOnly = ( ( pDlg && pDlg->IsRangeChecked(PRINTDIALOG_SELECTION) ) ? sal_True : sal_False ); + + sal_Int32 nArgs = 2; + if ( aPrintFile.getLength() ) + nArgs++; + if ( aRangeText.getLength() ) + nArgs++; + else if ( bSelectionOnly ) + nArgs++; + + m_aPrintOptions.realloc(nArgs); + m_aPrintOptions[0].Name = DEFINE_CONST_UNICODE("CopyCount"); + m_aPrintOptions[0].Value <<= (sal_Int16) (pPrinter ? pPrinter->GetCopyCount() : 1 ); + m_aPrintOptions[1].Name = DEFINE_CONST_UNICODE("Collate"); + m_aPrintOptions[1].Value <<= (sal_Bool) (pDlg ? pDlg->IsCollateChecked() : sal_False ); + + if ( bSelectionOnly ) + { + m_aPrintOptions[2].Name = DEFINE_CONST_UNICODE("Selection"); + m_aPrintOptions[2].Value <<= bSelectionOnly; + } + else if ( aRangeText.getLength() ) + { + m_aPrintOptions[2].Name = DEFINE_CONST_UNICODE("Pages"); + m_aPrintOptions[2].Value <<= aRangeText; + } + + if ( aPrintFile.getLength() ) + { + m_aPrintOptions[nArgs-1].Name = DEFINE_CONST_UNICODE("FileName"); + m_aPrintOptions[nArgs-1].Value <<= aPrintFile; + } +*/ + m_aPrintOptions = pPrintHint->GetOptions(); + } +/* + else if ( pPrintHint->GetWhich() == -3 ) // -3 : AdditionalPrintOptions + { + uno::Sequence < beans::PropertyValue >& lOldOpts = m_aPrintOptions; + const uno::Sequence < beans::PropertyValue >& lNewOpts = pPrintHint->GetAdditionalOptions(); + sal_Int32 nOld = lOldOpts.getLength(); + sal_Int32 nAdd = lNewOpts.getLength(); + lOldOpts.realloc( nOld + nAdd ); + + // assume that all new elements are overwriting old ones and so don't need to be added + sal_Int32 nTotal = nOld; + for ( sal_Int32 n=0; n<nAdd; n++ ) + { + sal_Int32 m; + for ( m=0; m<nOld; m++ ) + if ( lNewOpts[n].Name == lOldOpts[m].Name ) + // new option overwrites old one + break; + + if ( m == nOld ) + { + // this is a new option, so add it to the resulting sequence - counter must be incremented + lOldOpts[nTotal].Name = lNewOpts[n].Name; + lOldOpts[nTotal++].Value = lNewOpts[n].Value; + } + else + // overwrite old option with new value, counter stays unmodified + lOldOpts[m].Value = lNewOpts[n].Value; + } + + if ( nTotal != lOldOpts.getLength() ) + // at least one new options has overwritten an old one, so we allocated too much + lOldOpts.realloc( nTotal ); + } +*/ + else if ( pPrintHint->GetWhich() != -2 ) // -2 : CancelPrintJob + { + view::PrintJobEvent aEvent; + aEvent.Source = m_xPrintJob; + aEvent.State = (com::sun::star::view::PrintableState) pPrintHint->GetWhich(); + ::cppu::OInterfaceContainerHelper* pContainer = m_aInterfaceContainer.getContainer( ::getCppuType( ( const uno::Reference< view::XPrintJobListener >*) NULL ) ); + if ( pContainer!=NULL ) + { + ::cppu::OInterfaceIteratorHelper pIterator(*pContainer); + while (pIterator.hasMoreElements()) + ((view::XPrintJobListener*)pIterator.next())->printJobEvent( aEvent ); + } + } + } + } +} + +void SAL_CALL SfxPrintHelper::addPrintJobListener( const ::com::sun::star::uno::Reference< ::com::sun::star::view::XPrintJobListener >& xListener ) throw (::com::sun::star::uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + m_pData->m_aInterfaceContainer.addInterface( ::getCppuType((const uno::Reference < view::XPrintJobListener>*)0), xListener ); +} + +void SAL_CALL SfxPrintHelper::removePrintJobListener( const ::com::sun::star::uno::Reference< ::com::sun::star::view::XPrintJobListener >& xListener ) throw (::com::sun::star::uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + m_pData->m_aInterfaceContainer.removeInterface( ::getCppuType((const uno::Reference < view::XPrintJobListener>*)0), xListener ); +} + + diff --git a/sfx2/source/doc/printhelper.hxx b/sfx2/source/doc/printhelper.hxx new file mode 100755 index 000000000000..9ba05fc20cee --- /dev/null +++ b/sfx2/source/doc/printhelper.hxx @@ -0,0 +1,69 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "sal/config.h" +#include "sfx2/dllapi.h" +#include "sal/types.h" + +#include <com/sun/star/view/XPrintable.hpp> +#include <com/sun/star/view/XPrintJobBroadcaster.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/lang/XInitialization.hpp> +#include <osl/mutex.hxx> +#include <cppuhelper/implbase3.hxx> + +struct IMPL_PrintListener_DataContainer; +class SfxViewShell; +class SfxPrinter; + +class SfxPrintHelper : public cppu::WeakImplHelper3 + < com::sun::star::view::XPrintable + , com::sun::star::view::XPrintJobBroadcaster + , com::sun::star::lang::XInitialization > +{ +public: + + SfxPrintHelper() ; + virtual ~SfxPrintHelper() ; + + void SAL_CALL initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addPrintJobListener( const ::com::sun::star::uno::Reference< ::com::sun::star::view::XPrintJobListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removePrintJobListener( const ::com::sun::star::uno::Reference< ::com::sun::star::view::XPrintJobListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + virtual com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > SAL_CALL getPrinter() throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setPrinter( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& seqPrinter ) + throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL print( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& seqOptions ) + throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + +private: + + osl::Mutex m_aMutex; + IMPL_PrintListener_DataContainer* m_pData ; + virtual void impl_setPrinter(const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& rPrinter,SfxPrinter*& pPrinter,sal_uInt16& nChangeFlags,SfxViewShell*& pViewSh); +} ; diff --git a/sfx2/source/doc/querytemplate.cxx b/sfx2/source/doc/querytemplate.cxx new file mode 100644 index 000000000000..8e006721351a --- /dev/null +++ b/sfx2/source/doc/querytemplate.cxx @@ -0,0 +1,52 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include "querytemplate.hxx" +#include "sfxresid.hxx" +#include "doc.hrc" + +#include <vcl/svapp.hxx> + +namespace sfx2 +{ + +QueryTemplateBox::QueryTemplateBox( Window* pParent, const String& rMessage ) : + MessBox ( pParent, 0, Application::GetDisplayName(), rMessage ) +{ + SetImage( QueryBox::GetStandardImage() ); + SetHelpId( MSG_QUERY_LOAD_TEMPLATE ); + + AddButton( String( SfxResId( STR_QRYTEMPL_UPDATE_BTN ) ), RET_YES, + BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_OKBUTTON | BUTTONDIALOG_FOCUSBUTTON ); + AddButton( String( SfxResId( STR_QRYTEMPL_KEEP_BTN ) ), RET_NO, BUTTONDIALOG_CANCELBUTTON ); +} + +} // end of namespace sfx2 + diff --git a/sfx2/source/doc/querytemplate.hxx b/sfx2/source/doc/querytemplate.hxx new file mode 100644 index 000000000000..92e9f26da0a7 --- /dev/null +++ b/sfx2/source/doc/querytemplate.hxx @@ -0,0 +1,44 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _SFX2_QUERYTEMPLATE_HXX +#define _SFX2_QUERYTEMPLATE_HXX + +#include <vcl/msgbox.hxx> + +namespace sfx2 +{ + + class QueryTemplateBox : public MessBox + { + public: + QueryTemplateBox( Window* pParent, const String& rMessage ); + }; + +} // end of namespace sfx2 + +#endif + diff --git a/sfx2/source/doc/sfxacldetect.cxx b/sfx2/source/doc/sfxacldetect.cxx new file mode 100644 index 000000000000..de6528794e20 --- /dev/null +++ b/sfx2/source/doc/sfxacldetect.cxx @@ -0,0 +1,105 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifdef WNT + +// necessary to include system headers without warnings +#ifdef _MSC_VER +#pragma warning(disable:4668 4917) +#endif + +#include <windows.h> +#include <lmaccess.h> +#include <sal/types.h> + +sal_Bool IsReadonlyAccordingACL( const sal_Unicode* pFilePath ) +{ + sal_Bool bResult = sal_False; + + sal_uInt32 nFDSize = 0; + GetFileSecurityW( reinterpret_cast< LPCWSTR >(pFilePath), DACL_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION, NULL, 0, &nFDSize ); + if ( nFDSize ) + { + PSECURITY_DESCRIPTOR pFileDescr = reinterpret_cast< PSECURITY_DESCRIPTOR >( malloc( nFDSize ) ); + if ( GetFileSecurityW( reinterpret_cast< LPCWSTR >(pFilePath), DACL_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION, pFileDescr, nFDSize, &nFDSize ) ) + { + HANDLE hToken = NULL; + if ( OpenThreadToken( GetCurrentThread(), TOKEN_DUPLICATE|TOKEN_QUERY, TRUE, &hToken ) + || OpenProcessToken( GetCurrentProcess(), TOKEN_DUPLICATE|TOKEN_QUERY, &hToken) ) + { + HANDLE hImpersonationToken = NULL; + if ( DuplicateToken( hToken, SecurityImpersonation, &hImpersonationToken) ) + { + sal_uInt32 nDesiredAccess = ACCESS_WRITE; + GENERIC_MAPPING aGenericMapping = { ACCESS_READ, ACCESS_WRITE, 0, ACCESS_READ | ACCESS_WRITE }; + MapGenericMask( &nDesiredAccess, &aGenericMapping ); + + PRIVILEGE_SET aPrivilegeSet; + sal_uInt32 nPrivilegeSetSize = sizeof( PRIVILEGE_SET ); + + sal_uInt32 nGrantedAccess; + BOOL bAccessible = TRUE; + if ( AccessCheck( pFileDescr, + hImpersonationToken, + nDesiredAccess, + &aGenericMapping, + &aPrivilegeSet, + &nPrivilegeSetSize, + &nGrantedAccess, + &bAccessible ) ) + { + bResult = !bAccessible; + } + + CloseHandle( hImpersonationToken ); + } + + CloseHandle( hToken ); + } + } + + free( pFileDescr ); + } + + return bResult; +} + +#else // this is UNX +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + + +#include <sal/types.h> + +sal_Bool IsReadonlyAccordingACL( const sal_Unicode* ) +{ + // to be implemented + return sal_False; +} + +#endif + diff --git a/sfx2/source/doc/sfxbasemodel.cxx b/sfx2/source/doc/sfxbasemodel.cxx new file mode 100644 index 000000000000..846cc669b9a7 --- /dev/null +++ b/sfx2/source/doc/sfxbasemodel.cxx @@ -0,0 +1,4309 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +//________________________________________________________________________________________________________ +// my own includes +//________________________________________________________________________________________________________ + +#include <sfx2/sfxbasemodel.hxx> + +//________________________________________________________________________________________________________ +// include of other projects +//________________________________________________________________________________________________________ + +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/task/ErrorCodeRequest.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/view/XPrintJobListener.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/frame/IllegalArgumentIOException.hpp> +#include <com/sun/star/frame/XUntitledNumbers.hpp> +#include <com/sun/star/frame/UntitledNumbersConst.hpp> +#include <com/sun/star/embed/XTransactionBroadcaster.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/embed/EmbedMapUnits.hpp> +#include <com/sun/star/document/XStorageChangeListener.hpp> +#include <com/sun/star/document/XActionLockable.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/script/provider/XScriptProviderFactory.hpp> +#include <com/sun/star/script/provider/XScriptProvider.hpp> +#include <com/sun/star/ui/XUIConfigurationStorage.hpp> +#include <com/sun/star/ui/XUIConfigurationPersistence.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/Aspects.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/frame/XTransientDocumentsDocumentContentFactory.hpp> +#include <comphelper/enumhelper.hxx> // can be removed when this is a "real" service + +#include <cppuhelper/interfacecontainer.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <comphelper/processfactory.hxx> // can be removed when this is a "real" service +#include <comphelper/componentcontext.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <svl/itemset.hxx> +#include <svl/stritem.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <basic/sbx.hxx> +#include <basic/sbuno.hxx> +#include <tools/urlobj.hxx> +#include <tools/diagnose_ex.h> +#include <unotools/tempfile.hxx> +#include <vos/mutex.hxx> +#include <vcl/salctype.hxx> +#include <sot/clsids.hxx> +#include <sot/storinfo.hxx> +#include <comphelper/storagehelper.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <svtools/transfer.hxx> +#include <svtools/ehdl.hxx> +#include <svtools/sfxecode.hxx> +#include <rtl/logfile.hxx> +#include <framework/configimporter.hxx> +#include <framework/interaction.hxx> +#include <framework/titlehelper.hxx> +#include <comphelper/numberedcollection.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <unotools/ucbhelper.hxx> + +//________________________________________________________________________________________________________ +// includes of my own project +//________________________________________________________________________________________________________ + +#include <sfx2/sfxbasecontroller.hxx> +#include "viewfac.hxx" +#include "workwin.hxx" +#include <sfx2/signaturestate.hxx> +#include <sfx2/sfxuno.hxx> +#include <objshimp.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/request.hxx> +#include <sfx2/objuno.hxx> +#include <sfx2/printer.hxx> +#include <basmgr.hxx> +#include <sfx2/event.hxx> +#include <eventsupplier.hxx> +#include <sfx2/evntconf.hxx> +#include <sfx2/sfx.hrc> +#include <sfx2/app.hxx> +#include <sfx2/viewfrm.hxx> +#include "appdata.hxx" +#include <sfx2/docfac.hxx> +#include <sfx2/fcontnr.hxx> +#include "sfx2/docstoragemodifylistener.hxx" +#include "brokenpackageint.hxx" +#include "graphhelp.hxx" +#include <sfx2/msgpool.hxx> +#include <sfx2/DocumentMetadataAccess.hxx> + +#include <sfxresid.hxx> + +//________________________________________________________________________________________________________ +// const +static const ::rtl::OUString SERVICENAME_DESKTOP = ::rtl::OUString::createFromAscii ("com.sun.star.frame.Desktop"); + +//________________________________________________________________________________________________________ +// namespaces +//________________________________________________________________________________________________________ + +namespace css = ::com::sun::star; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::frame::XFrame; +using ::com::sun::star::frame::XController; +using ::com::sun::star::frame::XController2; +using ::com::sun::star::lang::IllegalArgumentException; +using ::com::sun::star::io::IOException; +using ::com::sun::star::lang::WrappedTargetException; +using ::com::sun::star::uno::Type; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::document::XDocumentRecovery; + +/** This Listener is used to get notified when the XDocumentProperties of the + XModel change. + */ +class SfxDocInfoListener_Impl : public ::cppu::WeakImplHelper1< + ::com::sun::star::util::XModifyListener > +{ + +public: + SfxObjectShell& m_rShell; + + SfxDocInfoListener_Impl( SfxObjectShell& i_rDoc ) + : m_rShell(i_rDoc) + { }; + + ~SfxDocInfoListener_Impl(); + + virtual void SAL_CALL disposing( const lang::EventObject& ) + throw ( uno::RuntimeException ); + virtual void SAL_CALL modified( const lang::EventObject& ) + throw ( uno::RuntimeException ); +}; +SfxDocInfoListener_Impl::~SfxDocInfoListener_Impl() +{ +} +void SAL_CALL SfxDocInfoListener_Impl::modified( const lang::EventObject& ) + throw ( uno::RuntimeException ) +{ + ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + + // notify changes to the SfxObjectShell + m_rShell.FlushDocInfo(); +} + +void SAL_CALL SfxDocInfoListener_Impl::disposing( const lang::EventObject& ) + throw ( uno::RuntimeException ) +{ +} + +//________________________________________________________________________________________________________ +// impl. declarations +//________________________________________________________________________________________________________ + + +struct IMPL_SfxBaseModel_DataContainer : public ::sfx2::IModifiableDocument +{ + // counter for SfxBaseModel instances created. + static sal_Int64 g_nInstanceCounter ; + SfxObjectShellRef m_pObjectShell ; + ::rtl::OUString m_sURL ; + ::rtl::OUString m_sRuntimeUID ; + ::rtl::OUString m_aPreusedFilterName; + ::cppu::OMultiTypeInterfaceContainerHelper m_aInterfaceContainer ; + uno::Reference< uno::XInterface > m_xParent ; + uno::Reference< frame::XController > m_xCurrent ; + uno::Reference< document::XDocumentInfo > m_xDocumentInfo ; + uno::Reference< document::XDocumentProperties > m_xDocumentProperties; + uno::Reference< script::XStarBasicAccess > m_xStarBasicAccess ; + uno::Reference< container::XNameReplace > m_xEvents ; + uno::Sequence< beans::PropertyValue> m_seqArguments ; + uno::Sequence< uno::Reference< frame::XController > > m_seqControllers ; + uno::Reference< container::XIndexAccess > m_contViewData ; + sal_uInt16 m_nControllerLockCount ; + sal_Bool m_bClosed ; + sal_Bool m_bClosing ; + sal_Bool m_bSaving ; + sal_Bool m_bSuicide ; + sal_Bool m_bInitialized ; + sal_Bool m_bModifiedSinceLastSave; + uno::Reference< com::sun::star::view::XPrintable> m_xPrintable ; + uno::Reference< script::provider::XScriptProvider > m_xScriptProvider; + uno::Reference< ui::XUIConfigurationManager > m_xUIConfigurationManager; + ::rtl::Reference< ::sfx2::DocumentStorageModifyListener > m_pStorageModifyListen; + ::rtl::OUString m_sModuleIdentifier; + css::uno::Reference< css::frame::XTitle > m_xTitleHelper; + css::uno::Reference< css::frame::XUntitledNumbers > m_xNumberedControllers; + uno::Reference< rdf::XDocumentMetadataAccess> m_xDocumentMetadata; + + + IMPL_SfxBaseModel_DataContainer( ::osl::Mutex& rMutex, SfxObjectShell* pObjectShell ) + : m_pObjectShell ( pObjectShell ) + , m_aInterfaceContainer ( rMutex ) + , m_nControllerLockCount ( 0 ) + , m_bClosed ( sal_False ) + , m_bClosing ( sal_False ) + , m_bSaving ( sal_False ) + , m_bSuicide ( sal_False ) + , m_bInitialized ( sal_False ) + , m_bModifiedSinceLastSave( sal_False ) + , m_pStorageModifyListen ( NULL ) + , m_xTitleHelper () + , m_xNumberedControllers () + , m_xDocumentMetadata () // lazy + { + // increase global instance counter. + ++g_nInstanceCounter; + // set own Runtime UID + m_sRuntimeUID = rtl::OUString::valueOf( g_nInstanceCounter ); + } + + virtual ~IMPL_SfxBaseModel_DataContainer() + { + } + + // ::sfx2::IModifiableDocument + virtual void storageIsModified() + { + if ( m_pObjectShell.Is() && !m_pObjectShell->IsModified() ) + m_pObjectShell->SetModified( sal_True ); + } + + uno::Reference<rdf::XDocumentMetadataAccess> GetDMA() + { + if (!m_xDocumentMetadata.is()) + { + OSL_ENSURE(m_pObjectShell, "GetDMA: no object shell?"); + if (!m_pObjectShell) + { + return 0; + } + + const uno::Reference<uno::XComponentContext> xContext( + ::comphelper::getProcessComponentContext()); + ::rtl::OUString uri; + const uno::Reference<frame::XModel> xModel( + m_pObjectShell->GetModel()); + const uno::Reference<lang::XMultiComponentFactory> xMsf( + xContext->getServiceManager()); + const uno::Reference<frame:: + XTransientDocumentsDocumentContentFactory> xTDDCF( + xMsf->createInstanceWithContext( + ::rtl::OUString::createFromAscii( "com.sun.star.frame." + "TransientDocumentsDocumentContentFactory"), + xContext), + uno::UNO_QUERY_THROW); + const uno::Reference<ucb::XContent> xContent( + xTDDCF->createDocumentContent(xModel) ); + OSL_ENSURE(xContent.is(), "GetDMA: cannot create DocumentContent"); + if (!xContent.is()) + { + return 0; + } + uri = xContent->getIdentifier()->getContentIdentifier(); + OSL_ENSURE(uri.getLength(), "GetDMA: empty uri?"); + if (uri.getLength() && !uri.endsWithAsciiL("/", 1)) + { + uri = uri + ::rtl::OUString::createFromAscii("/"); + } + + m_xDocumentMetadata = new ::sfx2::DocumentMetadataAccess( + xContext, *m_pObjectShell, uri); + } + return m_xDocumentMetadata; + } + + uno::Reference<rdf::XDocumentMetadataAccess> CreateDMAUninitialized() + { + return (m_pObjectShell) + ? new ::sfx2::DocumentMetadataAccess( + ::comphelper::getProcessComponentContext(), *m_pObjectShell) + : 0; + } +}; + +// static member initialization. +sal_Int64 IMPL_SfxBaseModel_DataContainer::g_nInstanceCounter = 0; + +// ======================================================================================================= + +// Listener that forwards notifications from the PrintHelper to the "real" listeners +class SfxPrintHelperListener_Impl : public ::cppu::WeakImplHelper1< ::com::sun::star::view::XPrintJobListener > +{ +public: + IMPL_SfxBaseModel_DataContainer* m_pData; + SfxPrintHelperListener_Impl( IMPL_SfxBaseModel_DataContainer* pData ) + : m_pData( pData ) + {} + + virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) throw ( uno::RuntimeException ) ; + virtual void SAL_CALL printJobEvent( const view::PrintJobEvent& rEvent ) throw ( uno::RuntimeException); +}; + +void SAL_CALL SfxPrintHelperListener_Impl::disposing( const lang::EventObject& ) throw ( uno::RuntimeException ) +{ + m_pData->m_xPrintable = 0; +} + +void SAL_CALL SfxPrintHelperListener_Impl::printJobEvent( const view::PrintJobEvent& rEvent ) throw (uno::RuntimeException) +{ + ::cppu::OInterfaceContainerHelper* pContainer = m_pData->m_aInterfaceContainer.getContainer( ::getCppuType( ( const uno::Reference< view::XPrintJobListener >*) NULL ) ); + if ( pContainer!=NULL ) + { + ::cppu::OInterfaceIteratorHelper pIterator(*pContainer); + while (pIterator.hasMoreElements()) + ((view::XPrintJobListener*)pIterator.next())->printJobEvent( rEvent ); + } +} + +// SfxOwnFramesLocker ==================================================================================== +// allows to lock all the frames related to the provided SfxObjectShell +class SfxOwnFramesLocker +{ + uno::Sequence< uno::Reference< frame::XFrame > > m_aLockedFrames; + + Window* GetVCLWindow( const uno::Reference< frame::XFrame >& xFrame ); +public: + SfxOwnFramesLocker( SfxObjectShell* ObjechShell ); + ~SfxOwnFramesLocker(); + void UnlockFrames(); +}; + +SfxOwnFramesLocker::SfxOwnFramesLocker( SfxObjectShell* pObjectShell ) +{ + if ( !pObjectShell ) + return; + + for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst( pObjectShell ); + pFrame; + pFrame = SfxViewFrame::GetNext( *pFrame, pObjectShell ) + ) + { + SfxFrame& rSfxFrame = pFrame->GetFrame(); + try + { + // get vcl window related to the frame and lock it if it is still not locked + uno::Reference< frame::XFrame > xFrame = rSfxFrame.GetFrameInterface(); + Window* pWindow = GetVCLWindow( xFrame ); + if ( !pWindow ) + throw uno::RuntimeException(); + + if ( pWindow->IsEnabled() ) + { + pWindow->Disable(); + + try + { + sal_Int32 nLen = m_aLockedFrames.getLength(); + m_aLockedFrames.realloc( nLen + 1 ); + m_aLockedFrames[nLen] = xFrame; + } + catch( uno::Exception& ) + { + pWindow->Enable(); + throw; + } + } + } + catch( uno::Exception& ) + { + OSL_ENSURE( sal_False, "Not possible to lock the frame window!\n" ); + } + } +} + +SfxOwnFramesLocker::~SfxOwnFramesLocker() +{ + UnlockFrames(); +} + +Window* SfxOwnFramesLocker::GetVCLWindow( const uno::Reference< frame::XFrame >& xFrame ) +{ + Window* pWindow = NULL; + + if ( xFrame.is() ) + { + uno::Reference< awt::XWindow > xWindow = xFrame->getContainerWindow(); + if ( xWindow.is() ) + pWindow = VCLUnoHelper::GetWindow( xWindow ); + } + + return pWindow; +} + +void SfxOwnFramesLocker::UnlockFrames() +{ + for ( sal_Int32 nInd = 0; nInd < m_aLockedFrames.getLength(); nInd++ ) + { + try + { + if ( m_aLockedFrames[nInd].is() ) + { + // get vcl window related to the frame and unlock it + Window* pWindow = GetVCLWindow( m_aLockedFrames[nInd] ); + if ( !pWindow ) + throw uno::RuntimeException(); + + pWindow->Enable(); + + m_aLockedFrames[nInd] = uno::Reference< frame::XFrame >(); + } + } + catch( uno::Exception& ) + { + OSL_ENSURE( sal_False, "Can't unlock the frame window!\n" ); + } + } +} + +// SfxSaveGuard ==================================================================================== +class SfxSaveGuard +{ + private: + uno::Reference< frame::XModel > m_xModel; + IMPL_SfxBaseModel_DataContainer* m_pData; + SfxOwnFramesLocker* m_pFramesLock; + + public: + SfxSaveGuard(const uno::Reference< frame::XModel >& xModel , + IMPL_SfxBaseModel_DataContainer* pData , + sal_Bool bRejectConcurrentSaveRequest); + ~SfxSaveGuard(); +}; + +SfxSaveGuard::SfxSaveGuard(const uno::Reference< frame::XModel >& xModel , + IMPL_SfxBaseModel_DataContainer* pData , + sal_Bool bRejectConcurrentSaveRequest) + : m_xModel (xModel) + , m_pData (pData ) + , m_pFramesLock(0 ) +{ + static ::rtl::OUString MSG_1 = ::rtl::OUString::createFromAscii("Object already disposed." ); + static ::rtl::OUString MSG_2 = ::rtl::OUString::createFromAscii("Concurrent save requests on the same document are not possible."); + + if ( m_pData->m_bClosed ) + throw ::com::sun::star::lang::DisposedException( + MSG_1, + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >()); + + if ( + bRejectConcurrentSaveRequest && + m_pData->m_bSaving + ) + throw ::com::sun::star::io::IOException( + MSG_2, + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >()); + + m_pData->m_bSaving = sal_True; + m_pFramesLock = new SfxOwnFramesLocker(m_pData->m_pObjectShell); +} + +SfxSaveGuard::~SfxSaveGuard() +{ + SfxOwnFramesLocker* pFramesLock = m_pFramesLock; + m_pFramesLock = 0; + delete pFramesLock; + + m_pData->m_bSaving = sal_False; + + // m_bSuicide was set e.g. in case somewhere tried to close a document, while it was used for + // storing at the same time. Further m_bSuicide was set to TRUE only if close(TRUE) was called. + // So the owner ship was delegated to the place where a veto exception was thrown. + // Now we have to call close() again and delegate the owner ship to the next one, which + // cant accept that. Close(FALSE) cant work in this case. Because then the document will may be never closed ... + + if ( m_pData->m_bSuicide ) + { + // Reset this state. In case the new close() request is not accepted by somehwere else ... + // it's not a good idea to have two "owners" for close .-) + m_pData->m_bSuicide = sal_False; + try + { + uno::Reference< util::XCloseable > xClose(m_xModel, uno::UNO_QUERY); + if (xClose.is()) + xClose->close(sal_True); + } + catch(const util::CloseVetoException&) + {} + } +} + +// ======================================================================================================= + +//________________________________________________________________________________________________________ +// constructor +//________________________________________________________________________________________________________ +DBG_NAME(sfx2_SfxBaseModel) +SfxBaseModel::SfxBaseModel( SfxObjectShell *pObjectShell ) +: BaseMutex() +, m_pData( new IMPL_SfxBaseModel_DataContainer( m_aMutex, pObjectShell ) ) +, m_bSupportEmbeddedScripts( pObjectShell && pObjectShell->Get_Impl() ? !pObjectShell->Get_Impl()->m_bNoBasicCapabilities : false ) +, m_bSupportDocRecovery( pObjectShell && pObjectShell->Get_Impl() ? pObjectShell->Get_Impl()->m_bDocRecoverySupport : false ) +{ + DBG_CTOR(sfx2_SfxBaseModel,NULL); + if ( pObjectShell != NULL ) + { + StartListening( *pObjectShell ) ; + } +} + +//________________________________________________________________________________________________________ +// destructor +//________________________________________________________________________________________________________ + +SfxBaseModel::~SfxBaseModel() +{ + DBG_DTOR(sfx2_SfxBaseModel,NULL); +} + +//________________________________________________________________________________________________________ +// XInterface +//________________________________________________________________________________________________________ + +uno::Any SAL_CALL SfxBaseModel::queryInterface( const UNOTYPE& rType ) throw( uno::RuntimeException ) +{ + if ( ( !m_bSupportEmbeddedScripts && rType.equals( XEMBEDDEDSCRIPTS::static_type() ) ) + || ( !m_bSupportDocRecovery && rType.equals( XDocumentRecovery::static_type() ) ) + ) + return Any(); + + return SfxBaseModel_Base::queryInterface( rType ); +} + +//________________________________________________________________________________________________________ +// XInterface +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::acquire() throw( ) +{ + // Attention: + // Don't use mutex or guard in this method!!! Is a method of XInterface. + + // Forward to baseclass + OWeakObject::acquire() ; +} + +//________________________________________________________________________________________________________ +// XInterface +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::release() throw( ) +{ + // Attention: + // Don't use mutex or guard in this method!!! Is a method of XInterface. + + // Forward to baseclass + OWeakObject::release() ; +} + +//________________________________________________________________________________________________________ +// XTypeProvider +//________________________________________________________________________________________________________ + +namespace +{ + void lcl_stripType( Sequence< Type >& io_rTypes, const Type& i_rTypeToStrip ) + { + Sequence< UNOTYPE > aStrippedTypes( io_rTypes.getLength() - 1 ); + ::std::remove_copy_if( + io_rTypes.getConstArray(), + io_rTypes.getConstArray() + io_rTypes.getLength(), + aStrippedTypes.getArray(), + ::std::bind2nd( ::std::equal_to< Type >(), i_rTypeToStrip ) + ); + io_rTypes = aStrippedTypes; + } +} + +uno::Sequence< UNOTYPE > SAL_CALL SfxBaseModel::getTypes() throw( uno::RuntimeException ) +{ + uno::Sequence< UNOTYPE > aTypes( SfxBaseModel_Base::getTypes() ); + + if ( !m_bSupportEmbeddedScripts ) + lcl_stripType( aTypes, XEMBEDDEDSCRIPTS::static_type() ); + + if ( !m_bSupportDocRecovery ) + lcl_stripType( aTypes, XDocumentRecovery::static_type() ); + + return aTypes; +} + +//________________________________________________________________________________________________________ +// XTypeProvider +//________________________________________________________________________________________________________ + +uno::Sequence< sal_Int8 > SAL_CALL SfxBaseModel::getImplementationId() throw( uno::RuntimeException ) +{ + // Create one Id for all instances of this class. + // Use ethernet address to do this! (sal_True) + + // Optimize this method + // We initialize a static variable only one time. And we don't must use a mutex at every call! + // For the first call; pID is NULL - for the second call pID is different from NULL! + static ::cppu::OImplementationId* pID = NULL ; + + if ( pID == NULL ) + { + // Ready for multithreading; get global mutex for first call of this method only! see before + ::osl::MutexGuard aGuard( MUTEX::getGlobalMutex() ) ; + + // Control these pointer again ... it can be, that another instance will be faster then these! + if ( pID == NULL ) + { + // Create a new static ID ... + static ::cppu::OImplementationId aID( sal_False ) ; + // ... and set his address to static pointer! + pID = &aID ; + } + } + + return pID->getImplementationId() ; +} + +//________________________________________________________________________________________________________ +// XStarBasicAccess +//________________________________________________________________________________________________________ + +uno::Reference< script::XStarBasicAccess > implGetStarBasicAccess( SfxObjectShell* pObjectShell ) +{ + uno::Reference< script::XStarBasicAccess > xRet; + if( pObjectShell ) + { + BasicManager* pMgr = pObjectShell->GetBasicManager(); + xRet = getStarBasicAccess( pMgr ); + } + return xRet; +} + +uno::Reference< XNAMECONTAINER > SAL_CALL SfxBaseModel::getLibraryContainer() throw( uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + + uno::Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess; + if( !rxAccess.is() && m_pData->m_pObjectShell.Is() ) + rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell ); + + uno::Reference< XNAMECONTAINER > xRet; + if( rxAccess.is() ) + xRet = rxAccess->getLibraryContainer(); + return xRet; +} + +/**___________________________________________________________________________________________________ + @seealso XStarBasicAccess +*/ +void SAL_CALL SfxBaseModel::createLibrary( const ::rtl::OUString& LibName, const ::rtl::OUString& Password, + const ::rtl::OUString& ExternalSourceURL, const ::rtl::OUString& LinkTargetURL ) + throw(ELEMENTEXISTEXCEPTION, uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + uno::Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess; + if( !rxAccess.is() && m_pData->m_pObjectShell.Is() ) + rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell ); + + if( rxAccess.is() ) + rxAccess->createLibrary( LibName, Password, ExternalSourceURL, LinkTargetURL ); +} + +/**___________________________________________________________________________________________________ + @seealso XStarBasicAccess +*/ +void SAL_CALL SfxBaseModel::addModule( const ::rtl::OUString& LibraryName, const ::rtl::OUString& ModuleName, + const ::rtl::OUString& Language, const ::rtl::OUString& Source ) + throw( NOSUCHELEMENTEXCEPTION, uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + uno::Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess; + if( !rxAccess.is() && m_pData->m_pObjectShell.Is() ) + rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell ); + + if( rxAccess.is() ) + rxAccess->addModule( LibraryName, ModuleName, Language, Source ); +} + +/**___________________________________________________________________________________________________ + @seealso XStarBasicAccess +*/ +void SAL_CALL SfxBaseModel::addDialog( const ::rtl::OUString& LibraryName, const ::rtl::OUString& DialogName, + const ::com::sun::star::uno::Sequence< sal_Int8 >& Data ) + throw(NOSUCHELEMENTEXCEPTION, uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + uno::Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess; + if( !rxAccess.is() && m_pData->m_pObjectShell.Is() ) + rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell ); + + if( rxAccess.is() ) + rxAccess->addDialog( LibraryName, DialogName, Data ); +} + + +//________________________________________________________________________________________________________ +// XChild +//________________________________________________________________________________________________________ + +uno::Reference< uno::XInterface > SAL_CALL SfxBaseModel::getParent() throw( uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + + return m_pData->m_xParent; +} + +//________________________________________________________________________________________________________ +// XChild +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::setParent(const uno::Reference< uno::XInterface >& Parent) throw(NOSUPPORTEXCEPTION, uno::RuntimeException) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + m_pData->m_xParent = Parent; +} + +//________________________________________________________________________________________________________ +// XChild +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::dispose() throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + + if ( !m_pData->m_bClosed ) + { + // gracefully accept wrong dispose calls instead of close call + // and try to make it work (may be really disposed later!) + try + { + close( sal_True ); + } + catch ( com::sun::star::util::CloseVetoException& ) + { + } + + return; + } + + if ( m_pData->m_pStorageModifyListen.is() ) + { + m_pData->m_pStorageModifyListen->dispose(); + m_pData->m_pStorageModifyListen = NULL; + } + + lang::EventObject aEvent( (frame::XModel *)this ); + m_pData->m_aInterfaceContainer.disposeAndClear( aEvent ); + + if ( m_pData->m_xDocumentInfo.is() ) + { + // as long as an SfxObjectShell is assigned to an SfxBaseModel it is still existing here + // so we can't dispose the shared DocumentInfoObject here + // uno::Reference < lang::XComponent > xComp( m_pData->m_xDocumentInfo, uno::UNO_QUERY ); + // xComp->dispose(); + m_pData->m_xDocumentInfo = 0; + } + + m_pData->m_xDocumentProperties.clear(); + + m_pData->m_xDocumentMetadata.clear(); + + EndListening( *m_pData->m_pObjectShell ); + + m_pData->m_xCurrent = uno::Reference< frame::XController > (); + m_pData->m_seqControllers = uno::Sequence< uno::Reference< frame::XController > > () ; + + // m_pData member must be set to zero before 0delete is called to + // force disposed exception whenever someone tries to access our + // instance while in the dtor. + IMPL_SfxBaseModel_DataContainer* pData = m_pData; + m_pData = 0; + delete pData; +} + +//________________________________________________________________________________________________________ +// XChild +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::addEventListener( const uno::Reference< XEVENTLISTENER >& aListener ) + throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + m_pData->m_aInterfaceContainer.addInterface( ::getCppuType((const uno::Reference< XEVENTLISTENER >*)0), aListener ); +} + +//________________________________________________________________________________________________________ +// XChild +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::removeEventListener( const uno::Reference< XEVENTLISTENER >& aListener ) + throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + m_pData->m_aInterfaceContainer.removeInterface( ::getCppuType((const uno::Reference< XEVENTLISTENER >*)0), aListener ); +} + +//________________________________________________________________________________________________________ +// document::XDocumentInfoSupplier +//________________________________________________________________________________________________________ + +uno::Reference< document::XDocumentInfo > SAL_CALL SfxBaseModel::getDocumentInfo() throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + if ( !m_pData->m_xDocumentInfo.is() ) + { + // WARNING: this will only work if (when loading a document) the + // document meta-data has already been read and completely written + // into the XDocumentProperties at this point + // ==> DO NOT call getDocumentInfo before document info has been read! + uno::Reference< document::XDocumentInfo > xDocInfo = + new SfxDocumentInfoObject; + uno::Reference< document::XDocumentProperties > xDocProps = + getDocumentProperties(); + uno::Sequence< uno::Any > args(1); + args[0] <<= xDocProps; + uno::Reference< lang::XInitialization > xInit( + xDocInfo, uno::UNO_QUERY_THROW); + try { + xInit->initialize(args); + ((SfxBaseModel*)this)->m_pData->m_xDocumentInfo = xDocInfo; + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException(::rtl::OUString::createFromAscii( + "SfxBaseModel::getDocumentInfo: cannot initialize"), *this, + uno::makeAny(e)); + } + try { + rtl::OUString aName = rtl::OUString::createFromAscii("MediaType"); + uno::Reference < beans::XPropertySet > xSet( + getDocumentStorage(), uno::UNO_QUERY ); + uno::Any aMediaType = xSet->getPropertyValue( aName ); + uno::Reference < beans::XPropertySet > xDocSet( + m_pData->m_xDocumentInfo, uno::UNO_QUERY ); + xDocSet->setPropertyValue( aName, aMediaType ); + } catch (uno::Exception &) { + //ignore + } + } + + return m_pData->m_xDocumentInfo; +} + +// document::XDocumentPropertiesSupplier: +uno::Reference< document::XDocumentProperties > SAL_CALL +SfxBaseModel::getDocumentProperties() + throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + if ( !m_pData->m_xDocumentProperties.is() ) + { + uno::Reference< lang::XInitialization > xDocProps( + ::comphelper::getProcessServiceFactory()->createInstance( + DEFINE_CONST_UNICODE("com.sun.star.document.DocumentProperties") ), + uno::UNO_QUERY_THROW); +// xDocProps->initialize(uno::Sequence<uno::Any>()); + m_pData->m_xDocumentProperties.set(xDocProps, uno::UNO_QUERY_THROW); + uno::Reference<util::XModifyBroadcaster> xMB(m_pData->m_xDocumentProperties, uno::UNO_QUERY_THROW); + xMB->addModifyListener(new SfxDocInfoListener_Impl(*m_pData->m_pObjectShell)); + } + + return m_pData->m_xDocumentProperties; +} + + +//________________________________________________________________________________________________________ +// XEVENTLISTENER +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::disposing( const lang::EventObject& aObject ) + throw(::com::sun::star::uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + return; + + uno::Reference< XMODIFYLISTENER > xMod( aObject.Source, uno::UNO_QUERY ); + uno::Reference< XEVENTLISTENER > xListener( aObject.Source, uno::UNO_QUERY ); + uno::Reference< XDOCEVENTLISTENER > xDocListener( aObject.Source, uno::UNO_QUERY ); + + if ( xMod.is() ) + m_pData->m_aInterfaceContainer.removeInterface( ::getCppuType((const uno::Reference< XMODIFYLISTENER >*)0), xMod ); + else if ( xListener.is() ) + m_pData->m_aInterfaceContainer.removeInterface( ::getCppuType((const uno::Reference< XEVENTLISTENER >*)0), xListener ); + else if ( xDocListener.is() ) + m_pData->m_aInterfaceContainer.removeInterface( ::getCppuType((const uno::Reference< XDOCEVENTLISTENER >*)0), xListener ); +} + +//________________________________________________________________________________________________________ +// frame::XModel +//________________________________________________________________________________________________________ + +sal_Bool SAL_CALL SfxBaseModel::attachResource( const ::rtl::OUString& rURL , + const uno::Sequence< beans::PropertyValue >& rArgs ) + throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + if ( rURL.getLength() == 0 && rArgs.getLength() == 1 && rArgs[0].Name.equalsAscii( "SetEmbedded" ) ) + { + // allows to set a windowless document to EMBEDDED state + // but _only_ before load() or initNew() methods + if ( m_pData->m_pObjectShell.Is() && !m_pData->m_pObjectShell->GetMedium() ) + { + sal_Bool bEmb = sal_Bool(); + if ( ( rArgs[0].Value >>= bEmb ) && bEmb ) + m_pData->m_pObjectShell->SetCreateMode_Impl( SFX_CREATE_MODE_EMBEDDED ); + } + + return sal_True; + } + + if ( m_pData->m_pObjectShell.Is() ) + { + m_pData->m_sURL = rURL; + + SfxObjectShell* pObjectShell = m_pData->m_pObjectShell; + + ::comphelper::NamedValueCollection aArgs( rArgs ); + + Sequence< sal_Int32 > aWinExtent; + if ( ( aArgs.get( "WinExtent" ) >>= aWinExtent )&& ( aWinExtent.getLength() == 4 ) ) + { + Rectangle aVisArea( aWinExtent[0], aWinExtent[1], aWinExtent[2], aWinExtent[3] ); + aVisArea = OutputDevice::LogicToLogic( aVisArea, MAP_100TH_MM, pObjectShell->GetMapUnit() ); + pObjectShell->SetVisArea( aVisArea ); + } + + sal_Bool bBreakMacroSign = sal_False; + if ( aArgs.get( "BreakMacroSignature" ) >>= bBreakMacroSign ) + { + pObjectShell->BreakMacroSign_Impl( bBreakMacroSign ); + } + + aArgs.remove( "WinExtent" ); + aArgs.remove( "BreakMacroSignature" ); + aArgs.remove( "Stream" ); + aArgs.remove( "InputStream" ); + aArgs.remove( "URL" ); + aArgs.remove( "Frame" ); + + // TODO/LATER: all the parameters that are accepted by ItemSet of the DocShell must be removed here + + m_pData->m_seqArguments = aArgs.getPropertyValues(); + + SfxMedium* pMedium = pObjectShell->GetMedium(); + if ( pMedium ) + { + SfxAllItemSet aSet( pObjectShell->GetPool() ); + TransformParameters( SID_OPENDOC, rArgs, aSet ); + + // the arguments are not allowed to reach the medium + aSet.ClearItem( SID_FILE_NAME ); + aSet.ClearItem( SID_FILLFRAME ); + + pMedium->GetItemSet()->Put( aSet ); + SFX_ITEMSET_ARG( &aSet, pItem, SfxStringItem, SID_FILTER_NAME, sal_False ); + if ( pItem ) + pMedium->SetFilter( + pObjectShell->GetFactory().GetFilterContainer()->GetFilter4FilterName( pItem->GetValue() ) ); + + SFX_ITEMSET_ARG( &aSet, pTitleItem, SfxStringItem, SID_DOCINFO_TITLE, sal_False ); + if ( pTitleItem ) + { + SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pObjectShell ); + if ( pFrame ) + pFrame->UpdateTitle(); + } + } + } + + return sal_True ; +} + +//________________________________________________________________________________________________________ +// frame::XModel +//________________________________________________________________________________________________________ + +::rtl::OUString SAL_CALL SfxBaseModel::getURL() throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + return m_pData->m_sURL ; +} + +//________________________________________________________________________________________________________ +// frame::XModel +//________________________________________________________________________________________________________ + +uno::Sequence< beans::PropertyValue > SAL_CALL SfxBaseModel::getArgs() throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + if ( m_pData->m_pObjectShell.Is() ) + { + uno::Sequence< beans::PropertyValue > seqArgsNew; + uno::Sequence< beans::PropertyValue > seqArgsOld; + SfxAllItemSet aSet( m_pData->m_pObjectShell->GetPool() ); + + // we need to know which properties are supported by the transformer + // hopefully it is a temporary solution, I guess nonconvertable properties + // should not be supported so then there will be only ItemSet from medium + + TransformItems( SID_OPENDOC, *(m_pData->m_pObjectShell->GetMedium()->GetItemSet()), seqArgsNew ); + TransformParameters( SID_OPENDOC, m_pData->m_seqArguments, aSet ); + TransformItems( SID_OPENDOC, aSet, seqArgsOld ); + + sal_Int32 nOrgLength = m_pData->m_seqArguments.getLength(); + sal_Int32 nOldLength = seqArgsOld.getLength(); + sal_Int32 nNewLength = seqArgsNew.getLength(); + + // "WinExtent" property should be updated always. + // We can store it now to overwrite an old value + // since it is not from ItemSet + Rectangle aTmpRect = m_pData->m_pObjectShell->GetVisArea( ASPECT_CONTENT ); + aTmpRect = OutputDevice::LogicToLogic( aTmpRect, m_pData->m_pObjectShell->GetMapUnit(), MAP_100TH_MM ); + + Sequence< sal_Int32 > aRectSeq(4); + aRectSeq[0] = aTmpRect.Left(); + aRectSeq[1] = aTmpRect.Top(); + aRectSeq[2] = aTmpRect.Right(); + aRectSeq[3] = aTmpRect.Bottom(); + + seqArgsNew.realloc( ++nNewLength ); + seqArgsNew[ nNewLength - 1 ].Name = ::rtl::OUString::createFromAscii( "WinExtent" ); + seqArgsNew[ nNewLength - 1 ].Value <<= aRectSeq; + + if ( m_pData->m_aPreusedFilterName.getLength() ) + { + seqArgsNew.realloc( ++nNewLength ); + seqArgsNew[ nNewLength - 1 ].Name = ::rtl::OUString::createFromAscii( "PreusedFilterName" ); + seqArgsNew[ nNewLength - 1 ].Value <<= m_pData->m_aPreusedFilterName; + } + + SfxViewFrame* pFrame = SfxViewFrame::GetFirst( m_pData->m_pObjectShell ); + if ( pFrame ) + { + SvBorder aBorder = pFrame->GetBorderPixelImpl( pFrame->GetViewShell() ); + + Sequence< sal_Int32 > aBorderSeq(4); + aBorderSeq[0] = aBorder.Left(); + aBorderSeq[1] = aBorder.Top(); + aBorderSeq[2] = aBorder.Right(); + aBorderSeq[3] = aBorder.Bottom(); + + seqArgsNew.realloc( ++nNewLength ); + seqArgsNew[ nNewLength - 1 ].Name = ::rtl::OUString::createFromAscii( "DocumentBorder" ); + seqArgsNew[ nNewLength - 1 ].Value <<= aBorderSeq; + } + + // only the values that are not supported by the ItemSet must be cached here + uno::Sequence< beans::PropertyValue > aFinalCache; + sal_Int32 nFinalLength = 0; + + for ( sal_Int32 nOrg = 0; nOrg < nOrgLength; nOrg++ ) + { + sal_Int32 nOldInd = 0; + while ( nOldInd < nOldLength ) + { + if ( m_pData->m_seqArguments[nOrg].Name.equals( seqArgsOld[nOldInd].Name ) ) + break; + nOldInd++; + } + + if ( nOldInd == nOldLength ) + { + // the entity with this name should be new for seqArgsNew + // since it is not supported by transformer + + seqArgsNew.realloc( ++nNewLength ); + seqArgsNew[ nNewLength - 1 ] = m_pData->m_seqArguments[nOrg]; + + aFinalCache.realloc( ++nFinalLength ); + aFinalCache[ nFinalLength - 1 ] = m_pData->m_seqArguments[nOrg]; + } + } + + m_pData->m_seqArguments = aFinalCache; + + return seqArgsNew; + } + + return m_pData->m_seqArguments; +} + +//________________________________________________________________________________________________________ +// frame::XModel +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::connectController( const uno::Reference< frame::XController >& xController ) + throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + OSL_PRECOND( xController.is(), "SfxBaseModel::connectController: invalid controller!" ); + if ( !xController.is() ) + return; + + sal_uInt32 nOldCount = m_pData->m_seqControllers.getLength(); + uno::Sequence< uno::Reference< frame::XController > > aNewSeq( nOldCount + 1 ); + for ( sal_uInt32 n = 0; n < nOldCount; n++ ) + aNewSeq.getArray()[n] = m_pData->m_seqControllers.getConstArray()[n]; + aNewSeq.getArray()[nOldCount] = xController; + m_pData->m_seqControllers = aNewSeq; + + if ( m_pData->m_seqControllers.getLength() == 1 ) + { + SfxViewFrame* pViewFrame = SfxViewFrame::Get( xController, GetObjectShell() ); + ENSURE_OR_THROW( pViewFrame, "SFX document without SFX view!?" ); + pViewFrame->UpdateDocument_Impl(); + const String sDocumentURL = GetObjectShell()->GetMedium()->GetName(); + if ( sDocumentURL.Len() ) + SFX_APP()->Broadcast( SfxStringHint( SID_OPENURL, sDocumentURL ) ); + } +} + +//________________________________________________________________________________________________________ +// frame::XModel +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::disconnectController( const uno::Reference< frame::XController >& xController ) throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + sal_uInt32 nOldCount = m_pData->m_seqControllers.getLength(); + if ( !nOldCount ) + return; + + uno::Sequence< uno::Reference< frame::XController > > aNewSeq( nOldCount - 1 ); + for ( sal_uInt32 nOld = 0, nNew = 0; nOld < nOldCount; ++nOld ) + { + if ( xController != m_pData->m_seqControllers.getConstArray()[nOld] ) + { + aNewSeq.getArray()[nNew] = m_pData->m_seqControllers.getConstArray()[nOld]; + ++nNew; + } + } + + m_pData->m_seqControllers = aNewSeq; + + if ( xController == m_pData->m_xCurrent ) + m_pData->m_xCurrent = uno::Reference< frame::XController > (); +} + +//________________________________________________________________________________________________________ +// frame::XModel +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::lockControllers() throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + ++m_pData->m_nControllerLockCount ; +} + +//________________________________________________________________________________________________________ +// frame::XModel +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::unlockControllers() throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + --m_pData->m_nControllerLockCount ; +} + +//________________________________________________________________________________________________________ +// frame::XModel +//________________________________________________________________________________________________________ + +sal_Bool SAL_CALL SfxBaseModel::hasControllersLocked() throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + return ( m_pData->m_nControllerLockCount != 0 ) ; +} + +//________________________________________________________________________________________________________ +// frame::XModel +//________________________________________________________________________________________________________ + +uno::Reference< frame::XController > SAL_CALL SfxBaseModel::getCurrentController() throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + // get the last active controller of this model + if ( m_pData->m_xCurrent.is() ) + return m_pData->m_xCurrent; + + // get the first controller of this model + return m_pData->m_seqControllers.getLength() ? m_pData->m_seqControllers.getConstArray()[0] : m_pData->m_xCurrent; +} + +//________________________________________________________________________________________________________ +// frame::XModel +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::setCurrentController( const uno::Reference< frame::XController >& xCurrentController ) + throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + m_pData->m_xCurrent = xCurrentController; +} + +//________________________________________________________________________________________________________ +// frame::XModel +//________________________________________________________________________________________________________ + +uno::Reference< uno::XInterface > SAL_CALL SfxBaseModel::getCurrentSelection() throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + uno::Reference< uno::XInterface > xReturn; + uno::Reference< frame::XController > xController = getCurrentController() ; + + if ( xController.is() ) + { + uno::Reference< view::XSelectionSupplier > xDocView( xController, uno::UNO_QUERY ); + if ( xDocView.is() ) + { + uno::Any xSel = xDocView->getSelection(); + xSel >>= xReturn ; + } + } + + return xReturn ; +} + +//________________________________________________________________________________________________________ +// XModifiable2 +//________________________________________________________________________________________________________ + +sal_Bool SAL_CALL SfxBaseModel::disableSetModified() throw (::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + if ( !m_pData->m_pObjectShell.Is() ) + throw uno::RuntimeException(); + + sal_Bool bResult = m_pData->m_pObjectShell->IsEnableSetModified(); + m_pData->m_pObjectShell->EnableSetModified( sal_False ); + + return bResult; +} + +sal_Bool SAL_CALL SfxBaseModel::enableSetModified() throw (::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + if ( !m_pData->m_pObjectShell.Is() ) + throw uno::RuntimeException(); + + sal_Bool bResult = m_pData->m_pObjectShell->IsEnableSetModified(); + m_pData->m_pObjectShell->EnableSetModified( sal_True ); + + return bResult; +} + +sal_Bool SAL_CALL SfxBaseModel::isSetModifiedEnabled() throw (::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + if ( !m_pData->m_pObjectShell.Is() ) + throw uno::RuntimeException(); + + return m_pData->m_pObjectShell->IsEnableSetModified(); +} + +//________________________________________________________________________________________________________ +// XModifiable +//________________________________________________________________________________________________________ + +sal_Bool SAL_CALL SfxBaseModel::isModified() throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + return m_pData->m_pObjectShell.Is() ? m_pData->m_pObjectShell->IsModified() : sal_False; +} + +//________________________________________________________________________________________________________ +// XModifiable +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::setModified( sal_Bool bModified ) + throw (::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + if ( m_pData->m_pObjectShell.Is() ) + m_pData->m_pObjectShell->SetModified(bModified); +} + +//________________________________________________________________________________________________________ +// XModifiable +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::addModifyListener(const uno::Reference< XMODIFYLISTENER >& xListener) throw( uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + + m_pData->m_aInterfaceContainer.addInterface( ::getCppuType((const uno::Reference< XMODIFYLISTENER >*)0),xListener ); +} + +//________________________________________________________________________________________________________ +// XModifiable +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::removeModifyListener(const uno::Reference< XMODIFYLISTENER >& xListener) throw( uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + + m_pData->m_aInterfaceContainer.removeInterface( ::getCppuType((const uno::Reference< XMODIFYLISTENER >*)0), xListener ); +} + +//____________________________________________________________________________________________________ +// XCloseable +//____________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::close( sal_Bool bDeliverOwnership ) throw (util::CloseVetoException, uno::RuntimeException) +{ + static ::rtl::OUString MSG_1 = ::rtl::OUString::createFromAscii("Cant close while saving."); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() || m_pData->m_bClosed || m_pData->m_bClosing ) + return; + + uno::Reference< uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) ); + lang::EventObject aSource (static_cast< ::cppu::OWeakObject*>(this)); + ::cppu::OInterfaceContainerHelper* pContainer = m_pData->m_aInterfaceContainer.getContainer( ::getCppuType( ( const uno::Reference< util::XCloseListener >*) NULL ) ); + if (pContainer!=NULL) + { + ::cppu::OInterfaceIteratorHelper pIterator(*pContainer); + while (pIterator.hasMoreElements()) + { + try + { + ((util::XCloseListener*)pIterator.next())->queryClosing( aSource, bDeliverOwnership ); + } + catch( uno::RuntimeException& ) + { + pIterator.remove(); + } + } + } + + if ( m_pData->m_bSaving ) + { + if (bDeliverOwnership) + m_pData->m_bSuicide = sal_True; + throw util::CloseVetoException( + MSG_1, + static_cast< ::com::sun::star::util::XCloseable* >(this)); + } + + // no own objections against closing! + m_pData->m_bClosing = sal_True; + pContainer = m_pData->m_aInterfaceContainer.getContainer( ::getCppuType( ( const uno::Reference< util::XCloseListener >*) NULL ) ); + if (pContainer!=NULL) + { + ::cppu::OInterfaceIteratorHelper pCloseIterator(*pContainer); + while (pCloseIterator.hasMoreElements()) + { + try + { + ((util::XCloseListener*)pCloseIterator.next())->notifyClosing( aSource ); + } + catch( uno::RuntimeException& ) + { + pCloseIterator.remove(); + } + } + } + + m_pData->m_bClosed = sal_True; + m_pData->m_bClosing = sal_False; + + dispose(); +} + +//____________________________________________________________________________________________________ +// XCloseBroadcaster +//____________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::addCloseListener( const uno::Reference< XCLOSELISTENER >& xListener ) throw (uno::RuntimeException) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + + m_pData->m_aInterfaceContainer.addInterface( ::getCppuType((const uno::Reference< XCLOSELISTENER >*)0), xListener ); +} + +//____________________________________________________________________________________________________ +// XCloseBroadcaster +//____________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::removeCloseListener( const uno::Reference< XCLOSELISTENER >& xListener ) throw (uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + m_pData->m_aInterfaceContainer.removeInterface( ::getCppuType((const uno::Reference< XCLOSELISTENER >*)0), xListener ); +} + +//________________________________________________________________________________________________________ +// XPrintable +//________________________________________________________________________________________________________ + +uno::Sequence< beans::PropertyValue > SAL_CALL SfxBaseModel::getPrinter() throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + if ( impl_getPrintHelper() ) + return m_pData->m_xPrintable->getPrinter(); + else + return uno::Sequence< beans::PropertyValue >(); +} + +void SAL_CALL SfxBaseModel::setPrinter(const uno::Sequence< beans::PropertyValue >& rPrinter) + throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + if ( impl_getPrintHelper() ) + m_pData->m_xPrintable->setPrinter( rPrinter ); +} + +void SAL_CALL SfxBaseModel::print(const uno::Sequence< beans::PropertyValue >& rOptions) + throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + if ( impl_getPrintHelper() ) + m_pData->m_xPrintable->print( rOptions ); +} + +//________________________________________________________________________________________________________ +// XStorable +//________________________________________________________________________________________________________ + +sal_Bool SAL_CALL SfxBaseModel::hasLocation() throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + return m_pData->m_pObjectShell.Is() ? m_pData->m_pObjectShell->HasName() : sal_False; +} + +//________________________________________________________________________________________________________ +// XStorable +//________________________________________________________________________________________________________ + +::rtl::OUString SAL_CALL SfxBaseModel::getLocation() throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + if ( m_pData->m_pObjectShell.Is() ) + { + // TODO/LATER: is it correct that the shared document returns shared file location? + if ( m_pData->m_pObjectShell->IsDocShared() ) + return m_pData->m_pObjectShell->GetSharedFileURL(); + else + return ::rtl::OUString(m_pData->m_pObjectShell->GetMedium()->GetName()); + } + + return m_pData->m_sURL; +} + +//________________________________________________________________________________________________________ +// XStorable +//________________________________________________________________________________________________________ + +sal_Bool SAL_CALL SfxBaseModel::isReadonly() throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + return m_pData->m_pObjectShell.Is() ? m_pData->m_pObjectShell->IsReadOnly() : sal_True; +} + +//________________________________________________________________________________________________________ +// XStorable2 +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::storeSelf( const uno::Sequence< beans::PropertyValue >& aSeqArgs ) + throw ( ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ) +{ + RTL_LOGFILE_PRODUCT_CONTEXT( aPerfLog, "PERFORMANCE - SfxBaseModel::storeSelf" ); + + SfxModelGuard aGuard( *this ); + + if ( m_pData->m_pObjectShell.Is() ) + { + m_pData->m_pObjectShell->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "storeSelf" ) ) ); + SfxSaveGuard aSaveGuard(this, m_pData, sal_False); + + for ( sal_Int32 nInd = 0; nInd < aSeqArgs.getLength(); nInd++ ) + { + // check that only acceptable parameters are provided here + if ( !aSeqArgs[nInd].Name.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VersionComment" ) ) ) + && !aSeqArgs[nInd].Name.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Author" ) ) ) + && !aSeqArgs[nInd].Name.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InteractionHandler" ) ) ) + && !aSeqArgs[nInd].Name.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StatusIndicator" ) ) ) ) + { + m_pData->m_pObjectShell->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "unexpected parameter for storeSelf, might be no problem if SaveAs is executed." ) ) ); + m_pData->m_pObjectShell->StoreLog(); + + ::rtl::OUString aMessage( RTL_CONSTASCII_USTRINGPARAM( "Unexpected MediaDescriptor parameter: " ) ); + aMessage += aSeqArgs[nInd].Name; + throw lang::IllegalArgumentException( aMessage, uno::Reference< uno::XInterface >(), 1 ); + } + } + + SfxAllItemSet *pParams = new SfxAllItemSet( SFX_APP()->GetPool() ); + TransformParameters( SID_SAVEDOC, aSeqArgs, *pParams ); + + SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_SAVEDOC, GlobalEventConfig::GetEventName(STR_EVENT_SAVEDOC), m_pData->m_pObjectShell ) ); + + sal_Bool bRet = sal_False; + + // TODO/LATER: let the embedded case of saving be handled more careful + if ( m_pData->m_pObjectShell->GetCreateMode() == SFX_CREATE_MODE_EMBEDDED ) + { + // If this is an embedded object that has no URL based location it should be stored to own storage. + // An embedded object can have a location based on URL in case it is a link, then it should be + // stored in normal way. + if ( !hasLocation() || getLocation().compareToAscii( "private:", 8 ) == 0 ) + { + // actually in this very rare case only UI parameters have sence + // TODO/LATER: should be done later, after integration of sb19 + bRet = m_pData->m_pObjectShell->DoSave() + && m_pData->m_pObjectShell->DoSaveCompleted(); + } + else + { + bRet = m_pData->m_pObjectShell->Save_Impl( pParams ); + } + } + else + bRet = m_pData->m_pObjectShell->Save_Impl( pParams ); + + DELETEZ( pParams ); + + sal_uInt32 nErrCode = m_pData->m_pObjectShell->GetError() ? m_pData->m_pObjectShell->GetError() + : ERRCODE_IO_CANTWRITE; + m_pData->m_pObjectShell->ResetError(); + + if ( bRet ) + { + m_pData->m_pObjectShell->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "successful saving." ) ) ); + m_pData->m_aPreusedFilterName = GetMediumFilterName_Impl(); + + SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_SAVEDOCDONE, GlobalEventConfig::GetEventName(STR_EVENT_SAVEDOCDONE), m_pData->m_pObjectShell ) ); + } + else + { + m_pData->m_pObjectShell->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Storing failed!" ) ) ); + m_pData->m_pObjectShell->StoreLog(); + + // write the contents of the logger to the file + SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_SAVEDOCFAILED, GlobalEventConfig::GetEventName(STR_EVENT_SAVEDOCFAILED), m_pData->m_pObjectShell ) ); + + throw task::ErrorCodeIOException( ::rtl::OUString(), uno::Reference< uno::XInterface >(), nErrCode ); + } + } + +} + +//________________________________________________________________________________________________________ +// XStorable +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::store() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) +{ + storeSelf( uno::Sequence< beans::PropertyValue >() ); +} + +//________________________________________________________________________________________________________ +// XStorable +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::storeAsURL( const ::rtl::OUString& rURL , + const uno::Sequence< beans::PropertyValue >& rArgs ) + throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_PRODUCT_CONTEXT( aPerfLog, "PERFORMANCE - SfxBaseModel::storeAsURL" ); + + SfxModelGuard aGuard( *this ); + + if ( m_pData->m_pObjectShell.Is() ) + { + m_pData->m_pObjectShell->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "storeAsURL" ) ) ); + SfxSaveGuard aSaveGuard(this, m_pData, sal_False); + + impl_store( rURL, rArgs, sal_False ); + + uno::Sequence< beans::PropertyValue > aSequence ; + TransformItems( SID_OPENDOC, *m_pData->m_pObjectShell->GetMedium()->GetItemSet(), aSequence ); + attachResource( rURL, aSequence ); + } +} + +//________________________________________________________________________________________________________ +// XStorable +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::storeToURL( const ::rtl::OUString& rURL , + const uno::Sequence< beans::PropertyValue >& rArgs ) + throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + if ( m_pData->m_pObjectShell.Is() ) + { + m_pData->m_pObjectShell->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "storeToURL" ) ) ); + SfxSaveGuard aSaveGuard(this, m_pData, sal_False); + impl_store( rURL, rArgs, sal_True ); + } +} + +::sal_Bool SAL_CALL SfxBaseModel::wasModifiedSinceLastSave() throw ( RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + return m_pData->m_bModifiedSinceLastSave; +} + +void SAL_CALL SfxBaseModel::storeToRecoveryFile( const ::rtl::OUString& i_TargetLocation, const Sequence< PropertyValue >& i_MediaDescriptor ) throw ( RuntimeException, IOException, WrappedTargetException ) +{ + SfxModelGuard aGuard( *this ); + + // delegate + SfxSaveGuard aSaveGuard( this, m_pData, sal_False ); + impl_store( i_TargetLocation, i_MediaDescriptor, sal_True ); + + // no need for subsequent calls to storeToRecoveryFile, unless we're modified, again + m_pData->m_bModifiedSinceLastSave = sal_False; +} + +void SAL_CALL SfxBaseModel::recoverFromFile( const ::rtl::OUString& i_SourceLocation, const ::rtl::OUString& i_SalvagedFile, const Sequence< PropertyValue >& i_MediaDescriptor ) throw ( RuntimeException, IOException, WrappedTargetException ) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + + // delegate to our "load" method + ::comphelper::NamedValueCollection aMediaDescriptor( i_MediaDescriptor ); + + // our load implementation expects the SalvagedFile to be in the media descriptor + OSL_ENSURE( !aMediaDescriptor.has( "SalvagedFile" ) || ( aMediaDescriptor.getOrDefault( "SalvagedFile", ::rtl::OUString() ) == i_SalvagedFile ), + "SfxBaseModel::recoverFromFile: inconsistent information!" ); + aMediaDescriptor.put( "SalvagedFile", i_SalvagedFile ); + + // similar for the to-be-loaded file + OSL_ENSURE( !aMediaDescriptor.has( "URL" ) || ( aMediaDescriptor.getOrDefault( "URL", ::rtl::OUString() ) == i_SourceLocation ), + "SfxBaseModel::recoverFromFile: inconsistent information!" ); + aMediaDescriptor.put( "URL", i_SourceLocation ); + + load( aMediaDescriptor.getPropertyValues() ); + + // Note: The XDocumentRecovery interface specification requires us to do an attachResource after loading. + // However, we will not do this here, as we know that our load implementation (respectively some method + // called from there) already did so. + // In particular, the load process might already have modified some elements of the media + // descriptor, for instance the MacroExecMode (in case the user was involved to decide about it), and we do + // not want to overwrite it with the "old" elements passed to this method here. +} + +//________________________________________________________________________________________________________ +// XLoadable +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::initNew() + throw (::com::sun::star::frame::DoubleInitializationException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException, + ::com::sun::star::uno::Exception) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + if ( IsInitialized() ) + throw ::com::sun::star::frame::DoubleInitializationException( ::rtl::OUString(), *this ); + + // the object shell should exist always + DBG_ASSERT( m_pData->m_pObjectShell.Is(), "Model is useless without an ObjectShell" ); + if ( m_pData->m_pObjectShell.Is() ) + { + if( m_pData->m_pObjectShell->GetMedium() ) + throw DOUBLEINITIALIZATIONEXCEPTION(); + + sal_Bool bRes = m_pData->m_pObjectShell->DoInitNew( NULL ); + sal_uInt32 nErrCode = m_pData->m_pObjectShell->GetError() ? + m_pData->m_pObjectShell->GetError() : ERRCODE_IO_CANTCREATE; + m_pData->m_pObjectShell->ResetError(); + + if ( !bRes ) + throw task::ErrorCodeIOException( ::rtl::OUString(), uno::Reference< uno::XInterface >(), nErrCode ); + } +} + +//________________________________________________________________________________________________________ +// XLoadable +//________________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::load( const uno::Sequence< beans::PropertyValue >& seqArguments ) + throw (::com::sun::star::frame::DoubleInitializationException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException, + ::com::sun::star::uno::Exception) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + if ( IsInitialized() ) + throw ::com::sun::star::frame::DoubleInitializationException( ::rtl::OUString(), *this ); + + // the object shell should exist always + DBG_ASSERT( m_pData->m_pObjectShell.Is(), "Model is useless without an ObjectShell" ); + + if ( m_pData->m_pObjectShell.Is() ) + { + if( m_pData->m_pObjectShell->GetMedium() ) + // if a Medium is present, the document is already initialized + throw DOUBLEINITIALIZATIONEXCEPTION(); + + SfxMedium* pMedium = new SfxMedium( seqArguments ); + String aFilterName; + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pFilterNameItem, SfxStringItem, SID_FILTER_NAME, sal_False ); + if( pFilterNameItem ) + aFilterName = pFilterNameItem->GetValue(); + if( !m_pData->m_pObjectShell->GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName ) ) + { + // filtername is not valid + delete pMedium; + throw frame::IllegalArgumentIOException(); + } + + // !TODO: currently not working + //SFX_ITEMSET_ARG( pParams, pFrameItem, SfxFrameItem, SID_DOCFRAME, FALSE ); + //if( pFrameItem && pFrameItem->GetFrame() ) + //{ + // SfxFrame* pFrame = pFrameItem->GetFrame(); + // pMedium->SetLoadTargetFrame( pFrame ); + //} + + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False ); + sal_Bool bSalvage = pSalvageItem ? sal_True : sal_False; + + // SFX_ITEMSET_ARG( pMedium->GetItemSet(), pTemplateItem, SfxBoolItem, SID_TEMPLATE, sal_False); + // sal_Bool bTemplate = pTemplateItem && pTemplateItem->GetValue(); + // + // does already happen in DoLoad call + //m_pData->m_pObjectShell->SetActivateEvent_Impl( bTemplate ? SFX_EVENT_CREATEDOC : SFX_EVENT_OPENDOC ); + + // load document + sal_uInt32 nError = ERRCODE_NONE; + if ( !m_pData->m_pObjectShell->DoLoad(pMedium) ) + nError=ERRCODE_IO_GENERAL; + + // QUESTION: if the following happens outside of DoLoad, something important is missing there! + ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler > xHandler = pMedium->GetInteractionHandler(); + if( m_pData->m_pObjectShell->GetErrorCode() ) + { + nError = m_pData->m_pObjectShell->GetErrorCode(); + if ( nError == ERRCODE_IO_BROKENPACKAGE && xHandler.is() ) + { + ::rtl::OUString aDocName = pMedium->GetURLObject().getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pRepairItem, SfxBoolItem, SID_REPAIRPACKAGE, FALSE ); + if ( !pRepairItem || !pRepairItem->GetValue() ) + { + RequestPackageReparation* pRequest = new RequestPackageReparation( aDocName ); + com::sun::star::uno::Reference< com::sun::star::task::XInteractionRequest > xRequest ( pRequest ); + xHandler->handle( xRequest ); + if( pRequest->isApproved() ) + { + // broken package: try second loading and allow repair + pMedium->GetItemSet()->Put( SfxBoolItem( SID_REPAIRPACKAGE, sal_True ) ); + pMedium->GetItemSet()->Put( SfxBoolItem( SID_TEMPLATE, sal_True ) ); + pMedium->GetItemSet()->Put( SfxStringItem( SID_DOCINFO_TITLE, aDocName ) ); + + // the error must be reset and the storage must be reopened in new mode + pMedium->ResetError(); + pMedium->CloseStorage(); + m_pData->m_pObjectShell->PrepareSecondTryLoad_Impl(); + if ( !m_pData->m_pObjectShell->DoLoad(pMedium) ) + nError=ERRCODE_IO_GENERAL; + nError = m_pData->m_pObjectShell->GetErrorCode(); + } + } + + if ( nError == ERRCODE_IO_BROKENPACKAGE ) + { + // repair either not allowed or not successful + NotifyBrokenPackage* pNotifyRequest = new NotifyBrokenPackage( aDocName ); + com::sun::star::uno::Reference< com::sun::star::task::XInteractionRequest > xRequest ( pNotifyRequest ); + xHandler->handle( xRequest ); + } + } + } + + if( m_pData->m_pObjectShell->IsAbortingImport() ) + nError = ERRCODE_ABORT; + + if( bSalvage ) + { + // file recovery: restore original filter + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False ); + SfxFilterMatcher& rMatcher = SFX_APP()->GetFilterMatcher(); + const SfxFilter* pSetFilter = rMatcher.GetFilter4FilterName( pFilterItem->GetValue() ); + pMedium->SetFilter( pSetFilter ); + m_pData->m_pObjectShell->SetModified(sal_True); + } + + // TODO/LATER: may be the mode should be retrieved from outside and the preused filter should not be set + if ( m_pData->m_pObjectShell->GetCreateMode() == SFX_CREATE_MODE_EMBEDDED ) + { + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pFilterItem, SfxStringItem, SID_FILTER_NAME, sal_False ); + if ( pFilterItem ) + m_pData->m_aPreusedFilterName = pFilterItem->GetValue(); + } + + if ( !nError ) + nError = pMedium->GetError(); + + m_pData->m_pObjectShell->ResetError(); + + if ( nError ) + { + BOOL bSilent = FALSE; + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pSilentItem, SfxBoolItem, SID_SILENT, sal_False); + if( pSilentItem ) + bSilent = pSilentItem->GetValue(); + + BOOL bWarning = ((nError & ERRCODE_WARNING_MASK) == ERRCODE_WARNING_MASK); + if ( nError != ERRCODE_IO_BROKENPACKAGE && !bSilent ) + { + // broken package was handled already + if ( SfxObjectShell::UseInteractionToHandleError( xHandler, nError ) && !bWarning ) + { + // abort loading (except for warnings) + nError = ERRCODE_IO_ABORT; + } + } + + if ( m_pData->m_pObjectShell->GetMedium() != pMedium ) + { + // for whatever reason document now has another medium + DBG_ERROR("Document has rejected the medium?!"); + delete pMedium; + } + + if ( !bWarning ) // #i30711# don't abort loading if it's only a warning + { + throw task::ErrorCodeIOException( ::rtl::OUString(), + uno::Reference< uno::XInterface >(), + nError ? nError : ERRCODE_IO_CANTREAD ); + } + } + + BOOL bHidden = FALSE; + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pHidItem, SfxBoolItem, SID_HIDDEN, sal_False); + if ( pHidItem ) + bHidden = pHidItem->GetValue(); + // !TODO: will be done by Framework! + pMedium->SetUpdatePickList( !bHidden ); + } +} + +//________________________________________________________________________________________________________ +// XTransferable +//________________________________________________________________________________________________________ + +uno::Any SAL_CALL SfxBaseModel::getTransferData( const DATAFLAVOR& aFlavor ) + throw (::com::sun::star::datatransfer::UnsupportedFlavorException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + uno::Any aAny; + + if ( m_pData->m_pObjectShell.Is() ) + { + if ( aFlavor.MimeType.equalsAscii( "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + { + TransferableObjectDescriptor aDesc; + + aDesc.maClassName = m_pData->m_pObjectShell->GetClassName(); + aDesc.maTypeName = aFlavor.HumanPresentableName; + + // TODO/LATER: ViewAspect needs to be sal_Int64 + aDesc.mnViewAspect = sal::static_int_cast< sal_uInt16 >( embed::Aspects::MSOLE_CONTENT ); + + //TODO/LATER: status needs to become sal_Int64 + aDesc.mnOle2Misc = m_pData->m_pObjectShell->GetMiscStatus(); + Size aSize = m_pData->m_pObjectShell->GetVisArea().GetSize(); + + MapUnit aMapUnit = m_pData->m_pObjectShell->GetMapUnit(); + aDesc.maSize = OutputDevice::LogicToLogic( aSize, aMapUnit, MAP_100TH_MM ); + aDesc.maDragStartPos = Point(); + aDesc.maDisplayName = String(); + aDesc.mbCanLink = FALSE; + + SvMemoryStream aMemStm( 1024, 1024 ); + aMemStm << aDesc; + aAny <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Tell() ); + } + else + throw datatransfer::UnsupportedFlavorException(); + } + else if ( aFlavor.MimeType.equalsAscii( "application/x-openoffice-embed-source;windows_formatname=\"Star EMBS\"" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + { + try + { + utl::TempFile aTmp; + aTmp.EnableKillingFile( TRUE ); + storeToURL( aTmp.GetURL(), uno::Sequence < beans::PropertyValue >() ); + SvStream* pStream = aTmp.GetStream( STREAM_READ ); + const sal_uInt32 nLen = pStream->Seek( STREAM_SEEK_TO_END ); + ::com::sun::star::uno::Sequence< sal_Int8 > aSeq( nLen ); + pStream->Seek( STREAM_SEEK_TO_BEGIN ); + pStream->Read( aSeq.getArray(), nLen ); + delete pStream; + if( aSeq.getLength() ) + aAny <<= aSeq; + } + catch ( uno::Exception& ) + { + } + } + else + throw datatransfer::UnsupportedFlavorException(); + } + else if ( aFlavor.MimeType.equalsAscii( "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + { + + ::boost::shared_ptr<GDIMetaFile> pMetaFile = + m_pData->m_pObjectShell->GetPreviewMetaFile( sal_True ); + + if ( pMetaFile ) + { + SvMemoryStream aMemStm( 65535, 65535 ); + aMemStm.SetVersion( SOFFICE_FILEFORMAT_CURRENT ); + + pMetaFile->Write( aMemStm ); + aAny <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( aMemStm.GetData() ), + aMemStm.Seek( STREAM_SEEK_TO_END ) ); + } + } + else + throw datatransfer::UnsupportedFlavorException(); + } + else if ( aFlavor.MimeType.equalsAscii( "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + { + ::boost::shared_ptr<GDIMetaFile> pMetaFile = + m_pData->m_pObjectShell->CreatePreviewMetaFile_Impl( sal_True, sal_True ); + + if ( pMetaFile ) + { + SvMemoryStream aMemStm( 65535, 65535 ); + aMemStm.SetVersion( SOFFICE_FILEFORMAT_CURRENT ); + + pMetaFile->Write( aMemStm ); + aAny <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( aMemStm.GetData() ), + aMemStm.Seek( STREAM_SEEK_TO_END ) ); + } + } + else + throw datatransfer::UnsupportedFlavorException(); + } + else if ( aFlavor.MimeType.equalsAscii( "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + { + ::boost::shared_ptr<GDIMetaFile> pMetaFile = + m_pData->m_pObjectShell->GetPreviewMetaFile( sal_True ); + + if ( pMetaFile ) + { + ::boost::shared_ptr<SvMemoryStream> pStream( + GraphicHelper::getFormatStrFromGDI_Impl( + pMetaFile.get(), CVT_EMF ) ); + if ( pStream ) + { + pStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT ); + aAny <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( pStream->GetData() ), + pStream->Seek( STREAM_SEEK_TO_END ) ); + } + } + } + else if ( GraphicHelper::supportsMetaFileHandle_Impl() + && aFlavor.DataType == getCppuType( (const sal_uInt64*) 0 ) ) + { + ::boost::shared_ptr<GDIMetaFile> pMetaFile = + m_pData->m_pObjectShell->GetPreviewMetaFile( sal_True ); + + if ( pMetaFile ) + { + aAny <<= reinterpret_cast< const sal_uInt64 >( + GraphicHelper::getEnhMetaFileFromGDI_Impl( pMetaFile.get() ) ); + } + } + else + throw datatransfer::UnsupportedFlavorException(); + } + else if ( aFlavor.MimeType.equalsAscii( "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + { + ::boost::shared_ptr<GDIMetaFile> pMetaFile = + m_pData->m_pObjectShell->GetPreviewMetaFile( sal_True ); + + if ( pMetaFile ) + { + ::boost::shared_ptr<SvMemoryStream> pStream( + GraphicHelper::getFormatStrFromGDI_Impl( + pMetaFile.get(), CVT_WMF ) ); + + if ( pStream ) + { + pStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT ); + aAny <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( pStream->GetData() ), + pStream->Seek( STREAM_SEEK_TO_END ) ); + } + } + } + else if ( GraphicHelper::supportsMetaFileHandle_Impl() + && aFlavor.DataType == getCppuType( (const sal_uInt64*) 0 ) ) + { + // means HGLOBAL handler to memory storage containing METAFILEPICT structure + + ::boost::shared_ptr<GDIMetaFile> pMetaFile = + m_pData->m_pObjectShell->GetPreviewMetaFile( sal_True ); + + if ( pMetaFile ) + { + Size aMetaSize = pMetaFile->GetPrefSize(); + aAny <<= reinterpret_cast< const sal_uInt64 >( + GraphicHelper::getWinMetaFileFromGDI_Impl( + pMetaFile.get(), aMetaSize ) ); + } + } + else + throw datatransfer::UnsupportedFlavorException(); + } + else if ( aFlavor.MimeType.equalsAscii( "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + { + ::boost::shared_ptr<GDIMetaFile> pMetaFile = + m_pData->m_pObjectShell->GetPreviewMetaFile( sal_True ); + + if ( pMetaFile ) + { + ::boost::shared_ptr<SvMemoryStream> pStream( + GraphicHelper::getFormatStrFromGDI_Impl( + pMetaFile.get(), CVT_BMP ) ); + + if ( pStream ) + { + pStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT ); + aAny <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( pStream->GetData() ), + pStream->Seek( STREAM_SEEK_TO_END ) ); + } + } + } + else + throw datatransfer::UnsupportedFlavorException(); + } + else if ( aFlavor.MimeType.equalsAscii( "image/png" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + { + ::boost::shared_ptr<GDIMetaFile> pMetaFile = + m_pData->m_pObjectShell->GetPreviewMetaFile( sal_True ); + + if ( pMetaFile ) + { + ::boost::shared_ptr<SvMemoryStream> pStream( + GraphicHelper::getFormatStrFromGDI_Impl( + pMetaFile.get(), CVT_PNG ) ); + + if ( pStream ) + { + pStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT ); + aAny <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( pStream->GetData() ), + pStream->Seek( STREAM_SEEK_TO_END ) ); + } + } + } + else + throw datatransfer::UnsupportedFlavorException(); + } + else + throw datatransfer::UnsupportedFlavorException(); + } + + return aAny; +} + +//________________________________________________________________________________________________________ +// XTransferable +//________________________________________________________________________________________________________ + + +uno::Sequence< DATAFLAVOR > SAL_CALL SfxBaseModel::getTransferDataFlavors() + throw (::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + sal_Int32 nSuppFlavors = GraphicHelper::supportsMetaFileHandle_Impl() ? 10 : 8; + uno::Sequence< DATAFLAVOR > aFlavorSeq( nSuppFlavors ); + + aFlavorSeq[0].MimeType = + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" ) ); + aFlavorSeq[0].HumanPresentableName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GDIMetaFile" ) ); + aFlavorSeq[0].DataType = getCppuType( (const Sequence< sal_Int8 >*) 0 ); + + aFlavorSeq[1].MimeType = + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" ) ); + aFlavorSeq[1].HumanPresentableName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GDIMetaFile" ) ); + aFlavorSeq[1].DataType = getCppuType( (const Sequence< sal_Int8 >*) 0 ); + + aFlavorSeq[2].MimeType = + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" ) ); + aFlavorSeq[2].HumanPresentableName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Enhanced Windows MetaFile" ) ); + aFlavorSeq[2].DataType = getCppuType( (const Sequence< sal_Int8 >*) 0 ); + + aFlavorSeq[3].MimeType = + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" ) ); + aFlavorSeq[3].HumanPresentableName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Windows MetaFile" ) ); + aFlavorSeq[3].DataType = getCppuType( (const Sequence< sal_Int8 >*) 0 ); + + aFlavorSeq[4].MimeType = + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"" ) ); + aFlavorSeq[4].HumanPresentableName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Star Object Descriptor (XML)" ) ); + aFlavorSeq[4].DataType = getCppuType( (const Sequence< sal_Int8 >*) 0 ); + + aFlavorSeq[5].MimeType = + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"" ) ); + aFlavorSeq[5].HumanPresentableName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Star Embed Source (XML)" ) ); + aFlavorSeq[5].DataType = getCppuType( (const Sequence< sal_Int8 >*) 0 ); + + aFlavorSeq[6].MimeType = + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" ) ); + aFlavorSeq[6].HumanPresentableName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Bitmap" ) ); + aFlavorSeq[6].DataType = getCppuType( (const Sequence< sal_Int8 >*) 0 ); + + aFlavorSeq[7].MimeType = + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "image/png" ) ); + aFlavorSeq[7].HumanPresentableName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PNG" ) ); + aFlavorSeq[7].DataType = getCppuType( (const Sequence< sal_Int8 >*) 0 ); + + if ( nSuppFlavors == 10 ) + { + aFlavorSeq[8].MimeType = + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" ) ); + aFlavorSeq[8].HumanPresentableName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Enhanced Windows MetaFile" ) ); + aFlavorSeq[8].DataType = getCppuType( (const sal_uInt64*) 0 ); + + aFlavorSeq[9].MimeType = + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" ) ); + aFlavorSeq[9].HumanPresentableName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Windows MetaFile" ) ); + aFlavorSeq[9].DataType = getCppuType( (const sal_uInt64*) 0 ); + } + + return aFlavorSeq; +} + +//________________________________________________________________________________________________________ +// XTransferable +//________________________________________________________________________________________________________ + + +sal_Bool SAL_CALL SfxBaseModel::isDataFlavorSupported( const DATAFLAVOR& aFlavor ) + throw (::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + if ( aFlavor.MimeType.equalsAscii( "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + return sal_True; + } + else if ( aFlavor.MimeType.equalsAscii( "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + return sal_True; + } + else if ( aFlavor.MimeType.equalsAscii( "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + return sal_True; + else if ( GraphicHelper::supportsMetaFileHandle_Impl() + && aFlavor.DataType == getCppuType( (const sal_uInt64*) 0 ) ) + return sal_True; + } + else if ( aFlavor.MimeType.equalsAscii( "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + return sal_True; + else if ( GraphicHelper::supportsMetaFileHandle_Impl() + && aFlavor.DataType == getCppuType( (const sal_uInt64*) 0 ) ) + return sal_True; + } + else if ( aFlavor.MimeType.equalsAscii( "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + return sal_True; + } + else if ( aFlavor.MimeType.equalsAscii( "application/x-openoffice-embed-source;windows_formatname=\"Star EMBS\"" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + return sal_True; + } + else if ( aFlavor.MimeType.equalsAscii( "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + return sal_True; + } + else if ( aFlavor.MimeType.equalsAscii( "image/png" ) ) + { + if ( aFlavor.DataType == getCppuType( (const Sequence< sal_Int8 >*) 0 ) ) + return sal_True; + } + + return sal_False; +} + + +//-------------------------------------------------------------------------------------------------------- +// XEventsSupplier +//-------------------------------------------------------------------------------------------------------- + +uno::Reference< container::XNameReplace > SAL_CALL SfxBaseModel::getEvents() throw( uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + + if ( ! m_pData->m_xEvents.is() ) + { + m_pData->m_xEvents = new SfxEvents_Impl( m_pData->m_pObjectShell, this ); + } + + return m_pData->m_xEvents; +} + +//-------------------------------------------------------------------------------------------------------- +// XEmbeddedScripts +//-------------------------------------------------------------------------------------------------------- + +uno::Reference< script::XStorageBasedLibraryContainer > SAL_CALL SfxBaseModel::getBasicLibraries() throw (RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + uno::Reference< script::XStorageBasedLibraryContainer > xBasicLibraries; + if ( m_pData->m_pObjectShell ) + xBasicLibraries.set( m_pData->m_pObjectShell->GetBasicContainer(), UNO_QUERY_THROW ); + return xBasicLibraries; +} + +uno::Reference< script::XStorageBasedLibraryContainer > SAL_CALL SfxBaseModel::getDialogLibraries() throw (RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + uno::Reference< script::XStorageBasedLibraryContainer > xDialogLibraries; + if ( m_pData->m_pObjectShell ) + xDialogLibraries.set( m_pData->m_pObjectShell->GetDialogContainer(), UNO_QUERY_THROW ); + return xDialogLibraries; +} + +::sal_Bool SAL_CALL SfxBaseModel::getAllowMacroExecution() throw (RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + if ( m_pData->m_pObjectShell ) + return m_pData->m_pObjectShell->AdjustMacroMode( String(), false ); + return sal_False; +} + +//-------------------------------------------------------------------------------------------------------- +// XScriptInvocationContext +//-------------------------------------------------------------------------------------------------------- + +Reference< document::XEmbeddedScripts > SAL_CALL SfxBaseModel::getScriptContainer() throw (RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + Reference< document::XEmbeddedScripts > xDocumentScripts; + + try + { + Reference< frame::XModel > xDocument( this ); + xDocumentScripts.set( xDocument, uno::UNO_QUERY ); + while ( !xDocumentScripts.is() && xDocument.is() ) + { + Reference< container::XChild > xDocAsChild( xDocument, uno::UNO_QUERY ); + if ( !xDocAsChild.is() ) + { + xDocument = NULL; + break; + } + + xDocument.set( xDocAsChild->getParent(), uno::UNO_QUERY ); + xDocumentScripts.set( xDocument, uno::UNO_QUERY ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + xDocumentScripts = NULL; + } + + return xDocumentScripts; +} + +//-------------------------------------------------------------------------------------------------------- +// XEventBroadcaster +//-------------------------------------------------------------------------------------------------------- + +void SAL_CALL SfxBaseModel::addEventListener( const uno::Reference< XDOCEVENTLISTENER >& aListener ) throw( uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + + m_pData->m_aInterfaceContainer.addInterface( ::getCppuType((const uno::Reference< XDOCEVENTLISTENER >*)0), aListener ); +} + +//-------------------------------------------------------------------------------------------------------- +// XEventBroadcaster +//-------------------------------------------------------------------------------------------------------- + +void SAL_CALL SfxBaseModel::removeEventListener( const uno::Reference< XDOCEVENTLISTENER >& aListener ) throw( uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + + m_pData->m_aInterfaceContainer.removeInterface( ::getCppuType((const uno::Reference< XDOCEVENTLISTENER >*)0), aListener ); +} + +//________________________________________________________________________________________________________ +// SfxListener +//________________________________________________________________________________________________________ + +void addTitle_Impl( Sequence < ::com::sun::star::beans::PropertyValue >& rSeq, const ::rtl::OUString& rTitle ) +{ + sal_Int32 nCount = rSeq.getLength(); + sal_Int32 nArg; + + for ( nArg = 0; nArg < nCount; nArg++ ) + { + ::com::sun::star::beans::PropertyValue& rProp = rSeq[nArg]; + if ( rProp.Name.equalsAscii("Title") ) + { + rProp.Value <<= rTitle; + break; + } + } + + if ( nArg == nCount ) + { + rSeq.realloc( nCount+1 ); + rSeq[nCount].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Title") ); + rSeq[nCount].Value <<= rTitle; + } +} + +void SfxBaseModel::NotifyStorageListeners_Impl() +{ + uno::Reference< uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) ); + + if ( m_pData->m_pObjectShell ) + { + ::cppu::OInterfaceContainerHelper* pContainer = + m_pData->m_aInterfaceContainer.getContainer( + ::getCppuType( ( const uno::Reference< document::XStorageChangeListener >*) NULL ) ); + if ( pContainer != NULL ) + { + uno::Reference< embed::XStorage > xNewStorage = m_pData->m_pObjectShell->GetStorage(); + ::cppu::OInterfaceIteratorHelper pIterator(*pContainer); + while ( pIterator.hasMoreElements() ) + { + try + { + ((document::XStorageChangeListener*)pIterator.next())->notifyStorageChange( + xSelfHold, + xNewStorage ); + } + catch( uno::RuntimeException& ) + { + pIterator.remove(); + } + } + } + } +} + +void SfxBaseModel::Notify( SfxBroadcaster& rBC , + const SfxHint& rHint ) +{ + if ( !m_pData ) + return; + + if ( &rBC == m_pData->m_pObjectShell ) + { + SfxSimpleHint* pSimpleHint = PTR_CAST( SfxSimpleHint, &rHint ); + if ( pSimpleHint && pSimpleHint->GetId() == SFX_HINT_DOCCHANGED ) + changing(); + + SfxEventHint* pNamedHint = PTR_CAST( SfxEventHint, &rHint ); + if ( pNamedHint ) + { + + switch ( pNamedHint->GetEventId() ) + { + case SFX_EVENT_STORAGECHANGED: + { + // for now this event is sent only on creation of a new storage for new document + // and in case of reload of medium without document reload + // other events are used to detect storage change + // NotifyStorageListeners_Impl(); + + if ( m_pData->m_xUIConfigurationManager.is() + && m_pData->m_pObjectShell->GetCreateMode() != SFX_CREATE_MODE_EMBEDDED ) + { + uno::Reference< XSTORAGE > xConfigStorage; + rtl::OUString aUIConfigFolderName( RTL_CONSTASCII_USTRINGPARAM( "Configurations2" )); + + xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, com::sun::star::embed::ElementModes::READWRITE ); + if ( !xConfigStorage.is() ) + xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, com::sun::star::embed::ElementModes::READ ); + + if ( xConfigStorage.is() || !m_pData->m_pObjectShell->GetStorage()->hasByName( aUIConfigFolderName ) ) + { + // the storage is different, since otherwise it could not be opened, so it must be exchanged + Reference< ui::XUIConfigurationStorage > xUIConfigStorage( m_pData->m_xUIConfigurationManager, uno::UNO_QUERY ); + xUIConfigStorage->setStorage( xConfigStorage ); + } + else + { + OSL_ENSURE( sal_False, "Unexpected scenario!\n" ); + } + } + + ListenForStorage_Impl( m_pData->m_pObjectShell->GetStorage() ); + } + break; + + case SFX_EVENT_LOADFINISHED: + { + impl_getPrintHelper(); + ListenForStorage_Impl( m_pData->m_pObjectShell->GetStorage() ); + m_pData->m_bModifiedSinceLastSave = sal_False; + } + break; + + case SFX_EVENT_SAVEASDOCDONE: + { + m_pData->m_sURL = m_pData->m_pObjectShell->GetMedium()->GetName(); + + SfxItemSet *pSet = m_pData->m_pObjectShell->GetMedium()->GetItemSet(); + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > aArgs; + ::rtl::OUString aTitle = m_pData->m_pObjectShell->GetTitle(); + TransformItems( SID_SAVEASDOC, *pSet, aArgs ); + addTitle_Impl( aArgs, aTitle ); + attachResource( m_pData->m_pObjectShell->GetMedium()->GetName(), aArgs ); + } + break; + + case SFX_EVENT_DOCCREATED: + { + impl_getPrintHelper(); + m_pData->m_bModifiedSinceLastSave = sal_False; + } + break; + + case SFX_EVENT_MODIFYCHANGED: + { + m_pData->m_bModifiedSinceLastSave = isModified(); + } + break; + } + + postEvent_Impl( pNamedHint->GetEventName() ); + } + + if ( pSimpleHint ) + { + if ( pSimpleHint->GetId() == SFX_HINT_TITLECHANGED ) + { + ::rtl::OUString aTitle = m_pData->m_pObjectShell->GetTitle(); + addTitle_Impl( m_pData->m_seqArguments, aTitle ); + postEvent_Impl( GlobalEventConfig::GetEventName( STR_EVENT_TITLECHANGED ) ); + } + if ( pSimpleHint->GetId() == SFX_HINT_MODECHANGED ) + { + postEvent_Impl( GlobalEventConfig::GetEventName( STR_EVENT_MODECHANGED ) ); + } +/* + else if ( pSimpleHint->GetId() == SFX_HINT_DYING + || pSimpleHint->GetId() == SFX_HINT_DEINITIALIZING ) + { + SfxObjectShellLock pShellLock = m_pData->m_pObjectShellLock; + m_pData->m_pObjectShellLock = SfxObjectShellLock(); + } +*/ + } + } +} + +//________________________________________________________________________________________________________ +// public impl. +//________________________________________________________________________________________________________ + +void SfxBaseModel::NotifyModifyListeners_Impl() const +{ + ::cppu::OInterfaceContainerHelper* pIC = m_pData->m_aInterfaceContainer.getContainer( ::getCppuType((const uno::Reference< XMODIFYLISTENER >*)0) ); + if ( pIC ) + { + lang::EventObject aEvent( (frame::XModel *)this ); + pIC->notifyEach( &util::XModifyListener::modified, aEvent ); + } + + // this notification here is done too generously, we cannot simply assume that we're really modified + // now, but we need to check it ... + m_pData->m_bModifiedSinceLastSave = const_cast< SfxBaseModel* >( this )->isModified(); +} + +void SfxBaseModel::changing() +{ + SfxModelGuard aGuard( *this ); + + // the notification should not be sent if the document can not be modified + if ( !m_pData->m_pObjectShell.Is() || !m_pData->m_pObjectShell->IsEnableSetModified() ) + return; + + NotifyModifyListeners_Impl(); +} + +void SfxBaseModel::impl_change() +{ + // object already disposed? + if ( impl_isDisposed() ) + return; + + NotifyModifyListeners_Impl(); +} + +//________________________________________________________________________________________________________ +// public impl. +//________________________________________________________________________________________________________ + +SfxObjectShell* SfxBaseModel::GetObjectShell() const +{ + return m_pData ? (SfxObjectShell*) m_pData->m_pObjectShell : 0; +} + +SfxObjectShell* SfxBaseModel::impl_getObjectShell() const +{ + return m_pData ? (SfxObjectShell*) m_pData->m_pObjectShell : 0; +} + +//________________________________________________________________________________________________________ +// public impl. +//________________________________________________________________________________________________________ + +sal_Bool SfxBaseModel::IsDisposed() const +{ + return ( m_pData == NULL ) ; +} + +sal_Bool SfxBaseModel::IsInitialized() const +{ + if ( !m_pData || !m_pData->m_pObjectShell ) + { + OSL_ENSURE( false, "SfxBaseModel::IsInitialized: this should have been caught earlier!" ); + return sal_False; + } + + return m_pData->m_pObjectShell->GetMedium() != NULL; +} + +sal_Bool SfxBaseModel::impl_isDisposed() const +{ + return ( m_pData == NULL ) ; +} + +//________________________________________________________________________________________________________ +// private impl. +//________________________________________________________________________________________________________ + +::rtl::OUString SfxBaseModel::GetMediumFilterName_Impl() +{ + const SfxFilter* pFilter = NULL; + SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium(); + if ( pMedium ) + pFilter = pMedium->GetFilter(); + + if ( pFilter ) + return pFilter->GetName(); + + return ::rtl::OUString(); +} + +void SfxBaseModel::impl_store( const ::rtl::OUString& sURL , + const uno::Sequence< beans::PropertyValue >& seqArguments , + sal_Bool bSaveTo ) +{ + if( !sURL.getLength() ) + throw frame::IllegalArgumentIOException(); + + //sal_Bool aSaveAsTemplate = sal_False; + + sal_Bool bSaved = sal_False; + if ( !bSaveTo && m_pData->m_pObjectShell && sURL.getLength() + && sURL.compareToAscii( "private:stream", 14 ) != COMPARE_EQUAL + && ::utl::UCBContentHelper::EqualURLs( getLocation(), sURL ) ) + { + // this is the same file URL as the current document location, try to use storeOwn if possible + + ::comphelper::SequenceAsHashMap aArgHash( seqArguments ); + ::rtl::OUString aFilterString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" ) ); + ::rtl::OUString aFilterName = aArgHash.getUnpackedValueOrDefault( aFilterString, ::rtl::OUString() ); + if ( aFilterName.getLength() ) + { + SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium(); + if ( pMedium ) + { + const SfxFilter* pFilter = pMedium->GetFilter(); + if ( pFilter && aFilterName.equals( pFilter->GetFilterName() ) ) + { + aArgHash.erase( aFilterString ); + aArgHash.erase( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) ) ); + + // if the password is changed SaveAs should be done + // no password for encrypted document is also a change here + sal_Bool bPassChanged = sal_False; + + ::comphelper::SequenceAsHashMap::iterator aNewPassIter + = aArgHash.find( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Password" ) ) ); + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pPasswordItem, SfxStringItem, SID_PASSWORD, sal_False ); + if ( pPasswordItem && aNewPassIter != aArgHash.end() ) + { + ::rtl::OUString aNewPass; + aNewPassIter->second >>= aNewPass; + bPassChanged = !aNewPass.equals( pPasswordItem->GetValue() ); + } + else if ( pPasswordItem || aNewPassIter != aArgHash.end() ) + bPassChanged = sal_True; + + if ( !bPassChanged ) + { + try + { + storeSelf( aArgHash.getAsConstPropertyValueList() ); + bSaved = sal_True; + } + catch( const lang::IllegalArgumentException& ) + { + // some additional arguments do not allow to use saving, SaveAs should be done + // but only for normal documents, the shared documents would be overwritten in this case + // that would mean an information loss + // TODO/LATER: need a new interaction for this case + if ( m_pData->m_pObjectShell->IsDocShared() ) + { + m_pData->m_pObjectShell->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't store shared document!" ) ) ); + m_pData->m_pObjectShell->StoreLog(); + + throw; + } + } + } + else if ( m_pData->m_pObjectShell->IsDocShared() ) + { + // if the password is changed a special error should be used in case of shared document + throw task::ErrorCodeIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Cant change password for shared document." ) ), uno::Reference< uno::XInterface >(), ERRCODE_SFX_SHARED_NOPASSWORDCHANGE ); + } + } + } + } + } + + if ( !bSaved && m_pData->m_pObjectShell ) + { + SFX_APP()->NotifyEvent( SfxEventHint( bSaveTo ? SFX_EVENT_SAVETODOC : SFX_EVENT_SAVEASDOC, GlobalEventConfig::GetEventName( bSaveTo ? STR_EVENT_SAVETODOC : STR_EVENT_SAVEASDOC ), + m_pData->m_pObjectShell ) ); + + SfxAllItemSet *aParams = new SfxAllItemSet( SFX_APP()->GetPool() ); + aParams->Put( SfxStringItem( SID_FILE_NAME, String(sURL) ) ); + if ( bSaveTo ) + aParams->Put( SfxBoolItem( SID_SAVETO, sal_True ) ); + + TransformParameters( SID_SAVEASDOC, seqArguments, *aParams ); + + SFX_ITEMSET_ARG( aParams, pCopyStreamItem, SfxBoolItem, SID_COPY_STREAM_IF_POSSIBLE, sal_False ); + + if ( pCopyStreamItem && pCopyStreamItem->GetValue() && !bSaveTo ) + { + m_pData->m_pObjectShell->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Misuse of CopyStreamIfPossible!" ) ) ); + m_pData->m_pObjectShell->StoreLog(); + + throw frame::IllegalArgumentIOException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("CopyStreamIfPossible parameter is not acceptable for storeAsURL() call!") ), + uno::Reference< uno::XInterface >() ); + } + + sal_uInt32 nModifyPasswordHash = 0; + uno::Sequence< beans::PropertyValue > aModifyPasswordInfo; + SFX_ITEMSET_ARG( aParams, pModifyPasswordInfoItem, SfxUnoAnyItem, SID_MODIFYPASSWORDINFO, sal_False ); + if ( pModifyPasswordInfoItem ) + { + // it contains either a simple hash or a set of PropertyValues + // TODO/LATER: the sequence of PropertyValue should replace the hash completely in future + sal_Int32 nMPHTmp = 0; + pModifyPasswordInfoItem->GetValue() >>= nMPHTmp; + nModifyPasswordHash = (sal_uInt32)nMPHTmp; + pModifyPasswordInfoItem->GetValue() >>= aModifyPasswordInfo; + } + aParams->ClearItem( SID_MODIFYPASSWORDINFO ); + sal_uInt32 nOldModifyPasswordHash = m_pData->m_pObjectShell->GetModifyPasswordHash(); + m_pData->m_pObjectShell->SetModifyPasswordHash( nModifyPasswordHash ); + uno::Sequence< beans::PropertyValue > aOldModifyPasswordInfo = m_pData->m_pObjectShell->GetModifyPasswordInfo(); + m_pData->m_pObjectShell->SetModifyPasswordInfo( aModifyPasswordInfo ); + + // since saving a document modifies its DocumentInfo, the current + // DocumentInfo must be saved on "SaveTo", so it can be restored + // after saving + sal_Bool bCopyTo = bSaveTo || + m_pData->m_pObjectShell->GetCreateMode() == SFX_CREATE_MODE_EMBEDDED; + uno::Reference<document::XDocumentProperties> xOldDocProps; + uno::Reference<document::XDocumentInfo> xOldDocInfo; + if ( bCopyTo ) + { + xOldDocProps = getDocumentProperties(); + if (m_pData->m_xDocumentInfo.is()) + { + xOldDocInfo = getDocumentInfo(); + const Reference<util::XCloneable> xCloneable(xOldDocInfo, + UNO_QUERY_THROW); + const Reference<document::XDocumentInfo> xNewDocInfo( + xCloneable->createClone(), UNO_QUERY_THROW); + const Reference<document::XDocumentPropertiesSupplier> xDPS( + xNewDocInfo, UNO_QUERY_THROW); + const Reference<document::XDocumentProperties> xNewDocProps( + xDPS->getDocumentProperties()); + m_pData->m_xDocumentProperties = xNewDocProps; + m_pData->m_xDocumentInfo = xNewDocInfo; + } + else // try not to create DocumentInfo if it does not exist... + { + const Reference<util::XCloneable> xCloneable(xOldDocProps, + UNO_QUERY_THROW); + const Reference<document::XDocumentProperties> xNewDocProps( + xCloneable->createClone(), UNO_QUERY_THROW); + m_pData->m_xDocumentProperties = xNewDocProps; + } + } + + sal_Bool bRet = m_pData->m_pObjectShell->APISaveAs_Impl( sURL, aParams ); + + if ( bCopyTo ) + { + // restore DocumentInfo if a copy was created + m_pData->m_xDocumentProperties = xOldDocProps; + m_pData->m_xDocumentInfo = xOldDocInfo; + } + + uno::Reference < task::XInteractionHandler > xHandler; + SFX_ITEMSET_ARG( aParams, pItem, SfxUnoAnyItem, SID_INTERACTIONHANDLER, sal_False); + if ( pItem ) + pItem->GetValue() >>= xHandler; + + DELETEZ( aParams ); + + sal_uInt32 nErrCode = m_pData->m_pObjectShell->GetErrorCode(); + if ( !bRet && !nErrCode ) + { + m_pData->m_pObjectShell->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Storing has failed, no error is set!" ) ) ); + nErrCode = ERRCODE_IO_CANTWRITE; + } + m_pData->m_pObjectShell->ResetError(); + + if ( bRet ) + { + if ( nErrCode ) + { + // must be a warning - use Interactionhandler if possible or abandone + if ( xHandler.is() ) + { + // TODO/LATER: a general way to set the error context should be available + SfxErrorContext aEc( ERRCTX_SFX_SAVEASDOC, m_pData->m_pObjectShell->GetTitle() ); + + ::com::sun::star::task::ErrorCodeRequest aErrorCode; + aErrorCode.ErrCode = nErrCode; + SfxMedium::CallApproveHandler( xHandler, uno::makeAny( aErrorCode ), sal_False ); + } + } + + m_pData->m_pObjectShell->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Storing succeeded!" ) ) ); + if ( !bSaveTo ) + { + m_pData->m_aPreusedFilterName = GetMediumFilterName_Impl(); + m_pData->m_pObjectShell->SetModifyPasswordEntered(); + + SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_SAVEASDOCDONE, GlobalEventConfig::GetEventName(STR_EVENT_SAVEASDOCDONE), m_pData->m_pObjectShell ) ); + } + else + { + m_pData->m_pObjectShell->SetModifyPasswordHash( nOldModifyPasswordHash ); + m_pData->m_pObjectShell->SetModifyPasswordInfo( aOldModifyPasswordInfo ); + + SFX_APP()->NotifyEvent( SfxEventHint( SFX_EVENT_SAVETODOCDONE, GlobalEventConfig::GetEventName(STR_EVENT_SAVETODOCDONE), m_pData->m_pObjectShell ) ); + } + } + else + { + // let the logring be stored to the related file + m_pData->m_pObjectShell->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Storing failed!" ) ) ); + m_pData->m_pObjectShell->StoreLog(); + + m_pData->m_pObjectShell->SetModifyPasswordHash( nOldModifyPasswordHash ); + m_pData->m_pObjectShell->SetModifyPasswordInfo( aOldModifyPasswordInfo ); + + + SFX_APP()->NotifyEvent( SfxEventHint( bSaveTo ? SFX_EVENT_SAVETODOCFAILED : SFX_EVENT_SAVEASDOCFAILED, GlobalEventConfig::GetEventName( bSaveTo ? STR_EVENT_SAVETODOCFAILED : STR_EVENT_SAVEASDOCFAILED), + m_pData->m_pObjectShell ) ); + + throw task::ErrorCodeIOException( ::rtl::OUString(), uno::Reference< uno::XInterface >(), nErrCode ); + } + } +} + +//******************************************************************************************************** + +void SfxBaseModel::postEvent_Impl( ::rtl::OUString aName ) +{ + // object already disposed? + if ( impl_isDisposed() ) + return; + + DBG_ASSERT( aName.getLength(), "Empty event name!" ); + if (!aName.getLength()) + return; + + ::cppu::OInterfaceContainerHelper* pIC = m_pData->m_aInterfaceContainer.getContainer( + ::getCppuType((const uno::Reference< XDOCEVENTLISTENER >*)0) ); + if( pIC ) + + { +#ifdef DBG_UTIL + ByteString aTmp( "SfxEvent: "); + aTmp += ByteString( String(aName), RTL_TEXTENCODING_UTF8 ); + DBG_TRACE( aTmp.GetBuffer() ); +#endif + document::EventObject aEvent( (frame::XModel *)this, aName ); + ::cppu::OInterfaceContainerHelper aIC( m_aMutex ); + uno::Sequence < uno::Reference < uno::XInterface > > aElements = pIC->getElements(); + for ( sal_Int32 nElem=0; nElem<aElements.getLength(); nElem++ ) + aIC.addInterface( aElements[nElem] ); + ::cppu::OInterfaceIteratorHelper aIt( aIC ); + while( aIt.hasMoreElements() ) + { + try + { + ((XDOCEVENTLISTENER *)aIt.next())->notifyEvent( aEvent ); + } + catch( uno::RuntimeException& ) + { + aIt.remove(); + } + } + } +} + +uno::Reference < container::XIndexAccess > SAL_CALL SfxBaseModel::getViewData() throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + if ( m_pData->m_pObjectShell.Is() && !m_pData->m_contViewData.is() ) + { + SfxViewFrame *pActFrame = SfxViewFrame::Current(); + if ( !pActFrame || pActFrame->GetObjectShell() != m_pData->m_pObjectShell ) + pActFrame = SfxViewFrame::GetFirst( m_pData->m_pObjectShell ); + + if ( !pActFrame || !pActFrame->GetViewShell() ) + // currently no frame for this document at all or View is under construction + return uno::Reference < container::XIndexAccess >(); + + m_pData->m_contViewData = Reference < container::XIndexAccess >( + ::comphelper::getProcessServiceFactory()->createInstance( + DEFINE_CONST_UNICODE("com.sun.star.document.IndexedPropertyValues") ), + uno::UNO_QUERY ); + + if ( !m_pData->m_contViewData.is() ) + { + // error: no container class available! + return uno::Reference < container::XIndexAccess >(); + } + + uno::Reference < container::XIndexContainer > xCont( m_pData->m_contViewData, uno::UNO_QUERY ); + sal_Int32 nCount = 0; + uno::Sequence < beans::PropertyValue > aSeq; + ::com::sun::star::uno::Any aAny; + for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst( m_pData->m_pObjectShell ); pFrame; + pFrame = SfxViewFrame::GetNext( *pFrame, m_pData->m_pObjectShell ) ) + { + BOOL bIsActive = ( pFrame == pActFrame ); + pFrame->GetViewShell()->WriteUserDataSequence( aSeq ); + aAny <<= aSeq; + xCont->insertByIndex( bIsActive ? 0 : nCount, aAny ); + nCount++; + } + } + + return m_pData->m_contViewData; +} + +void SAL_CALL SfxBaseModel::setViewData( const uno::Reference < container::XIndexAccess >& aData ) throw(::com::sun::star::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + m_pData->m_contViewData = aData; +} + +/** calls all XEventListeners */ +void SfxBaseModel::notifyEvent( const ::com::sun::star::document::EventObject& aEvent ) const +{ + // object already disposed? + if ( impl_isDisposed() ) + return; + + ::cppu::OInterfaceContainerHelper* pIC = m_pData->m_aInterfaceContainer.getContainer( + ::getCppuType((const uno::Reference< XDOCEVENTLISTENER >*)0) ); + if( pIC ) + + { + ::cppu::OInterfaceIteratorHelper aIt( *pIC ); + while( aIt.hasMoreElements() ) + { + try + { + ((XDOCEVENTLISTENER *)aIt.next())->notifyEvent( aEvent ); + } + catch( uno::RuntimeException& ) + { + aIt.remove(); + } + } + } +} + +/** returns true if someone added a XEventListener to this XEventBroadcaster */ +sal_Bool SfxBaseModel::hasEventListeners() const +{ + return !impl_isDisposed() && (NULL != m_pData->m_aInterfaceContainer.getContainer( ::getCppuType((const uno::Reference< XDOCEVENTLISTENER >*)0) ) ); +} + +void SAL_CALL SfxBaseModel::addPrintJobListener( const uno::Reference< view::XPrintJobListener >& xListener ) throw (uno::RuntimeException) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + + if ( impl_getPrintHelper() ) + { + uno::Reference < view::XPrintJobBroadcaster > xPJB( m_pData->m_xPrintable, uno::UNO_QUERY ); + if ( xPJB.is() ) + xPJB->addPrintJobListener( xListener ); + } +// else +// m_pData->m_aInterfaceContainer.addInterface( ::getCppuType((const uno::Reference< view::XPrintJobListener >*)0), xListener ); +} + +void SAL_CALL SfxBaseModel::removePrintJobListener( const uno::Reference< view::XPrintJobListener >& xListener ) throw (uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + if ( impl_getPrintHelper() ) + { + uno::Reference < view::XPrintJobBroadcaster > xPJB( m_pData->m_xPrintable, uno::UNO_QUERY ); + if ( xPJB.is() ) + xPJB->removePrintJobListener( xListener ); + } +// else +// m_pData->m_aInterfaceContainer.addInterface( ::getCppuType((const uno::Reference< view::XPrintJobListener >*)0), xListener ); +} + +// simple declaration of class SvObject is enough +// the corresponding <so3/iface.hxx> cannon be included because it provides +// declaration of class SvBorder that conflicts with ../../inc/viewfrm.hxx +class SvObject; +sal_Int64 SAL_CALL SfxBaseModel::getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw(::com::sun::star::uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( GetObjectShell() ) + { + SvGlobalName aName( aIdentifier ); + if ( aName == SvGlobalName( SO3_GLOBAL_CLASSID ) ) + return (sal_Int64)(sal_IntPtr)(SvObject*)GetObjectShell(); + else if ( aName == SvGlobalName( SFX_GLOBAL_CLASSID ) ) + return (sal_Int64)(sal_IntPtr)(SfxObjectShell*)GetObjectShell(); + } + + return 0; +} + +//____________________________________________________________________________________________________ +// XDocumentSubStorageSupplier +//____________________________________________________________________________________________________ + +void SfxBaseModel::ListenForStorage_Impl( const uno::Reference< embed::XStorage >& xStorage ) +{ + uno::Reference< util::XModifiable > xModifiable( xStorage, uno::UNO_QUERY ); + if ( xModifiable.is() ) + { + if ( !m_pData->m_pStorageModifyListen.is() ) + { + m_pData->m_pStorageModifyListen = new ::sfx2::DocumentStorageModifyListener( *m_pData, Application::GetSolarMutex() ); + } + + // no need to deregister the listening for old storage since it should be disposed automatically + xModifiable->addModifyListener( m_pData->m_pStorageModifyListen.get() ); + } +} + +uno::Reference< XSTORAGE > SAL_CALL SfxBaseModel::getDocumentSubStorage( const ::rtl::OUString& aStorageName, sal_Int32 nMode ) + throw ( uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + uno::Reference< XSTORAGE > xResult; + if ( m_pData->m_pObjectShell.Is() ) + { + uno::Reference< embed::XStorage > xStorage = m_pData->m_pObjectShell->GetStorage(); + if ( xStorage.is() ) + { + try + { + xResult = xStorage->openStorageElement( aStorageName, nMode ); + } + catch ( uno::Exception& ) + { + } + } + } + + return xResult; +} + +Sequence< ::rtl::OUString > SAL_CALL SfxBaseModel::getDocumentSubStoragesNames() + throw ( io::IOException, + RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + + Sequence< ::rtl::OUString > aResult; + sal_Int32 nResultSize = 0; + sal_Bool bSuccess = sal_False; + if ( m_pData->m_pObjectShell.Is() ) + { + uno::Reference < embed::XStorage > xStorage = m_pData->m_pObjectShell->GetStorage(); + uno::Reference < container::XNameAccess > xAccess( xStorage, uno::UNO_QUERY ); + if ( xAccess.is() ) + { + Sequence< ::rtl::OUString > aTemp = xAccess->getElementNames(); + for ( sal_Int32 n = 0; n < aTemp.getLength(); n++ ) + { + if ( xStorage->isStorageElement( aTemp[n] ) ) + { + aResult.realloc( ++nResultSize ); + aResult[ nResultSize - 1 ] = aTemp[n]; + } + } + + bSuccess = sal_True; + } + } + + if ( !bSuccess ) + throw io::IOException(); + + return aResult; +} + +//____________________________________________________________________________________________________ +// XScriptProviderSupplier +//____________________________________________________________________________________________________ + + +uno::Reference< script::provider::XScriptProvider > SAL_CALL SfxBaseModel::getScriptProvider() + throw ( uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + + uno::Reference< script::provider::XScriptProvider > xScriptProvider; + + ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); + Reference< script::provider::XScriptProviderFactory > xScriptProviderFactory( + aContext.getSingleton( "com.sun.star.script.provider.theMasterScriptProviderFactory" ), uno::UNO_QUERY_THROW ); + + try + { + Reference< XScriptInvocationContext > xScriptContext( this ); + xScriptProvider.set( xScriptProviderFactory->createScriptProvider( makeAny( xScriptContext ) ), uno::UNO_SET_THROW ); + } + catch( const uno::RuntimeException& ) + { + throw; + } + catch( const lang::IllegalArgumentException& ) + { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString(), + *this, + ::cppu::getCaughtException() + ); + } + + return xScriptProvider; +} + +//____________________________________________________________________________________________________ +// XUIConfigurationManagerSupplier +//____________________________________________________________________________________________________ + +rtl::OUString SfxBaseModel::getRuntimeUID() const +{ + OSL_ENSURE( m_pData->m_sRuntimeUID.getLength() > 0, + "SfxBaseModel::getRuntimeUID - ID is empty!" ); + return m_pData->m_sRuntimeUID; +} + +sal_Bool SfxBaseModel::hasValidSignatures() const +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( m_pData->m_pObjectShell.Is() ) + return ( m_pData->m_pObjectShell->ImplGetSignatureState( sal_False ) == SIGNATURESTATE_SIGNATURES_OK ); + return sal_False; +} + +static void GetCommandFromSequence( rtl::OUString& rCommand, sal_Int32& nIndex, const uno::Sequence< beans::PropertyValue >& rSeqPropValue ) +{ + rtl::OUString aCommand; + nIndex = -1; + + for ( sal_Int32 i = 0; i < rSeqPropValue.getLength(); i++ ) + { + if ( rSeqPropValue[i].Name.equalsAsciiL( "Command", 7 )) + { + rSeqPropValue[i].Value >>= rCommand; + nIndex = i; + return; + } + } +} + +static void ConvertSlotsToCommands( SfxObjectShell* pDoc, uno::Reference< container::XIndexContainer >& rToolbarDefinition ) +{ + if ( pDoc ) + { + Any aAny; + SfxModule* pModule( pDoc->GetFactory().GetModule() ); + rtl::OUString aSlotCmd( RTL_CONSTASCII_USTRINGPARAM( "slot:" )); + rtl::OUString aUnoCmd( RTL_CONSTASCII_USTRINGPARAM( ".uno:" )); + uno::Sequence< beans::PropertyValue > aSeqPropValue; + + for ( sal_Int32 i = 0; i < rToolbarDefinition->getCount(); i++ ) + { + sal_Int32 nIndex( -1 ); + rtl::OUString aCommand; + + if ( rToolbarDefinition->getByIndex( i ) >>= aSeqPropValue ) + { + GetCommandFromSequence( aCommand, nIndex, aSeqPropValue ); + if ( nIndex >= 0 && ( aCommand.indexOf( aSlotCmd ) == 0 )) + { + rtl::OUString aSlot( aCommand.copy( 5 )); + + // We have to replace the old "slot-Command" with our new ".uno:-Command" + const SfxSlot* pSlot = pModule->GetSlotPool()->GetSlot( USHORT( aSlot.toInt32() )); + if ( pSlot ) + { + rtl::OUStringBuffer aStrBuf( aUnoCmd ); + aStrBuf.appendAscii( pSlot->GetUnoName() ); + + aCommand = aStrBuf.makeStringAndClear(); + aSeqPropValue[nIndex].Value <<= aCommand; + rToolbarDefinition->replaceByIndex( i, Any( aSeqPropValue )); + } + } + } + } + } +} + +uno::Reference< ui::XUIConfigurationManager > SAL_CALL SfxBaseModel::getUIConfigurationManager() + throw ( uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + + if ( !m_pData->m_xUIConfigurationManager.is() ) + { + uno::Reference< ui::XUIConfigurationManager > xNewUIConfMan( + ::comphelper::getProcessServiceFactory()->createInstance( + ::rtl::OUString::createFromAscii( "com.sun.star.ui.UIConfigurationManager" )), + uno::UNO_QUERY ); + + Reference< ui::XUIConfigurationStorage > xUIConfigStorage( xNewUIConfMan, uno::UNO_QUERY ); + if ( xUIConfigStorage.is() ) + { + uno::Reference< XSTORAGE > xConfigStorage; + + rtl::OUString aUIConfigFolderName( RTL_CONSTASCII_USTRINGPARAM( "Configurations2" )); + // First try to open with READWRITE and then READ + xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READWRITE ); + if ( xConfigStorage.is() ) + { + rtl::OUString aMediaTypeProp( RTL_CONSTASCII_USTRINGPARAM( "MediaType" )); + rtl::OUString aUIConfigMediaType( + RTL_CONSTASCII_USTRINGPARAM( "application/vnd.sun.xml.ui.configuration" ) ); + rtl::OUString aMediaType; + uno::Reference< beans::XPropertySet > xPropSet( xConfigStorage, uno::UNO_QUERY ); + Any a = xPropSet->getPropertyValue( aMediaTypeProp ); + if ( !( a >>= aMediaType ) || ( aMediaType.getLength() == 0 )) + { + a <<= aUIConfigMediaType; + xPropSet->setPropertyValue( aMediaTypeProp, a ); + } + } + else + xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READ ); + + // initialize ui configuration manager with document substorage + xUIConfigStorage->setStorage( xConfigStorage ); + + // embedded objects did not support local configuration data until OOo 3.0, so there's nothing to + // migrate + if ( m_pData->m_pObjectShell->GetCreateMode() != SFX_CREATE_MODE_EMBEDDED ) + { + // Import old UI configuration from OOo 1.x + uno::Reference< XSTORAGE > xOOo1ConfigStorage; + rtl::OUString aOOo1UIConfigFolderName( RTL_CONSTASCII_USTRINGPARAM( "Configurations" )); + + // Try to open with READ + xOOo1ConfigStorage = getDocumentSubStorage( aOOo1UIConfigFolderName, embed::ElementModes::READ ); + if ( xOOo1ConfigStorage.is() ) + { + uno::Reference< lang::XMultiServiceFactory > xServiceMgr( ::comphelper::getProcessServiceFactory() ); + uno::Sequence< uno::Reference< container::XIndexContainer > > rToolbars; + + sal_Bool bImported = UIConfigurationImporterOOo1x::ImportCustomToolbars( + xNewUIConfMan, rToolbars, xServiceMgr, xOOo1ConfigStorage ); + if ( bImported ) + { + SfxObjectShell* pObjShell = SfxBaseModel::GetObjectShell(); + + char aNum[] = "private:resource/toolbar/custom_OOo1x_0"; + char aTitle[] = "Toolbar 0"; + sal_Int32 nNumIndex = strlen( aNum )-1; + sal_Int32 nTitleIndex = strlen( aTitle )-1; + for ( sal_Int32 i = 0; i < rToolbars.getLength(); i++ ) + { + aNum[nNumIndex]++; + aTitle[nTitleIndex]++; + + rtl::OUString aCustomTbxName( RTL_CONSTASCII_USTRINGPARAM( aNum )); + rtl::OUString aCustomTbxTitle( RTL_CONSTASCII_USTRINGPARAM( aTitle )); + + uno::Reference< container::XIndexContainer > xToolbar = rToolbars[i]; + ConvertSlotsToCommands( pObjShell, xToolbar ); + if ( !xNewUIConfMan->hasSettings( aCustomTbxName )) + { + // Set UIName for the toolbar with container property + uno::Reference< beans::XPropertySet > xPropSet( xToolbar, UNO_QUERY ); + if ( xPropSet.is() ) + { + try + { + rtl::OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( "UIName" )); + Any aAny( aCustomTbxTitle ); + xPropSet->setPropertyValue( aPropName, aAny ); + } + catch ( beans::UnknownPropertyException& ) + { + } + } + + uno::Reference< container::XIndexAccess > xToolbarData( xToolbar, uno::UNO_QUERY ); + xNewUIConfMan->insertSettings( aCustomTbxName, xToolbarData ); + uno::Reference< ui::XUIConfigurationPersistence > xPersist( xNewUIConfMan, uno::UNO_QUERY ); + xPersist->store(); + } + } + } + } + } + } + + m_pData->m_xUIConfigurationManager = xNewUIConfMan; + } + + return m_pData->m_xUIConfigurationManager; +} + +//____________________________________________________________________________________________________ +// XVisualObject +//____________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::setVisualAreaSize( sal_Int64 nAspect, const awt::Size& aSize ) + throw ( lang::IllegalArgumentException, + embed::WrongStateException, + uno::Exception, + uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + + if ( !m_pData->m_pObjectShell.Is() ) + throw uno::Exception(); // TODO: error handling + + SfxViewFrame* pViewFrm = SfxViewFrame::GetFirst( m_pData->m_pObjectShell, sal_False ); + if ( pViewFrm && m_pData->m_pObjectShell->GetCreateMode() == SFX_CREATE_MODE_EMBEDDED && !pViewFrm->GetFrame().IsInPlace() ) + { + Window* pWindow = VCLUnoHelper::GetWindow( pViewFrm->GetFrame().GetFrameInterface()->getContainerWindow() ); + Size aWinSize = pWindow->GetSizePixel(); + awt::Size aCurrent = getVisualAreaSize( nAspect ); + Size aDiff( aSize.Width-aCurrent.Width, aSize.Height-aCurrent.Height ); + Size aWrongDiff = OutputDevice::LogicToLogic( aDiff , m_pData->m_pObjectShell->GetMapUnit(), pWindow->GetMapMode() ); + aDiff = pViewFrm->GetViewShell()->GetWindow()->LogicToPixel( aDiff ); + aWinSize.Width() += aDiff.Width(); + aWinSize.Height() += aDiff.Height(); + pWindow->SetSizePixel( aWinSize ); + } + else + { + Rectangle aTmpRect = m_pData->m_pObjectShell->GetVisArea( ASPECT_CONTENT ); + aTmpRect.SetSize( Size( aSize.Width, aSize.Height ) ); + m_pData->m_pObjectShell->SetVisArea( aTmpRect ); + } +} + +awt::Size SAL_CALL SfxBaseModel::getVisualAreaSize( sal_Int64 /*nAspect*/ ) + throw ( lang::IllegalArgumentException, + embed::WrongStateException, + uno::Exception, + uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + if ( !m_pData->m_pObjectShell.Is() ) + throw uno::Exception(); // TODO: error handling + + Rectangle aTmpRect = m_pData->m_pObjectShell->GetVisArea( ASPECT_CONTENT ); + +#if 0 + Window* pWindow = NULL; + SfxViewFrame* pViewFrm = m_pData->m_pObjectShell.Is() ? + SfxViewFrame::GetFirst( m_pData->m_pObjectShell, 0, sal_False ) : 0; + + if ( pWindow ) + { + MapMode aInternalMapMode( pViewFrm->GetWindow().GetMapMode() ); + MapMode aExternalMapMode( m_pData->m_pObjectShell->GetMapUnit() ); + + aTmpRect = OutputDevice::LogicToLogic( aTmpRect, aInternalMapMode, aExternalMapMode ); + } +#endif + + return awt::Size( aTmpRect.GetWidth(), aTmpRect.GetHeight() ); +} + + +sal_Int32 SAL_CALL SfxBaseModel::getMapUnit( sal_Int64 /*nAspect*/ ) + throw ( uno::Exception, + uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + if ( !m_pData->m_pObjectShell.Is() ) + throw uno::Exception(); // TODO: error handling + + return VCLUnoHelper::VCL2UnoEmbedMapUnit( m_pData->m_pObjectShell->GetMapUnit() ); +} + +embed::VisualRepresentation SAL_CALL SfxBaseModel::getPreferredVisualRepresentation( ::sal_Int64 /*nAspect*/ ) + throw ( lang::IllegalArgumentException, + embed::WrongStateException, + uno::Exception, + uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + + datatransfer::DataFlavor aDataFlavor( + ::rtl::OUString::createFromAscii( "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" ), + ::rtl::OUString::createFromAscii( "GDIMetaFile" ), + ::getCppuType( (const uno::Sequence< sal_Int8 >*) NULL ) ); + + embed::VisualRepresentation aVisualRepresentation; + aVisualRepresentation.Data = getTransferData( aDataFlavor ); + aVisualRepresentation.Flavor = aDataFlavor; + + return aVisualRepresentation; +} + +//____________________________________________________________________________________________________ +// XStorageBasedDocument +//____________________________________________________________________________________________________ + +void SAL_CALL SfxBaseModel::loadFromStorage( const uno::Reference< XSTORAGE >& xStorage, + const uno::Sequence< beans::PropertyValue >& aMediaDescriptor ) + throw ( lang::IllegalArgumentException, + DOUBLEINITIALIZATIONEXCEPTION, + IOEXCEPTION, + EXCEPTION, + uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + if ( IsInitialized() ) + throw ::com::sun::star::frame::DoubleInitializationException( ::rtl::OUString(), *this ); + + // after i36090 is fixed the pool from object shell can be used + // SfxAllItemSet aSet( m_pData->m_pObjectShell->GetPool() ); + SfxAllItemSet aSet( SFX_APP()->GetPool() ); + + // the BaseURL is part of the ItemSet + SfxMedium* pMedium = new SfxMedium( xStorage, String() ); + TransformParameters( SID_OPENDOC, aMediaDescriptor, aSet ); + pMedium->GetItemSet()->Put( aSet ); + + // allow to use an interactionhandler (if there is one) + pMedium->UseInteractionHandler( TRUE ); + + SFX_ITEMSET_ARG( &aSet, pTemplateItem, SfxBoolItem, SID_TEMPLATE, sal_False); + BOOL bTemplate = pTemplateItem && pTemplateItem->GetValue(); + m_pData->m_pObjectShell->SetActivateEvent_Impl( bTemplate ? SFX_EVENT_CREATEDOC : SFX_EVENT_OPENDOC ); + m_pData->m_pObjectShell->Get_Impl()->bOwnsStorage = FALSE; + + // load document + if ( !m_pData->m_pObjectShell->DoLoad(pMedium) ) + { + sal_uInt32 nError = m_pData->m_pObjectShell->GetErrorCode(); + throw task::ErrorCodeIOException( ::rtl::OUString(), + uno::Reference< uno::XInterface >(), + nError ? nError : ERRCODE_IO_CANTREAD ); + } +} + +void SAL_CALL SfxBaseModel::storeToStorage( const uno::Reference< XSTORAGE >& xStorage, + const uno::Sequence< beans::PropertyValue >& aMediaDescriptor ) + throw ( lang::IllegalArgumentException, + IOEXCEPTION, + EXCEPTION, + uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + + uno::Reference< XSTORAGE > xResult; + if ( !m_pData->m_pObjectShell.Is() ) + throw IOEXCEPTION(); // TODO: + + SfxAllItemSet aSet( m_pData->m_pObjectShell->GetPool() ); + TransformParameters( SID_SAVEASDOC, aMediaDescriptor, aSet ); + + // TODO/LATER: may be a special URL "private:storage" should be used + SFX_ITEMSET_ARG( &aSet, pItem, SfxStringItem, SID_FILTER_NAME, sal_False ); + sal_Int32 nVersion = SOFFICE_FILEFORMAT_CURRENT; + if( pItem ) + { + String aFilterName = pItem->GetValue(); + const SfxFilter* pFilter = SFX_APP()->GetFilterMatcher().GetFilter4FilterName( aFilterName ); + if ( pFilter && pFilter->UsesStorage() ) + nVersion = pFilter->GetVersion(); + } + + sal_Bool bSuccess = sal_False; + if ( xStorage == m_pData->m_pObjectShell->GetStorage() ) + { + // storing to the own storage + bSuccess = m_pData->m_pObjectShell->DoSave(); + } + else + { + // TODO/LATER: if the provided storage has some data inside the storing might fail, probably the storage must be truncated + // TODO/LATER: is it possible to have a template here? + m_pData->m_pObjectShell->SetupStorage( xStorage, nVersion, sal_False ); + + // BaseURL is part of the ItemSet + SfxMedium aMedium( xStorage, String(), &aSet ); + aMedium.CanDisposeStorage_Impl( FALSE ); + if ( aMedium.GetFilter() ) + { + // storing without a valid filter will often crash + bSuccess = m_pData->m_pObjectShell->DoSaveObjectAs( aMedium, TRUE ); + m_pData->m_pObjectShell->DoSaveCompleted( NULL ); + } + } + + sal_uInt32 nError = m_pData->m_pObjectShell->GetErrorCode(); + m_pData->m_pObjectShell->ResetError(); + + // the warnings are currently not transported + if ( !bSuccess ) + { + throw task::ErrorCodeIOException( ::rtl::OUString(), + uno::Reference< uno::XInterface >(), + nError ? nError : ERRCODE_IO_GENERAL ); + } +} + +void SAL_CALL SfxBaseModel::switchToStorage( const uno::Reference< XSTORAGE >& xStorage ) + throw ( lang::IllegalArgumentException, + IOEXCEPTION, + EXCEPTION, + uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + + uno::Reference< XSTORAGE > xResult; + if ( !m_pData->m_pObjectShell.Is() ) + throw IOEXCEPTION(); // TODO: + + // the persistence should be switched only if the storage is different + if ( xStorage != m_pData->m_pObjectShell->GetStorage() + && !m_pData->m_pObjectShell->SwitchPersistance( xStorage ) ) + { + sal_uInt32 nError = m_pData->m_pObjectShell->GetErrorCode(); + throw task::ErrorCodeIOException( ::rtl::OUString(), + uno::Reference< uno::XInterface >(), + nError ? nError : ERRCODE_IO_GENERAL ); + } + + m_pData->m_pObjectShell->Get_Impl()->bOwnsStorage = FALSE; +} + +uno::Reference< XSTORAGE > SAL_CALL SfxBaseModel::getDocumentStorage() + throw ( IOEXCEPTION, + EXCEPTION, + uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + + uno::Reference< XSTORAGE > xResult; + if ( !m_pData->m_pObjectShell.Is() ) + throw IOEXCEPTION(); // TODO + + return m_pData->m_pObjectShell->GetStorage(); +} + +void SAL_CALL SfxBaseModel::addStorageChangeListener( + const uno::Reference< document::XStorageChangeListener >& xListener ) + throw ( uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + + m_pData->m_aInterfaceContainer.addInterface( + ::getCppuType((const uno::Reference< document::XStorageChangeListener >*)0), xListener ); +} + +void SAL_CALL SfxBaseModel::removeStorageChangeListener( + const uno::Reference< document::XStorageChangeListener >& xListener ) + throw ( uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + + m_pData->m_aInterfaceContainer.removeInterface( + ::getCppuType((const uno::Reference< document::XStorageChangeListener >*)0), xListener ); +} + +#include "printhelper.hxx" +bool SfxBaseModel::impl_getPrintHelper() +{ + if ( m_pData->m_xPrintable.is() ) + return true; + m_pData->m_xPrintable = new SfxPrintHelper(); + uno::Reference < lang::XInitialization > xInit( m_pData->m_xPrintable, uno::UNO_QUERY ); + uno::Sequence < uno::Any > aValues(1); + aValues[0] <<= uno::Reference < frame::XModel > (static_cast< frame::XModel* >(this), uno::UNO_QUERY ); + xInit->initialize( aValues ); + uno::Reference < view::XPrintJobBroadcaster > xBrd( m_pData->m_xPrintable, uno::UNO_QUERY ); + xBrd->addPrintJobListener( new SfxPrintHelperListener_Impl( m_pData ) ); + return true; +} + +//============================================================================= +// css.frame.XModule + void SAL_CALL SfxBaseModel::setIdentifier(const ::rtl::OUString& Identifier) + throw (css::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + m_pData->m_sModuleIdentifier = Identifier; +} + +//============================================================================= +// css.frame.XModule + ::rtl::OUString SAL_CALL SfxBaseModel::getIdentifier() + throw (css::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + if (m_pData->m_sModuleIdentifier.getLength() > 0) + return m_pData->m_sModuleIdentifier; + if (m_pData->m_pObjectShell) + return m_pData->m_pObjectShell->GetFactory().GetDocumentServiceName(); + return ::rtl::OUString(); +} + +//============================================================================= +css::uno::Reference< css::frame::XTitle > SfxBaseModel::impl_getTitleHelper () +{ + SfxModelGuard aGuard( *this ); + + if ( ! m_pData->m_xTitleHelper.is ()) + { + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = ::comphelper::getProcessServiceFactory (); + css::uno::Reference< css::frame::XUntitledNumbers > xDesktop(xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::frame::XModel > xThis (static_cast< css::frame::XModel* >(this), css::uno::UNO_QUERY_THROW); + + ::framework::TitleHelper* pHelper = new ::framework::TitleHelper(xSMGR); + m_pData->m_xTitleHelper = css::uno::Reference< css::frame::XTitle >(static_cast< ::cppu::OWeakObject* >(pHelper), css::uno::UNO_QUERY_THROW); + pHelper->setOwner (xThis ); + pHelper->connectWithUntitledNumbers (xDesktop); + } + + return m_pData->m_xTitleHelper; +} + +//============================================================================= +css::uno::Reference< css::frame::XUntitledNumbers > SfxBaseModel::impl_getUntitledHelper () +{ + SfxModelGuard aGuard( *this ); + + if ( ! m_pData->m_xNumberedControllers.is ()) + { + css::uno::Reference< css::frame::XModel > xThis (static_cast< css::frame::XModel* >(this), css::uno::UNO_QUERY_THROW); + ::comphelper::NumberedCollection* pHelper = new ::comphelper::NumberedCollection(); + + m_pData->m_xNumberedControllers = css::uno::Reference< css::frame::XUntitledNumbers >(static_cast< ::cppu::OWeakObject* >(pHelper), css::uno::UNO_QUERY_THROW); + + pHelper->setOwner (xThis); + pHelper->setUntitledPrefix (::rtl::OUString::createFromAscii(" : ")); + } + + return m_pData->m_xNumberedControllers; +} + +//============================================================================= +// css.frame.XTitle +::rtl::OUString SAL_CALL SfxBaseModel::getTitle() + throw (css::uno::RuntimeException) +{ + // SYNCHRONIZED -> + SfxModelGuard aGuard( *this ); + + ::rtl::OUString aResult = impl_getTitleHelper()->getTitle (); + if ( m_pData->m_pObjectShell ) + { + SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium(); + if ( pMedium ) + { + SFX_ITEMSET_ARG( pMedium->GetItemSet(), pRepairedDocItem, SfxBoolItem, SID_REPAIRPACKAGE, sal_False ); + if ( pRepairedDocItem && pRepairedDocItem->GetValue() ) + aResult += String( SfxResId(STR_REPAIREDDOCUMENT) ); + } + + if ( m_pData->m_pObjectShell->IsReadOnlyUI() || (m_pData->m_pObjectShell->GetMedium() && m_pData->m_pObjectShell->GetMedium()->IsReadOnly()) ) + aResult += ::rtl::OUString( String( SfxResId(STR_READONLY) ) ); + else if ( m_pData->m_pObjectShell->IsDocShared() ) + aResult += ::rtl::OUString( String( SfxResId(STR_SHARED) ) ); + + if ( m_pData->m_pObjectShell->GetDocumentSignatureState() == SIGNATURESTATE_SIGNATURES_OK ) + aResult += String( SfxResId( RID_XMLSEC_DOCUMENTSIGNED ) ); + } + + return aResult; +} + +//============================================================================= +// css.frame.XTitle +void SAL_CALL SfxBaseModel::setTitle( const ::rtl::OUString& sTitle ) + throw (css::uno::RuntimeException) +{ + // SYNCHRONIZED -> + SfxModelGuard aGuard( *this ); + + impl_getTitleHelper()->setTitle (sTitle); +} + +//============================================================================= +// css.frame.XTitleChangeBroadcaster +void SAL_CALL SfxBaseModel::addTitleChangeListener( const css::uno::Reference< css::frame::XTitleChangeListener >& xListener ) + throw (css::uno::RuntimeException) +{ + // SYNCHRONIZED -> + SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING ); + + css::uno::Reference< css::frame::XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper(), css::uno::UNO_QUERY); + if (xBroadcaster.is ()) + xBroadcaster->addTitleChangeListener (xListener); +} + +//============================================================================= +// css.frame.XTitleChangeBroadcaster +void SAL_CALL SfxBaseModel::removeTitleChangeListener( const css::uno::Reference< css::frame::XTitleChangeListener >& xListener ) + throw (css::uno::RuntimeException) +{ + // SYNCHRONIZED -> + SfxModelGuard aGuard( *this ); + + css::uno::Reference< css::frame::XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper(), css::uno::UNO_QUERY); + if (xBroadcaster.is ()) + xBroadcaster->removeTitleChangeListener (xListener); +} + +//============================================================================= +// css.frame.XUntitledNumbers +::sal_Int32 SAL_CALL SfxBaseModel::leaseNumber( const css::uno::Reference< css::uno::XInterface >& xComponent ) + throw (css::lang::IllegalArgumentException, + css::uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + + return impl_getUntitledHelper ()->leaseNumber (xComponent); +} + +//============================================================================= +// css.frame.XUntitledNumbers +void SAL_CALL SfxBaseModel::releaseNumber( ::sal_Int32 nNumber ) + throw (css::lang::IllegalArgumentException, + css::uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + impl_getUntitledHelper ()->releaseNumber (nNumber); +} + +//============================================================================= +// css.frame.XUntitledNumbers +void SAL_CALL SfxBaseModel::releaseNumberForComponent( const css::uno::Reference< css::uno::XInterface >& xComponent ) + throw (css::lang::IllegalArgumentException, + css::uno::RuntimeException ) +{ + SfxModelGuard aGuard( *this ); + impl_getUntitledHelper ()->releaseNumberForComponent (xComponent); +} + +//============================================================================= +// css.frame.XUntitledNumbers +::rtl::OUString SAL_CALL SfxBaseModel::getUntitledPrefix() + throw (css::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + return impl_getUntitledHelper ()->getUntitledPrefix (); +} + +//============================================================================= +// css::frame::XModel2 +css::uno::Reference< css::container::XEnumeration > SAL_CALL SfxBaseModel::getControllers() + throw (css::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + sal_Int32 c = m_pData->m_seqControllers.getLength(); + sal_Int32 i = 0; + css::uno::Sequence< css::uno::Any > lEnum(c); + for (i=0; i<c; ++i) + lEnum[i] <<= m_pData->m_seqControllers[i]; + + ::comphelper::OAnyEnumeration* pEnum = new ::comphelper::OAnyEnumeration(lEnum); + css::uno::Reference< css::container::XEnumeration > xEnum(static_cast< css::container::XEnumeration* >(pEnum), css::uno::UNO_QUERY_THROW); + return xEnum; +} + +//============================================================================= +// css::frame::XModel2 +css::uno::Sequence< ::rtl::OUString > SAL_CALL SfxBaseModel::getAvailableViewControllerNames() + throw (css::uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + const SfxObjectFactory& rDocumentFactory = GetObjectShell()->GetFactory(); + const sal_Int32 nViewFactoryCount = rDocumentFactory.GetViewFactoryCount(); + + Sequence< ::rtl::OUString > aViewNames( nViewFactoryCount ); + for ( sal_Int32 nViewNo = 0; nViewNo < nViewFactoryCount; ++nViewNo ) + aViewNames[nViewNo] = rDocumentFactory.GetViewFactory( nViewNo ).GetAPIViewName(); + return aViewNames; +} + +//============================================================================= +// css::frame::XModel2 +css::uno::Reference< css::frame::XController2 > SAL_CALL SfxBaseModel::createDefaultViewController( const css::uno::Reference< css::frame::XFrame >& i_rFrame ) + throw (css::uno::RuntimeException , + css::lang::IllegalArgumentException, + css::uno::Exception ) +{ + SfxModelGuard aGuard( *this ); + + const SfxObjectFactory& rDocumentFactory = GetObjectShell()->GetFactory(); + const ::rtl::OUString sDefaultViewName = rDocumentFactory.GetViewFactory( 0 ).GetAPIViewName(); + + aGuard.clear(); + + return createViewController( sDefaultViewName, Sequence< PropertyValue >(), i_rFrame ); +} + +//============================================================================= +namespace sfx { namespace intern { + + /** a class which, in its dtor, cleans up variuos objects (well, at the moment only the frame) collected during + the creation of a document view, unless the creation was successful. + */ + class SAL_DLLPRIVATE ViewCreationGuard + { + public: + ViewCreationGuard() + :m_bSuccess( false ) + { + } + + ~ViewCreationGuard() + { + if ( !m_bSuccess ) + impl_closeAll(); + } + + void takeFrameOwnership( SfxFrame* i_pFrame ) + { + OSL_PRECOND( !m_aWeakFrame, "ViewCreationGuard::takeFrameOwnership: already have a frame!" ); + OSL_PRECOND( i_pFrame != NULL, "ViewCreationGuard::takeFrameOwnership: invalid frame!" ); + m_aWeakFrame = i_pFrame; + } + + void releaseAll() + { + m_bSuccess = true; + } + + private: + void impl_closeAll() + { + if ( m_aWeakFrame && !m_aWeakFrame->GetCurrentDocument() ) + { + m_aWeakFrame->SetFrameInterface_Impl( NULL ); + m_aWeakFrame->DoClose(); + } + } + + private: + bool m_bSuccess; + SfxFrameWeak m_aWeakFrame; + }; +} } + +//============================================================================= +SfxViewFrame* SfxBaseModel::FindOrCreateViewFrame_Impl( const Reference< XFrame >& i_rFrame, ::sfx::intern::ViewCreationGuard& i_rGuard ) const +{ + SfxViewFrame* pViewFrame = NULL; + for ( pViewFrame = SfxViewFrame::GetFirst( GetObjectShell(), FALSE ); + pViewFrame; + pViewFrame= SfxViewFrame::GetNext( *pViewFrame, GetObjectShell(), FALSE ) + ) + { + if ( pViewFrame->GetFrame().GetFrameInterface() == i_rFrame ) + break; + } + if ( !pViewFrame ) + { + #if OSL_DEBUG_LEVEL > 0 + for ( SfxFrame* pCheckFrame = SfxFrame::GetFirst(); + pCheckFrame; + pCheckFrame = SfxFrame::GetNext( *pCheckFrame ) + ) + { + if ( pCheckFrame->GetFrameInterface() == i_rFrame ) + { + if ( ( pCheckFrame->GetCurrentViewFrame() != NULL ) + || ( pCheckFrame->GetCurrentDocument() != NULL ) + ) + // Note that it is perfectly letgitimate that during loading into an XFrame which already contains + // a document, there exist two SfxFrame instances bound to this XFrame - the old one, which will be + // destroyed later, and the new one, which we're going to create + continue; + + OSL_ENSURE( false, "SfxBaseModel::FindOrCreateViewFrame_Impl: there already is an SfxFrame for the given XFrame, but no view in it!" ); + // nowadays, we're the only instance allowed to create an SfxFrame for an XFrame, so this case here should not happen + break; + } + } + #endif + + SfxFrame* pTargetFrame = SfxFrame::Create( i_rFrame ); + ENSURE_OR_THROW( pTargetFrame, "could not create an SfxFrame" ); + i_rGuard.takeFrameOwnership( pTargetFrame ); + + // prepare it + pTargetFrame->PrepareForDoc_Impl( *GetObjectShell() ); + + // create view frame + pViewFrame = new SfxViewFrame( *pTargetFrame, GetObjectShell() ); + } + return pViewFrame; +} + +//============================================================================= +// css::frame::XModel2 +css::uno::Reference< css::frame::XController2 > SAL_CALL SfxBaseModel::createViewController( + const ::rtl::OUString& i_rViewName, const Sequence< PropertyValue >& i_rArguments, const Reference< XFrame >& i_rFrame ) + throw (css::uno::RuntimeException , + css::lang::IllegalArgumentException, + css::uno::Exception ) +{ + SfxModelGuard aGuard( *this ); + + if ( !i_rFrame.is() ) + throw css::lang::IllegalArgumentException( ::rtl::OUString(), *this, 3 ); + + // find the proper SFX view factory + SfxViewFactory* pViewFactory = GetObjectShell()->GetFactory().GetViewFactoryByViewName( i_rViewName ); + if ( !pViewFactory ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); + + // determine previous shell (used in some special cases) + Reference< XController > xPreviousController( i_rFrame->getController() ); + const Reference< XModel > xMe( this ); + if ( ( xPreviousController.is() ) + && ( xMe != xPreviousController->getModel() ) + ) + { + xPreviousController.clear(); + } + SfxViewShell* pOldViewShell = SfxViewShell::Get( xPreviousController ); + OSL_ENSURE( !xPreviousController.is() || ( pOldViewShell != NULL ), + "SfxBaseModel::createViewController: invalid old controller!" ); + + // a guard which will clean up in case of failure + ::sfx::intern::ViewCreationGuard aViewCreationGuard; + + // determine the ViewFrame belonging to the given XFrame + SfxViewFrame* pViewFrame = FindOrCreateViewFrame_Impl( i_rFrame, aViewCreationGuard ); + OSL_POSTCOND( pViewFrame, "SfxBaseModel::createViewController: no frame?" ); + + // delegate to SFX' view factory + pViewFrame->GetBindings().ENTERREGISTRATIONS(); + SfxViewShell* pViewShell = pViewFactory->CreateInstance( pViewFrame, pOldViewShell ); + pViewFrame->GetBindings().LEAVEREGISTRATIONS(); + ENSURE_OR_THROW( pViewShell, "invalid view shell provided by factory" ); + + // by setting the ViewShell it is prevented that disposing the Controller will destroy this ViewFrame also + pViewFrame->GetDispatcher()->SetDisableFlags( 0 ); + pViewFrame->SetViewShell_Impl( pViewShell ); + + // remember ViewID + pViewFrame->SetCurViewId_Impl( pViewFactory->GetOrdinal() ); + + // ensure a default controller, if the view shell did not provide an own implementation + if ( !pViewShell->GetController().is() ) + pViewShell->SetController( new SfxBaseController( pViewShell ) ); + + // pass the creation arguments to the controller + SfxBaseController* pBaseController = pViewShell->GetBaseController_Impl(); + ENSURE_OR_THROW( pBaseController, "invalid controller implementation!" ); + pBaseController->SetCreationArguments_Impl( i_rArguments ); + + // some initial view settings, coming from our most recent attachResource call + ::comphelper::NamedValueCollection aDocumentLoadArgs( getArgs() ); + if ( aDocumentLoadArgs.getOrDefault( "ViewOnly", false ) ) + pViewFrame->GetFrame().SetMenuBarOn_Impl( FALSE ); + + const sal_Int16 nPluginMode = aDocumentLoadArgs.getOrDefault( "PluginMode", sal_Int16( 0 ) ); + if ( nPluginMode == 1 ) + { + pViewFrame->ForceOuterResize_Impl( FALSE ); + pViewFrame->GetBindings().HidePopups( TRUE ); + + SfxFrame& rFrame = pViewFrame->GetFrame(); + // MBA: layoutmanager of inplace frame starts locked and invisible + rFrame.GetWorkWindow_Impl()->MakeVisible_Impl( FALSE ); + rFrame.GetWorkWindow_Impl()->Lock_Impl( TRUE ); + + rFrame.GetWindow().SetBorderStyle( WINDOW_BORDER_NOBORDER ); + pViewFrame->GetWindow().SetBorderStyle( WINDOW_BORDER_NOBORDER ); + } + + // tell the guard we were successful + aViewCreationGuard.releaseAll(); + + // outta gere + return pBaseController; +} + +//============================================================================= +// RDF DocumentMetadataAccess + +// ::com::sun::star::rdf::XRepositorySupplier: +uno::Reference< rdf::XRepository > SAL_CALL +SfxBaseModel::getRDFRepository() throw (uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->getRDFRepository(); +} + +// ::com::sun::star::rdf::XNode: +::rtl::OUString SAL_CALL +SfxBaseModel::getStringValue() throw (uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->getStringValue(); +} + +// ::com::sun::star::rdf::XURI: +::rtl::OUString SAL_CALL +SfxBaseModel::getNamespace() throw (uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->getNamespace(); +} + +::rtl::OUString SAL_CALL +SfxBaseModel::getLocalName() throw (uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->getLocalName(); +} + +// ::com::sun::star::rdf::XDocumentMetadataAccess: +uno::Reference< rdf::XMetadatable > SAL_CALL +SfxBaseModel::getElementByMetadataReference( + const ::com::sun::star::beans::StringPair & i_rReference) +throw (uno::RuntimeException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->getElementByMetadataReference(i_rReference); +} + +uno::Reference< rdf::XMetadatable > SAL_CALL +SfxBaseModel::getElementByURI(const uno::Reference< rdf::XURI > & i_xURI) +throw (uno::RuntimeException, lang::IllegalArgumentException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->getElementByURI(i_xURI); +} + +uno::Sequence< uno::Reference< rdf::XURI > > SAL_CALL +SfxBaseModel::getMetadataGraphsWithType( + const uno::Reference<rdf::XURI> & i_xType) +throw (uno::RuntimeException, lang::IllegalArgumentException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->getMetadataGraphsWithType(i_xType); +} + +uno::Reference<rdf::XURI> SAL_CALL +SfxBaseModel::addMetadataFile(const ::rtl::OUString & i_rFileName, + const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::ElementExistException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->addMetadataFile(i_rFileName, i_rTypes); +} + +uno::Reference<rdf::XURI> SAL_CALL +SfxBaseModel::importMetadataFile(::sal_Int16 i_Format, + const uno::Reference< io::XInputStream > & i_xInStream, + const ::rtl::OUString & i_rFileName, + const uno::Reference< rdf::XURI > & i_xBaseURI, + const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes) +throw (uno::RuntimeException, lang::IllegalArgumentException, + datatransfer::UnsupportedFlavorException, + container::ElementExistException, rdf::ParseException, io::IOException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->importMetadataFile(i_Format, + i_xInStream, i_rFileName, i_xBaseURI, i_rTypes); +} + +void SAL_CALL +SfxBaseModel::removeMetadataFile( + const uno::Reference< rdf::XURI > & i_xGraphName) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::NoSuchElementException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->removeMetadataFile(i_xGraphName); +} + +void SAL_CALL +SfxBaseModel::addContentOrStylesFile(const ::rtl::OUString & i_rFileName) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::ElementExistException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->addContentOrStylesFile(i_rFileName); +} + +void SAL_CALL +SfxBaseModel::removeContentOrStylesFile(const ::rtl::OUString & i_rFileName) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::NoSuchElementException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->removeContentOrStylesFile(i_rFileName); +} + +void SAL_CALL +SfxBaseModel::loadMetadataFromStorage( + uno::Reference< embed::XStorage > const & i_xStorage, + uno::Reference<rdf::XURI> const & i_xBaseURI, + uno::Reference<task::XInteractionHandler> const & i_xHandler) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA( + m_pData->CreateDMAUninitialized()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + try { + xDMA->loadMetadataFromStorage(i_xStorage, i_xBaseURI, i_xHandler); + } catch (lang::IllegalArgumentException &) { + throw; // not initialized + } catch (uno::Exception &) { + // UGLY: if it's a RuntimeException, we can't be sure DMA is initialzed + m_pData->m_xDocumentMetadata = xDMA; + throw; + } + m_pData->m_xDocumentMetadata = xDMA; + +} + +void SAL_CALL +SfxBaseModel::storeMetadataToStorage( + uno::Reference< embed::XStorage > const & i_xStorage) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->storeMetadataToStorage(i_xStorage); +} + +void SAL_CALL +SfxBaseModel::loadMetadataFromMedium( + const uno::Sequence< beans::PropertyValue > & i_rMedium) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA( + m_pData->CreateDMAUninitialized()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + try { + xDMA->loadMetadataFromMedium(i_rMedium); + } catch (lang::IllegalArgumentException &) { + throw; // not initialized + } catch (uno::Exception &) { + // UGLY: if it's a RuntimeException, we can't be sure DMA is initialzed + m_pData->m_xDocumentMetadata = xDMA; + throw; + } + m_pData->m_xDocumentMetadata = xDMA; +} + +void SAL_CALL +SfxBaseModel::storeMetadataToMedium( + const uno::Sequence< beans::PropertyValue > & i_rMedium) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + SfxModelGuard aGuard( *this ); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->storeMetadataToMedium(i_rMedium); +} + diff --git a/sfx2/source/doc/sfxmodelfactory.cxx b/sfx2/source/doc/sfxmodelfactory.cxx new file mode 100644 index 000000000000..714dfc2ea824 --- /dev/null +++ b/sfx2/source/doc/sfxmodelfactory.cxx @@ -0,0 +1,239 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" +#include "sfx2/sfxmodelfactory.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +/** === end UNO includes === **/ + +#include <comphelper/namedvaluecollection.hxx> +#include <cppuhelper/implbase2.hxx> + +#include <algorithm> +#include <functional> + +//........................................................................ +namespace sfx2 +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::lang::XMultiServiceFactory; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::lang::XSingleServiceFactory; + using ::com::sun::star::lang::XServiceInfo; + using ::com::sun::star::beans::NamedValue; + using ::com::sun::star::beans::PropertyValue; + using ::com::sun::star::lang::XInitialization; + /** === end UNO using === **/ + + //==================================================================== + //= SfxModelFactory - declaration + //==================================================================== + typedef ::cppu::WeakImplHelper2 < XSingleServiceFactory + , XServiceInfo + > SfxModelFactory_Base; + /** implements a XSingleServiceFactory which can be used to created instances + of classes derived from SfxBaseModel + + In opposite to the default implementations from module cppuhelper, this + factory evaluates certain creation arguments (passed to createInstanceWithArguments) + and passes them to the factory function of the derived class. + */ + class SfxModelFactory : public SfxModelFactory_Base + { + public: + SfxModelFactory( + const Reference< XMultiServiceFactory >& _rxServiceFactory, + const ::rtl::OUString& _rImplementationName, + const SfxModelFactoryFunc _pComponentFactoryFunc, + const Sequence< ::rtl::OUString >& _rServiceNames + ); + + // XSingleServiceFactory + virtual Reference< XInterface > SAL_CALL createInstance( ) throw (Exception, RuntimeException); + virtual Reference< XInterface > SAL_CALL createInstanceWithArguments( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw (RuntimeException); + virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (RuntimeException); + virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw (RuntimeException); + + protected: + virtual ~SfxModelFactory(); + + private: + Reference< XInterface > impl_createInstance( const sal_uInt64 _nCreationFlags ) const; + + private: + const Reference< XMultiServiceFactory > m_xServiceFactory; + const ::rtl::OUString m_sImplementationName; + const Sequence< ::rtl::OUString > m_aServiceNames; + const SfxModelFactoryFunc m_pComponentFactoryFunc; + }; + + //==================================================================== + //= SfxModelFactory - implementation + //==================================================================== + //-------------------------------------------------------------------- + SfxModelFactory::SfxModelFactory( const Reference< XMultiServiceFactory >& _rxServiceFactory, + const ::rtl::OUString& _rImplementationName, const SfxModelFactoryFunc _pComponentFactoryFunc, + const Sequence< ::rtl::OUString >& _rServiceNames ) + :m_xServiceFactory( _rxServiceFactory ) + ,m_sImplementationName( _rImplementationName ) + ,m_aServiceNames( _rServiceNames ) + ,m_pComponentFactoryFunc( _pComponentFactoryFunc ) + { + } + + //-------------------------------------------------------------------- + SfxModelFactory::~SfxModelFactory() + { + } + + //-------------------------------------------------------------------- + Reference< XInterface > SfxModelFactory::impl_createInstance( const sal_uInt64 _nCreationFlags ) const + { + return (*m_pComponentFactoryFunc)( m_xServiceFactory, _nCreationFlags ); + } + + //-------------------------------------------------------------------- + Reference< XInterface > SAL_CALL SfxModelFactory::createInstance( ) throw (Exception, RuntimeException) + { + return createInstanceWithArguments( Sequence< Any >() ); + } + + //-------------------------------------------------------------------- + namespace + { + struct IsSpecialArgument : public ::std::unary_function< Any, bool > + { + static bool isSpecialArgumentName( const ::rtl::OUString& _rValueName ) + { + return _rValueName.equalsAscii( "EmbeddedObject" ) + || _rValueName.equalsAscii( "EmbeddedScriptSupport" ) + || _rValueName.equalsAscii( "DocumentRecoverySupport" ); + } + + bool operator()( const Any& _rArgument ) const + { + NamedValue aNamedValue; + if ( ( _rArgument >>= aNamedValue ) && isSpecialArgumentName( aNamedValue.Name ) ) + return true; + PropertyValue aPropertyValue; + if ( ( _rArgument >>= aPropertyValue ) && isSpecialArgumentName( aPropertyValue.Name ) ) + return true; + return false; + } + }; + } + + //-------------------------------------------------------------------- + Reference< XInterface > SAL_CALL SfxModelFactory::createInstanceWithArguments( const Sequence< Any >& _rArguments ) throw (Exception, RuntimeException) + { + ::comphelper::NamedValueCollection aArgs( _rArguments ); + const sal_Bool bEmbeddedObject = aArgs.getOrDefault( "EmbeddedObject", sal_False ); + const sal_Bool bScriptSupport = aArgs.getOrDefault( "EmbeddedScriptSupport", sal_True ); + const sal_Bool bDocRecoverySupport = aArgs.getOrDefault( "DocumentRecoverySupport", sal_True ); + + sal_uInt64 nCreationFlags = + ( bEmbeddedObject ? SFXMODEL_EMBEDDED_OBJECT : 0 ) + | ( bScriptSupport ? 0 : SFXMODEL_DISABLE_EMBEDDED_SCRIPTS ) + | ( bDocRecoverySupport ? 0 : SFXMODEL_DISABLE_DOCUMENT_RECOVERY ); + + Reference< XInterface > xInstance( impl_createInstance( nCreationFlags ) ); + + // to mimic the bahaviour of the default factory's createInstanceWithArguments, we initialize + // the object with the given arguments, stripped by the three special ones + Sequence< Any > aStrippedArguments( _rArguments.getLength() ); + Any* pStrippedArgs = aStrippedArguments.getArray(); + Any* pStrippedArgsEnd = ::std::remove_copy_if( + _rArguments.getConstArray(), + _rArguments.getConstArray() + _rArguments.getLength(), + pStrippedArgs, + IsSpecialArgument() + ); + aStrippedArguments.realloc( pStrippedArgsEnd - pStrippedArgs ); + + if ( aStrippedArguments.getLength() ) + { + Reference< XInitialization > xModelInit( xInstance, UNO_QUERY ); + OSL_ENSURE( xModelInit.is(), "SfxModelFactory::createInstanceWithArguments: no XInitialization!" ); + if ( xModelInit.is() ) + xModelInit->initialize( aStrippedArguments ); + } + + return xInstance; + } + + //-------------------------------------------------------------------- + ::rtl::OUString SAL_CALL SfxModelFactory::getImplementationName( ) throw (RuntimeException) + { + return m_sImplementationName; + } + + //-------------------------------------------------------------------- + ::sal_Bool SAL_CALL SfxModelFactory::supportsService( const ::rtl::OUString& _rServiceName ) throw (RuntimeException) + { + return ::std::find( + m_aServiceNames.getConstArray(), + m_aServiceNames.getConstArray() + m_aServiceNames.getLength(), + _rServiceName + ) != m_aServiceNames.getConstArray() + m_aServiceNames.getLength(); + } + + //-------------------------------------------------------------------- + Sequence< ::rtl::OUString > SAL_CALL SfxModelFactory::getSupportedServiceNames( ) throw (RuntimeException) + { + return m_aServiceNames; + } + + //-------------------------------------------------------------------- + Reference< XSingleServiceFactory > createSfxModelFactory( const Reference< XMultiServiceFactory >& _rxServiceFactory, + const ::rtl::OUString& _rImplementationName, const SfxModelFactoryFunc _pComponentFactoryFunc, + const Sequence< ::rtl::OUString >& _rServiceNames ) + { + return new SfxModelFactory( _rxServiceFactory, _rImplementationName, _pComponentFactoryFunc, _rServiceNames ); + } + +//........................................................................ +} // namespace sfx2 +//........................................................................ diff --git a/sfx2/source/doc/syspath.cxx b/sfx2/source/doc/syspath.cxx new file mode 100755 index 000000000000..a1025370ed24 --- /dev/null +++ b/sfx2/source/doc/syspath.cxx @@ -0,0 +1,48 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2008 by Sun Microsystems, Inc. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* $RCSfile: shutdowniconw32.cxx,v $ +* $Revision: 1.48 $ +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +// Comment out precompiled statement due to redefinition errors +#include "precompiled_sfx2.hxx" + +#include "syspath.hxx" + +extern "C" bool GetUserTemplateLocation(sal_Unicode*, int nSize); + +bool SystemPath::GetUserTemplateLocation(sal_Unicode* pFolder, int nSize ) +{ +#ifdef WNT + return ::GetUserTemplateLocation( pFolder, nSize ); +#else + (void)pFolder; + (void)nSize; + return false; +#endif +} diff --git a/sfx2/source/doc/syspath.hxx b/sfx2/source/doc/syspath.hxx new file mode 100644 index 000000000000..015c16f18d26 --- /dev/null +++ b/sfx2/source/doc/syspath.hxx @@ -0,0 +1,44 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2008 by Sun Microsystems, Inc. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* $RCSfile: shutdowniconw32.cxx,v $ +* $Revision: 1.48 $ +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifndef __SYSPATH_HXX__ +#define __SYSPATH_HXX__ +//#pragma warning(disable:4917) + +#include <sfx2/dllapi.h> + +class SFX2_DLLPUBLIC SystemPath +{ +public: + static bool GetUserTemplateLocation(sal_Unicode*, int nSize); +}; + +#endif + diff --git a/sfx2/source/doc/syspathw32.cxx b/sfx2/source/doc/syspathw32.cxx new file mode 100644 index 000000000000..c0a163bed39c --- /dev/null +++ b/sfx2/source/doc/syspathw32.cxx @@ -0,0 +1,83 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2008 by Sun Microsystems, Inc. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* $RCSfile: shutdowniconw32.cxx,v $ +* $Revision: 1.48 $ +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#ifdef WNT +#ifdef _MSC_VER +#pragma warning(disable:4917) +#endif +#include <shlobj.h> + +static bool _SHGetSpecialFolderW32( int nFolderID, WCHAR* pszFolder, int nSize ) +{ + LPITEMIDLIST pidl; + HRESULT hHdl = SHGetSpecialFolderLocation( NULL, nFolderID, &pidl ); + + if( hHdl == NOERROR ) + { + WCHAR *lpFolder = static_cast< WCHAR* >( HeapAlloc( GetProcessHeap(), 0, 16000 )); + + SHGetPathFromIDListW( pidl, lpFolder ); + wcsncpy( pszFolder, lpFolder, nSize ); + + HeapFree( GetProcessHeap(), 0, lpFolder ); + IMalloc *pMalloc; + if( NOERROR == SHGetMalloc(&pMalloc) ) + { + pMalloc->Free( pidl ); + pMalloc->Release(); + } + } + return true; +} + +#endif + +// Copied from sal/types.h to circumvent problems with precompiled headers +// and redefinitions of BOOL, INT32 and other types. Unfortunately tools +// also define these type incompatible with Win32 types which leads from +// time to time to very nasty compilation errors. If someone finds a better +// way to solve these probs please remove this copied part! +typedef unsigned short sal_uInt16; +#if ( defined(WIN32) && !defined(__MINGW32__) ) + typedef wchar_t sal_Unicode; +#else + typedef sal_uInt16 sal_Unicode; +#endif + +extern "C" bool GetUserTemplateLocation(sal_Unicode* pFolder, int nSize) +{ +#ifdef WNT + return _SHGetSpecialFolderW32( CSIDL_TEMPLATES, reinterpret_cast<LPWSTR>(pFolder), nSize ); +#else + (void)pFolder; + (void)nSize; + return false; +#endif +} |