1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sd.hxx" 30 31 #include "TemplateScanner.hxx" 32 33 #ifndef _COMPHELPER_SERVICEFACTORY_HXX 34 #include <comphelper/processfactory.hxx> 35 #endif 36 #include <comphelper/documentconstants.hxx> 37 38 #include <tools/debug.hxx> 39 #include <vos/mutex.hxx> 40 #include <vcl/svapp.hxx> 41 #include <com/sun/star/frame/XDocumentTemplates.hpp> 42 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 43 #include <com/sun/star/ucb/XCommandEnvironment.hpp> 44 #include <com/sun/star/ucb/XContentAccess.hpp> 45 #include <com/sun/star/sdbc/XResultSet.hpp> 46 #include <com/sun/star/sdbc/XRow.hpp> 47 48 #include <set> 49 50 using namespace ::com::sun::star; 51 using namespace ::com::sun::star::uno; 52 53 namespace { 54 55 const ::rtl::OUString TITLE = ::rtl::OUString::createFromAscii ("Title"); 56 const ::rtl::OUString TARGET_DIR_URL = ::rtl::OUString::createFromAscii ("TargetDirURL"); 57 const ::rtl::OUString DESCRIPTION = ::rtl::OUString::createFromAscii ("TypeDescription"); 58 const ::rtl::OUString TARGET_URL = ::rtl::OUString::createFromAscii ("TargetURL"); 59 60 const ::rtl::OUString DOCTEMPLATES = ::rtl::OUString::createFromAscii ("com.sun.star.frame.DocumentTemplates"); 61 62 // These strings are used to find impress templates in the tree of 63 // template files. Should probably be determined dynamically. 64 const ::rtl::OUString IMPRESS_BIN_TEMPLATE = ::rtl::OUString::createFromAscii ("application/vnd.stardivision.impress"); 65 const ::rtl::OUString IMPRESS_XML_TEMPLATE = MIMETYPE_VND_SUN_XML_IMPRESS; 66 // The following id comes from the bugdoc in #i2764#. 67 const ::rtl::OUString IMPRESS_XML_TEMPLATE_B = ::rtl::OUString::createFromAscii ("Impress 2.0"); 68 const ::rtl::OUString IMPRESS_XML_TEMPLATE_OASIS = MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION; 69 70 71 class FolderDescriptor 72 { 73 public: 74 FolderDescriptor ( 75 int nPriority, 76 const ::rtl::OUString& rsTitle, 77 const ::rtl::OUString& rsTargetDir, 78 const ::rtl::OUString& rsContentIdentifier, 79 const Reference<com::sun::star::ucb::XCommandEnvironment>& rxFolderEnvironment) 80 : mnPriority(nPriority), 81 msTitle(rsTitle), 82 msTargetDir(rsTargetDir), 83 msContentIdentifier(rsContentIdentifier), 84 mxFolderEnvironment(rxFolderEnvironment) 85 { } 86 int mnPriority; 87 ::rtl::OUString msTitle; 88 ::rtl::OUString msTargetDir; 89 ::rtl::OUString msContentIdentifier; 90 // Reference<sdbc::XResultSet> mxFolderResultSet; 91 Reference<com::sun::star::ucb::XCommandEnvironment> mxFolderEnvironment; 92 93 class Comparator { public: 94 bool operator() (const FolderDescriptor& r1, const FolderDescriptor& r2) 95 { return r1.mnPriority < r2.mnPriority; } 96 }; 97 }; 98 99 /** Use a heuristic based on the URL of a top-level template folder to 100 assign a priority that is used to sort the folders. 101 */ 102 int Classify (const ::rtl::OUString&, const ::rtl::OUString& rsURL) 103 { 104 int nPriority (0); 105 106 if (rsURL.getLength() == 0) 107 nPriority = 100; 108 else if (rsURL.indexOf(::rtl::OUString::createFromAscii("presnt"))>=0) 109 { 110 nPriority = 30; 111 } 112 else if (rsURL.indexOf(::rtl::OUString::createFromAscii("layout"))>=0) 113 { 114 nPriority = 20; 115 } 116 else if (rsURL.indexOf(::rtl::OUString::createFromAscii("educate"))>=0) 117 { 118 nPriority = 40; 119 } 120 else if (rsURL.indexOf(::rtl::OUString::createFromAscii("finance"))>=0) 121 { 122 nPriority = 40; 123 } 124 else 125 { 126 // All other folders are taken for user supplied and have the 127 // highest priority. 128 nPriority = 10; 129 } 130 131 return nPriority; 132 } 133 134 } // end of anonymous namespace 135 136 137 138 139 namespace sd 140 { 141 142 class TemplateScanner::FolderDescriptorList 143 : public ::std::multiset<FolderDescriptor,FolderDescriptor::Comparator> 144 { 145 }; 146 147 TemplateScanner::TemplateScanner (void) 148 : meState(INITIALIZE_SCANNING), 149 maFolderContent(), 150 mpTemplateDirectory(NULL), 151 maFolderList(), 152 mpLastAddedEntry(NULL), 153 mpFolderDescriptors(new FolderDescriptorList()), 154 mxTemplateRoot(), 155 mxFolderEnvironment(), 156 mxEntryEnvironment(), 157 mxFolderResultSet(), 158 mxEntryResultSet() 159 { 160 // empty; 161 } 162 163 164 165 166 TemplateScanner::~TemplateScanner (void) 167 { 168 mpFolderDescriptors.reset(); 169 170 // Delete all entries of the template list that have not been 171 // transferred to another object. 172 std::vector<TemplateDir*>::iterator I; 173 for (I=maFolderList.begin(); I!=maFolderList.end(); I++) 174 if (*I != NULL) 175 delete *I; 176 } 177 178 179 180 181 TemplateScanner::State TemplateScanner::GetTemplateRoot (void) 182 { 183 State eNextState (INITIALIZE_FOLDER_SCANNING); 184 185 Reference<lang::XMultiServiceFactory> xFactory = ::comphelper::getProcessServiceFactory (); 186 DBG_ASSERT (xFactory.is(), "TemplateScanner::GetTemplateRoot: xFactory is NULL"); 187 188 if (xFactory.is()) 189 { 190 Reference<frame::XDocumentTemplates> xTemplates ( 191 xFactory->createInstance (DOCTEMPLATES), UNO_QUERY); 192 DBG_ASSERT (xTemplates.is(), "TemplateScanner::GetTemplateRoot: xTemplates is NULL"); 193 194 if (xTemplates.is()) 195 mxTemplateRoot = xTemplates->getContent(); 196 else 197 eNextState = ERROR; 198 } 199 else 200 eNextState = ERROR; 201 202 return eNextState; 203 } 204 205 206 207 208 TemplateScanner::State TemplateScanner::InitializeEntryScanning (void) 209 { 210 State eNextState (SCAN_ENTRY); 211 212 if (maFolderContent.isFolder()) 213 { 214 mxEntryEnvironment = Reference<com::sun::star::ucb::XCommandEnvironment>(); 215 216 // We are interested only in three properties: the entry's name, 217 // its URL, and its content type. 218 Sequence<rtl::OUString> aProps (3); 219 aProps[0] = TITLE; 220 aProps[1] = TARGET_URL; 221 aProps[2] = DESCRIPTION; 222 223 // Create a cursor to iterate over the templates in this folders. 224 ::ucbhelper::ResultSetInclude eInclude = ::ucbhelper::INCLUDE_DOCUMENTS_ONLY; 225 mxEntryResultSet = Reference<com::sun::star::sdbc::XResultSet>( 226 maFolderContent.createCursor(aProps, eInclude)); 227 } 228 else 229 eNextState = ERROR; 230 231 return eNextState; 232 } 233 234 235 236 237 TemplateScanner::State TemplateScanner::ScanEntry (void) 238 { 239 State eNextState (ERROR); 240 241 Reference<com::sun::star::ucb::XContentAccess> xContentAccess (mxEntryResultSet, UNO_QUERY); 242 Reference<com::sun::star::sdbc::XRow> xRow (mxEntryResultSet, UNO_QUERY); 243 244 if (xContentAccess.is() && xRow.is() && mxEntryResultSet.is()) 245 { 246 if (mxEntryResultSet->next()) 247 { 248 ::rtl::OUString sTitle (xRow->getString (1)); 249 ::rtl::OUString sTargetURL (xRow->getString (2)); 250 ::rtl::OUString sContentType (xRow->getString (3)); 251 252 ::rtl::OUString aId = xContentAccess->queryContentIdentifierString(); 253 ::ucbhelper::Content aContent = ::ucbhelper::Content (aId, mxEntryEnvironment); 254 if (aContent.isDocument ()) 255 { 256 // Check wether the entry is an impress template. If so 257 // add a new entry to the resulting list (which is created 258 // first if necessary). 259 if ( (sContentType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE) 260 || (sContentType == IMPRESS_XML_TEMPLATE_OASIS) 261 || (sContentType == IMPRESS_BIN_TEMPLATE) 262 || (sContentType == IMPRESS_XML_TEMPLATE) 263 || (sContentType == IMPRESS_XML_TEMPLATE_B)) 264 { 265 mpLastAddedEntry = new TemplateEntry(sTitle, sTargetURL); 266 mpTemplateDirectory->maEntries.push_back(mpLastAddedEntry); 267 } 268 } 269 270 // Continue scanning entries. 271 eNextState = SCAN_ENTRY; 272 } 273 else 274 { 275 if (mpTemplateDirectory->maEntries.empty()) 276 { 277 delete mpTemplateDirectory; 278 mpTemplateDirectory = NULL; 279 } 280 else 281 { 282 ::vos::OGuard aGuard(Application::GetSolarMutex()); 283 maFolderList.push_back(mpTemplateDirectory); 284 } 285 286 // Continue with scanning the next folder. 287 eNextState = SCAN_FOLDER; 288 } 289 } 290 291 return eNextState; 292 } 293 294 295 296 297 TemplateScanner::State TemplateScanner::InitializeFolderScanning (void) 298 { 299 State eNextState (ERROR); 300 301 mxFolderResultSet = Reference<sdbc::XResultSet>(); 302 303 try 304 { 305 // Create content for template folders. 306 mxFolderEnvironment = Reference<com::sun::star::ucb::XCommandEnvironment>(); 307 ::ucbhelper::Content aTemplateDir (mxTemplateRoot, mxFolderEnvironment); 308 309 // Define the list of properties we are interested in. 310 Sequence<rtl::OUString> aProps (2); 311 aProps[0] = TITLE; 312 aProps[1] = TARGET_DIR_URL; 313 314 // Create an cursor to iterate over the template folders. 315 ::ucbhelper::ResultSetInclude eInclude = ::ucbhelper::INCLUDE_FOLDERS_ONLY; 316 mxFolderResultSet = Reference<sdbc::XResultSet>( 317 aTemplateDir.createCursor(aProps, eInclude)); 318 if (mxFolderResultSet.is()) 319 eNextState = GATHER_FOLDER_LIST; 320 } 321 catch (::com::sun::star::uno::Exception&) 322 { 323 eNextState = ERROR; 324 } 325 326 return eNextState; 327 } 328 329 330 331 332 TemplateScanner::State TemplateScanner::GatherFolderList (void) 333 { 334 State eNextState (ERROR); 335 336 Reference<com::sun::star::ucb::XContentAccess> xContentAccess (mxFolderResultSet, UNO_QUERY); 337 if (xContentAccess.is() && mxFolderResultSet.is()) 338 { 339 while (mxFolderResultSet->next()) 340 { 341 Reference<sdbc::XRow> xRow (mxFolderResultSet, UNO_QUERY); 342 if (xRow.is()) 343 { 344 ::rtl::OUString sTitle (xRow->getString (1)); 345 ::rtl::OUString sTargetDir (xRow->getString (2)); 346 ::rtl::OUString aId = xContentAccess->queryContentIdentifierString(); 347 348 mpFolderDescriptors->insert( 349 FolderDescriptor( 350 Classify(sTitle,sTargetDir), 351 sTitle, 352 sTargetDir, 353 aId, 354 mxFolderEnvironment)); 355 } 356 } 357 358 eNextState = SCAN_FOLDER; 359 } 360 361 return eNextState; 362 } 363 364 365 366 367 TemplateScanner::State TemplateScanner::ScanFolder (void) 368 { 369 State eNextState (ERROR); 370 371 if (mpFolderDescriptors->size() > 0) 372 { 373 FolderDescriptor aDescriptor (*mpFolderDescriptors->begin()); 374 mpFolderDescriptors->erase(mpFolderDescriptors->begin()); 375 376 ::rtl::OUString sTitle (aDescriptor.msTitle); 377 ::rtl::OUString sTargetDir (aDescriptor.msTargetDir); 378 ::rtl::OUString aId (aDescriptor.msContentIdentifier); 379 380 maFolderContent = ::ucbhelper::Content (aId, aDescriptor.mxFolderEnvironment); 381 if (maFolderContent.isFolder()) 382 { 383 // Scan the folder and insert it into the list of template 384 // folders. 385 mpTemplateDirectory = new TemplateDir (sTitle, sTargetDir); 386 if (mpTemplateDirectory != NULL) 387 { 388 // Continue with scanning all entries in the folder. 389 eNextState = INITIALIZE_ENTRY_SCAN; 390 } 391 } 392 } 393 else 394 { 395 eNextState = DONE; 396 } 397 398 return eNextState; 399 } 400 401 402 403 404 void TemplateScanner::Scan (void) 405 { 406 while (HasNextStep()) 407 RunNextStep(); 408 } 409 410 411 412 413 std::vector<TemplateDir*>& TemplateScanner::GetFolderList (void) 414 { 415 return maFolderList; 416 } 417 418 419 420 421 void TemplateScanner::RunNextStep (void) 422 { 423 switch (meState) 424 { 425 case INITIALIZE_SCANNING: 426 meState = GetTemplateRoot(); 427 break; 428 429 case INITIALIZE_FOLDER_SCANNING: 430 meState = InitializeFolderScanning(); 431 break; 432 433 case SCAN_FOLDER: 434 meState = ScanFolder(); 435 break; 436 437 case GATHER_FOLDER_LIST: 438 meState = GatherFolderList(); 439 break; 440 441 case INITIALIZE_ENTRY_SCAN: 442 meState = InitializeEntryScanning(); 443 break; 444 445 case SCAN_ENTRY: 446 meState = ScanEntry(); 447 break; 448 default: 449 break; 450 } 451 452 switch (meState) 453 { 454 case DONE: 455 case ERROR: 456 mxTemplateRoot.clear(); 457 mxTemplateRoot.clear(); 458 mxFolderEnvironment.clear(); 459 mxEntryEnvironment.clear(); 460 mxFolderResultSet.clear(); 461 mxEntryResultSet.clear(); 462 mpLastAddedEntry = NULL; 463 break; 464 default: 465 break; 466 } 467 } 468 469 470 471 472 bool TemplateScanner::HasNextStep (void) 473 { 474 switch (meState) 475 { 476 case DONE: 477 case ERROR: 478 return false; 479 480 default: 481 return true; 482 } 483 } 484 485 486 487 488 const TemplateEntry* TemplateScanner::GetLastAddedEntry (void) const 489 { 490 return mpLastAddedEntry; 491 } 492 493 } 494