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