tdf#94987 Create directories for temp filenames
Per default a temporary file is construted from a path and a leading pattern for the filename. For mail merge the filename can be read from a database column. If the path is not existing, a temporary directory is created. Normally the temp file function would fail, if the filename contains a slash and the sub-directory of the filename doesn't exists as a subdirectory of path. To implement tdf#94987, this adds an option to the temp file class to create the parent directories of the filename pattern. Change-Id: I02bf34294dac85598ee153d8cfcf00bc5d7775af
This commit is contained in:
@@ -66,8 +66,11 @@ public:
|
||||
rLeadingChars="abc" means "abc0","abc1" and so on, depending on existing files in the folder ).
|
||||
The extension string may be f.e. ".txt" or "", if no extension string is given, ".tmp" is used
|
||||
@param _bStartWithZero If set to false names will be generated like "abc","abc0","abc1"
|
||||
@param bCreateParentDirs If rLeadingChars contains a slash, this will create the required
|
||||
parent directories.
|
||||
*/
|
||||
TempFile( const OUString& rLeadingChars, bool _bStartWithZero=true, const OUString* pExtension=nullptr, const OUString* pParent=nullptr);
|
||||
TempFile( const OUString& rLeadingChars, bool _bStartWithZero=true, const OUString* pExtension=nullptr,
|
||||
const OUString* pParent=nullptr, bool bCreateParentDirs=false );
|
||||
|
||||
/**
|
||||
TempFile will be removed from disk in dtor if EnableKillingFile(true) was called before.
|
||||
|
Binary file not shown.
@@ -70,7 +70,8 @@ public:
|
||||
* The 'verify' method actually has to execute the mail merge by
|
||||
* calling executeMailMerge() after modifying the job arguments.
|
||||
*/
|
||||
void executeMailMergeTest(const char* filename, const char* datasource, const char* tablename, bool file, int selection)
|
||||
void executeMailMergeTest( const char* filename, const char* datasource, const char* tablename,
|
||||
bool file, int selection, const char* column )
|
||||
{
|
||||
maMMtestFilename = filename;
|
||||
header();
|
||||
@@ -79,8 +80,9 @@ public:
|
||||
utl::TempFile aTempDir(nullptr, true);
|
||||
const OUString aWorkDir = aTempDir.GetURL();
|
||||
const OUString aURI( m_directories.getURLFromSrc(mpTestDocumentPath) + OUString::createFromAscii(datasource) );
|
||||
OUString aDBName = registerDBsource( aURI, aWorkDir );
|
||||
initMailMergeJobAndArgs( filename, tablename, aDBName, "LOMM_", aWorkDir, file, selection );
|
||||
const OUString aPrefix = column ? OUString::createFromAscii( column ) : "LOMM_";
|
||||
const OUString aDBName = registerDBsource( aURI, aWorkDir );
|
||||
initMailMergeJobAndArgs( filename, tablename, aDBName, aPrefix, aWorkDir, file, selection, column != nullptr );
|
||||
|
||||
verify();
|
||||
finish();
|
||||
@@ -130,7 +132,8 @@ public:
|
||||
}
|
||||
|
||||
void initMailMergeJobAndArgs( const char* filename, const char* tablename, const OUString &aDBName,
|
||||
const OUString &aPrefix, const OUString &aWorkDir, bool file, int nDataSets )
|
||||
const OUString &aPrefix, const OUString &aWorkDir, bool file, int nDataSets,
|
||||
const bool bPrefixIsColumn )
|
||||
{
|
||||
uno::Reference< task::XJob > xJob( getMultiServiceFactory()->createInstance( "com.sun.star.text.MailMerge" ), uno::UNO_QUERY_THROW );
|
||||
mxJob.set( xJob );
|
||||
@@ -144,6 +147,9 @@ public:
|
||||
args.push_back( beans::NamedValue( OUString( UNO_NAME_OUTPUT_URL ), uno::Any( aWorkDir ) ) );
|
||||
args.push_back( beans::NamedValue( OUString( UNO_NAME_FILE_NAME_PREFIX ), uno::Any( aPrefix )) );
|
||||
|
||||
if (bPrefixIsColumn)
|
||||
args.push_back( beans::NamedValue( OUString( UNO_NAME_FILE_NAME_FROM_COLUMN ), uno::Any( true ) ) );
|
||||
|
||||
if (tablename)
|
||||
{
|
||||
args.push_back( beans::NamedValue( OUString( UNO_NAME_DAD_COMMAND_TYPE ), uno::Any( sdb::CommandType::TABLE ) ) );
|
||||
@@ -174,6 +180,7 @@ public:
|
||||
|
||||
const beans::NamedValue *pArguments = mSeqMailMergeArgs.getConstArray();
|
||||
bool bOk = true;
|
||||
bool bMMFilenameFromColumn = false;
|
||||
sal_Int32 nArgs = mSeqMailMergeArgs.getLength();
|
||||
|
||||
for (sal_Int32 i = 0; i < nArgs; ++i) {
|
||||
@@ -187,6 +194,8 @@ public:
|
||||
bOk &= rValue >>= mailMergeOutputPrefix;
|
||||
else if (rName == UNO_NAME_OUTPUT_TYPE)
|
||||
bOk &= rValue >>= mnCurOutputType;
|
||||
else if (rName == UNO_NAME_FILE_NAME_FROM_COLUMN)
|
||||
bOk &= rValue >>= bMMFilenameFromColumn;
|
||||
}
|
||||
|
||||
CPPUNIT_ASSERT(bOk);
|
||||
@@ -205,7 +214,8 @@ public:
|
||||
else
|
||||
{
|
||||
CPPUNIT_ASSERT(res == true);
|
||||
loadMailMergeDocument( 0 );
|
||||
if( !bMMFilenameFromColumn )
|
||||
loadMailMergeDocument( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,24 +231,29 @@ public:
|
||||
return parseExportInternal( mailMergeOutputURL + "/" + name, rStreamName );
|
||||
}
|
||||
|
||||
void loadMailMergeDocument( const OUString &filename )
|
||||
{
|
||||
assert( mnCurOutputType == text::MailMergeType::FILE );
|
||||
if (mxComponent.is())
|
||||
mxComponent->dispose();
|
||||
// Output name early, so in the case of a hang, the name of the hanging input file is visible.
|
||||
std::cout << filename << ",";
|
||||
mnStartTime = osl_getGlobalTimer();
|
||||
mxComponent = loadFromDesktop(mailMergeOutputURL + "/" + filename, "com.sun.star.text.TextDocument");
|
||||
CPPUNIT_ASSERT( mxComponent.is());
|
||||
OString name2 = OUStringToOString( filename, RTL_TEXTENCODING_UTF8 );
|
||||
discardDumpedLayout();
|
||||
if (mustCalcLayoutOf(name2.getStr()))
|
||||
calcLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
Loads number-th document from mail merge. Requires file output from mail merge.
|
||||
*/
|
||||
void loadMailMergeDocument( int number )
|
||||
{
|
||||
assert( mnCurOutputType == text::MailMergeType::FILE );
|
||||
if (mxComponent.is())
|
||||
mxComponent->dispose();
|
||||
OUString name = mailMergeOutputPrefix + OUString::number( number ) + ".odt";
|
||||
// Output name early, so in the case of a hang, the name of the hanging input file is visible.
|
||||
std::cout << name << ",";
|
||||
mnStartTime = osl_getGlobalTimer();
|
||||
mxComponent = loadFromDesktop(mailMergeOutputURL + "/" + name, "com.sun.star.text.TextDocument");
|
||||
CPPUNIT_ASSERT( mxComponent.is());
|
||||
OString name2 = OUStringToOString( name, RTL_TEXTENCODING_UTF8 );
|
||||
discardDumpedLayout();
|
||||
if (mustCalcLayoutOf(name2.getStr()))
|
||||
calcLayout();
|
||||
loadMailMergeDocument( name );
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -254,7 +269,7 @@ protected:
|
||||
const char* maMMtestFilename;
|
||||
};
|
||||
|
||||
#define DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, file, BaseClass, selection) \
|
||||
#define DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, file, BaseClass, selection, column) \
|
||||
class TestName : public BaseClass { \
|
||||
protected: \
|
||||
virtual OUString getTestName() override { return OUString(#TestName); } \
|
||||
@@ -264,7 +279,7 @@ protected:
|
||||
CPPUNIT_TEST_SUITE_END(); \
|
||||
\
|
||||
void MailMerge() { \
|
||||
executeMailMergeTest(filename, datasource, tablename, file, selection); \
|
||||
executeMailMergeTest(filename, datasource, tablename, file, selection, column); \
|
||||
} \
|
||||
void verify() override; \
|
||||
}; \
|
||||
@@ -273,14 +288,17 @@ protected:
|
||||
|
||||
// Will generate the resulting document in mxMMDocument.
|
||||
#define DECLARE_SHELL_MAILMERGE_TEST(TestName, filename, datasource, tablename) \
|
||||
DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, false, MMTest, 0)
|
||||
DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, false, MMTest, 0, nullptr)
|
||||
|
||||
// Will generate documents as files, use loadMailMergeDocument().
|
||||
#define DECLARE_FILE_MAILMERGE_TEST(TestName, filename, datasource, tablename) \
|
||||
DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, true, MMTest, 0)
|
||||
DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, true, MMTest, 0, nullptr)
|
||||
|
||||
#define DECLARE_SHELL_MAILMERGE_TEST_SELECTION(TestName, filename, datasource, tablename, selection) \
|
||||
DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, false, MMTest, selection)
|
||||
DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, false, MMTest, selection, nullptr)
|
||||
|
||||
#define DECLARE_FILE_MAILMERGE_TEST_COLUMN(TestName, filename, datasource, tablename, column) \
|
||||
DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, true, MMTest, 0, column)
|
||||
|
||||
int MMTest::documentStartPageNumber( int document ) const
|
||||
{ // See documentStartPageNumber() .
|
||||
@@ -568,5 +586,22 @@ DECLARE_SHELL_MAILMERGE_TEST(test_sections_first_last, "sections_first_last.odt"
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_FILE_MAILMERGE_TEST_COLUMN(testDirMailMerge, "simple-mail-merge.odt", "10-testing-addresses.ods", "testing-addresses", "Filename")
|
||||
{
|
||||
executeMailMerge();
|
||||
for( int doc = 1;
|
||||
doc <= 10;
|
||||
++doc )
|
||||
{
|
||||
OUString filename = "sub/lastname" + OUString::number( doc )
|
||||
+ " firstname" + OUString::number( doc ) + ".odt";
|
||||
loadMailMergeDocument( filename );
|
||||
CPPUNIT_ASSERT_EQUAL( 1, getPages());
|
||||
CPPUNIT_ASSERT_EQUAL( OUString( "Fixed text." ), getRun( getParagraph( 1 ), 1 )->getString());
|
||||
CPPUNIT_ASSERT_EQUAL( OUString( "lastname" + OUString::number( doc )), getRun( getParagraph( 2 ), 1 )->getString());
|
||||
CPPUNIT_ASSERT_EQUAL( OUString( "Another fixed text." ), getRun( getParagraph( 3 ), 1 )->getString());
|
||||
}
|
||||
}
|
||||
|
||||
CPPUNIT_PLUGIN_IMPLEMENT();
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
@@ -1314,7 +1314,6 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
|
||||
{
|
||||
nStartRow = pImpl->pMergeData ? pImpl->pMergeData->xResultSet->getRow() : 0;
|
||||
|
||||
OUString sPath = rMergeDescriptor.sPath;
|
||||
OUString sColumnData;
|
||||
|
||||
// Read the indicated data column, which should contain a valid mail
|
||||
@@ -1322,28 +1321,32 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
|
||||
if( bMT_EMAIL || bColumnName )
|
||||
{
|
||||
sColumnData = GetDBField( xColumnProp, aColumnDBFormat );
|
||||
if( !bMT_EMAIL )
|
||||
{
|
||||
if (sColumnData.isEmpty())
|
||||
sColumnData = "_";
|
||||
sPath += sColumnData;
|
||||
}
|
||||
}
|
||||
|
||||
// create a new temporary file name - only done once in case of bCreateSingleFile
|
||||
if( bNeedsTempFiles && ( !bWorkDocInitialized || !bCreateSingleFile ))
|
||||
{
|
||||
INetURLObject aEntry(sPath);
|
||||
OUString sPath = rMergeDescriptor.sPath;
|
||||
OUString sLeading;
|
||||
|
||||
//#i97667# if the name is from a database field then it will be used _as is_
|
||||
if( !sColumnData.isEmpty() )
|
||||
sLeading = sColumnData;
|
||||
if( bColumnName && !bMT_EMAIL )
|
||||
{
|
||||
if (!sColumnData.isEmpty())
|
||||
sLeading = sColumnData;
|
||||
else
|
||||
sLeading = "_";
|
||||
}
|
||||
else
|
||||
{
|
||||
INetURLObject aEntry( sPath );
|
||||
sLeading = aEntry.GetBase();
|
||||
aEntry.removeSegment();
|
||||
sPath = aEntry.GetMainURL( INetURLObject::NO_DECODE );
|
||||
aEntry.removeSegment();
|
||||
sPath = aEntry.GetMainURL( INetURLObject::NO_DECODE );
|
||||
}
|
||||
|
||||
OUString sExt(comphelper::string::stripStart(pStoreToFilter->GetDefaultExtension(), '*'));
|
||||
aTempFile.reset( new utl::TempFile(sLeading, sColumnData.isEmpty(), &sExt, &sPath) );
|
||||
aTempFile.reset( new utl::TempFile(sLeading, sColumnData.isEmpty(), &sExt, &sPath, true) );
|
||||
if( !aTempFile->IsValid() )
|
||||
{
|
||||
ErrorHandler::HandleError( ERRCODE_IO_NOTSUPPORTED );
|
||||
|
@@ -225,11 +225,39 @@ private:
|
||||
|
||||
sal_uInt32 UniqueTokens::globalValue = SAL_MAX_UINT32;
|
||||
|
||||
namespace
|
||||
{
|
||||
class TempDirCreatedObserver : public DirectoryCreationObserver
|
||||
{
|
||||
public:
|
||||
virtual void DirectoryCreated(const rtl::OUString& aDirectoryUrl) override
|
||||
{
|
||||
File::setAttributes( aDirectoryUrl, osl_File_Attribute_OwnRead |
|
||||
osl_File_Attribute_OwnWrite | osl_File_Attribute_OwnExe );
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
OUString lcl_createName(
|
||||
const OUString& rLeadingChars, Tokens & tokens, const OUString* pExtension,
|
||||
const OUString* pParent, bool bDirectory, bool bKeep, bool bLock)
|
||||
const OUString* pParent, bool bDirectory, bool bKeep, bool bLock,
|
||||
bool bCreateParentDirs )
|
||||
{
|
||||
OUString aName = ConstructTempDir_Impl( pParent ) + rLeadingChars;
|
||||
OUString aName = ConstructTempDir_Impl( pParent );
|
||||
if ( bCreateParentDirs )
|
||||
{
|
||||
sal_Int32 nOffset = rLeadingChars.lastIndexOf("/");
|
||||
if (-1 != nOffset)
|
||||
{
|
||||
OUString aDirName = aName + OUString( rLeadingChars.getStr(), nOffset );
|
||||
TempDirCreatedObserver observer;
|
||||
FileBase::RC err = Directory::createPath( aDirName, &observer );
|
||||
if ( err != FileBase::E_None && err != FileBase::E_EXIST )
|
||||
return OUString();
|
||||
}
|
||||
}
|
||||
aName += rLeadingChars;
|
||||
|
||||
OUString token;
|
||||
while (tokens.next(&token))
|
||||
{
|
||||
@@ -306,7 +334,8 @@ OUString CreateTempName_Impl( const OUString* pParent, bool bKeep, bool bDir = t
|
||||
aEyeCatcher += aPidString;
|
||||
#endif
|
||||
UniqueTokens t;
|
||||
return lcl_createName(aEyeCatcher, t, nullptr, pParent, bDir, bKeep, false);
|
||||
return lcl_createName( aEyeCatcher, t, nullptr, pParent, bDir, bKeep,
|
||||
false, false);
|
||||
}
|
||||
|
||||
OUString TempFile::CreateTempName()
|
||||
@@ -328,13 +357,16 @@ TempFile::TempFile( const OUString* pParent, bool bDirectory )
|
||||
aName = CreateTempName_Impl( pParent, true, bDirectory );
|
||||
}
|
||||
|
||||
TempFile::TempFile( const OUString& rLeadingChars, bool _bStartWithZero, const OUString* pExtension, const OUString* pParent)
|
||||
TempFile::TempFile( const OUString& rLeadingChars, bool _bStartWithZero,
|
||||
const OUString* pExtension, const OUString* pParent,
|
||||
bool bCreateParentDirs )
|
||||
: pStream( nullptr )
|
||||
, bIsDirectory( false )
|
||||
, bKillingFileEnabled( false )
|
||||
{
|
||||
SequentialTokens t(_bStartWithZero);
|
||||
aName = lcl_createName(rLeadingChars, t, pExtension, pParent, false/*bDirectory*/, true, true);
|
||||
aName = lcl_createName( rLeadingChars, t, pExtension, pParent, false,
|
||||
true, true, bCreateParentDirs );
|
||||
}
|
||||
|
||||
TempFile::~TempFile()
|
||||
|
Reference in New Issue
Block a user