30 #include <hbmemoryutils_p.h> |
30 #include <hbmemoryutils_p.h> |
31 #include <hbcssparser_p.h> |
31 #include <hbcssparser_p.h> |
32 #include <hbsharedmemorymanager_p.h> |
32 #include <hbsharedmemorymanager_p.h> |
33 #include <hbsharedcache_p.h> |
33 #include <hbsharedcache_p.h> |
34 #include <hbcssconverterutils_p.h> |
34 #include <hbcssconverterutils_p.h> |
|
35 #include <hboffsetmapbuilder_p.h> |
|
36 #include <hbwidgetloader_p.h> |
35 |
37 |
36 // Global variables |
38 // Global variables |
37 QString AppName("hbbincssmaker"); |
39 static const QString CSSFileExtension = ".css"; |
|
40 static const QString WMLFileExtension = ".widgetml"; |
|
41 static const QString ColorCSSEnding = "_color.css"; |
|
42 |
|
43 static const QString AppName = "hbbincssmaker"; |
38 static bool verboseOn = false; |
44 static bool verboseOn = false; |
|
45 |
39 QTextStream out(stdout); |
46 QTextStream out(stdout); |
40 QTextStream verboseOut(stderr); |
47 QTextStream verboseOut(stderr); |
41 QTextStream err(stderr); |
48 QTextStream err(stderr); |
42 |
49 |
43 #define VERBOSE(statement) if(verboseOn) { verboseOut << statement; } |
50 #define VERBOSE(statement) if(verboseOn) { verboseOut << statement; } |
44 #define VERBOSEIF(test, statement) if(verboseOn && test) { verboseOut << statement; } |
51 #define VERBOSEIF(test, statement) if(verboseOn && test) { verboseOut << statement; } |
45 #define VERBOSELN(statement) if(verboseOn) { verboseOut << statement << endl; } |
52 #define VERBOSELN(statement) if(verboseOn) { verboseOut << statement << endl; } |
46 |
53 |
|
54 struct WidgetMLParseInput |
|
55 { |
|
56 QString filename; |
|
57 QList<CSSLayoutInfo> layouts; |
|
58 |
|
59 void clear() |
|
60 { |
|
61 layouts.clear(); |
|
62 filename.clear(); |
|
63 } |
|
64 }; |
47 |
65 |
48 void testDeclarations(const HbVector<HbCss::Declaration> &decls) |
66 void testDeclarations(const HbVector<HbCss::Declaration> &decls) |
49 { |
67 { |
50 VERBOSE("declarations count: "); |
68 VERBOSE("declarations count: "); |
51 VERBOSELN(decls.count()); |
69 VERBOSELN(decls.count()); |
113 testStyleRules(rule.portraitRules); |
131 testStyleRules(rule.portraitRules); |
114 testStyleRules(rule.landscapeRules); |
132 testStyleRules(rule.landscapeRules); |
115 } |
133 } |
116 } |
134 } |
117 |
135 |
118 class CssMap |
136 void testLayoutDef(const HbWidgetLoader::LayoutDefinition *layoutDef) |
119 { |
137 { |
120 public: |
138 VERBOSELN("mesh items count: " << layoutDef->meshItems.count()); |
121 CssMap() {} |
139 for (int i = 0; i < layoutDef->meshItems.count(); ++i) { |
122 void add(const QString &cssName, unsigned int offset) |
140 const HbWidgetLoader::MeshItem &meshItem = layoutDef->meshItems.at(i); |
123 { |
141 VERBOSELN("src: " << meshItem.src); |
124 HbOffsetItem mapItem = _mapItems.value(cssName, HbOffsetItem()); |
142 VERBOSELN("dst: " << meshItem.dst); |
125 if (mapItem.nameOffset < 0) { |
143 VERBOSELN("spacing text: " << meshItem.spacingText); |
126 mapItem.nameOffset = _cssNameBuffer.size(); |
144 VERBOSELN("spacer: " << meshItem.spacer); |
127 mapItem.offset = offset; |
145 } |
128 _cssNameBuffer.append(cssName.toLatin1()).append('\0'); |
146 } |
129 _mapItems.insert(cssName, mapItem); |
147 |
130 } else { |
148 bool testCss() |
131 err << "warning: duplicate cache key for " << cssName << endl; |
149 { |
132 } |
150 GET_MEMORY_MANAGER(HbMemoryManager::SharedMemory); |
133 } |
151 HbSharedMemoryManager *shared = static_cast<HbSharedMemoryManager*>(manager); |
134 |
152 HbSharedCache *cache = shared->cache(); |
135 void registerOffsetHolders() { |
153 |
136 foreach(const HbOffsetItem &mapItem, _mapItems) { |
154 for (int k = 0; k < cache->mOffsetItemCount; ++k) { |
137 HbCssConverterUtils::registerOffsetHolder(const_cast<int *>(&mapItem.offset)); |
155 if (cache->mOffsetItems[k].offsetCSS >= 0) { |
138 } |
156 HbCss::StyleSheet *sheet = HbMemoryUtils::getAddress<HbCss::StyleSheet>( |
139 } |
157 HbMemoryManager::SharedMemory, cache->mOffsetItems[k].offsetCSS); |
140 |
158 VERBOSELN("Cssmap item " << k |
141 QByteArray data() const { |
159 << "- hash value: \"" << cache->mOffsetItems[k].offsetCSS << "\""); |
142 QByteArray dataArray; |
160 // Tests the stylesheet offsets and prints info to verbose out |
143 int count = _mapItems.size(); |
161 testStyleSheet(sheet); |
144 int adjustment = count * sizeof(HbOffsetItem); |
162 |
145 foreach(const HbOffsetItem &mapItem, _mapItems) { |
163 //test layout definition. |
146 HbOffsetItem tmp(mapItem); |
164 int tableSize = 0; |
147 // Fix offsets in the items to be based on the beginning of the css map instead of |
165 const HbLayoutIndexItem *ptr = cache->layoutIndexItemBegin( |
148 // the beginning of the css name buffer. |
166 cache->mOffsetItems[k].offsetLayoutIndexTable, &tableSize); |
149 tmp.nameOffset += adjustment; |
167 for (; tableSize > 0; --tableSize, ++ptr) { |
150 dataArray.append(reinterpret_cast<const char*>(&tmp), sizeof(HbOffsetItem)); |
168 HbWidgetLoader::LayoutDefinition *layoutDef = |
151 } |
169 HbMemoryUtils::getAddress<HbWidgetLoader::LayoutDefinition>( |
152 dataArray.append(_cssNameBuffer); |
170 HbMemoryManager::SharedMemory, ptr->offset); |
153 return dataArray; |
171 testLayoutDef(layoutDef); |
154 } |
172 } |
155 int size() const { return _mapItems.count(); } |
173 } |
156 |
174 } |
157 private: |
175 return true; |
158 QMap<QString, HbOffsetItem> _mapItems; |
176 } |
159 QByteArray _cssNameBuffer; |
177 |
160 }; |
178 /*! |
161 |
179 Collects and return layout names from \a styleRules. |
162 struct InputFile |
180 \a layoutSet - map of already found layoutnames and sections to prevent duplicate layouts |
163 { |
181 to be added. |
164 InputFile(const QString &cacheName, const QFileInfo &file) : cacheName(cacheName), file(file) |
182 |
165 { |
183 */ |
166 } |
184 QList<CSSLayoutInfo> collectLayoutNames( |
167 |
185 QSet<QPair<QString, QString> > &layoutSet, |
168 QString cacheName; |
186 const HbVector<HbCss::StyleRule> &styleRules) |
169 QFileInfo file; |
187 { |
170 }; |
188 QList<CSSLayoutInfo> layouts; |
171 typedef QList<InputFile> InputFileList; |
189 layouts.append(CSSLayoutInfo()); |
172 |
190 |
173 struct InputFileInfo |
191 foreach(const HbCss::StyleRule &rule, styleRules) { |
174 { |
192 foreach(const HbCss::Declaration &decl, rule.declarations) { |
175 QString base; |
193 if (decl.propertyId == HbCss::Property_Layout) { |
176 QString path; |
194 if (decl.values.count() == 1) { |
177 QString prefix; |
195 layouts.last().layoutname = decl.values.at(0).variant.toString(); |
178 }; |
196 } |
179 typedef QList<InputFileInfo> InputFileInfoList; |
197 } else if (decl.propertyId == HbCss::Property_Section) { |
180 |
198 if (decl.values.count() == 1) { |
181 bool operator < (const InputFile & if1, const InputFile & if2) |
199 layouts.last().section = decl.values.at(0).variant.toString(); |
182 { |
200 } |
183 return if1.file.size() > if2.file.size(); |
201 } |
|
202 } |
|
203 const CSSLayoutInfo &infoRef = layouts.last(); |
|
204 if (!infoRef.layoutname.isEmpty()) { |
|
205 QPair<QString, QString> layout = qMakePair(infoRef.layoutname, |
|
206 infoRef.section); |
|
207 //only add layout, if not already collected before. |
|
208 if (!layoutSet.contains(layout)) { |
|
209 layoutSet.insert(layout); |
|
210 layouts.append(CSSLayoutInfo()); |
|
211 } |
|
212 } |
|
213 } |
|
214 layouts.removeLast(); |
|
215 return layouts; |
|
216 } |
|
217 |
|
218 /*! |
|
219 Collects all the layouts defined in \a stylesheet and add the result to \a input. |
|
220 returns true, if at least one layout is found. |
|
221 */ |
|
222 bool collectLayouts(const QString &cssFilePath, |
|
223 HbCss::StyleSheet *styleSheet, |
|
224 WidgetMLParseInput &input) |
|
225 { |
|
226 input.clear(); |
|
227 QSet<QPair<QString, QString> > layoutSet; //for removing duplicate layout names. |
|
228 foreach(const HbCss::WidgetStyleRules &rule, styleSheet->widgetRules) { |
|
229 layoutSet.clear(); |
|
230 input.layouts += collectLayoutNames(layoutSet, rule.styleRules); |
|
231 input.layouts += collectLayoutNames(layoutSet, rule.portraitRules); |
|
232 input.layouts += collectLayoutNames(layoutSet, rule.landscapeRules); |
|
233 } |
|
234 bool hasLayoutDef = false; |
|
235 if (!input.layouts.isEmpty()) { |
|
236 //if css contains at least 1 layout declaration, it might have .widgetml file. |
|
237 QString filePath(cssFilePath); |
|
238 filePath.replace(filePath.size() - CSSFileExtension.size(), |
|
239 CSSFileExtension.size(), WMLFileExtension); |
|
240 input.filename = filePath; |
|
241 hasLayoutDef = true; |
|
242 } |
|
243 return hasLayoutDef; |
184 } |
244 } |
185 |
245 |
186 void printHelp() |
246 void printHelp() |
187 { |
247 { |
188 out << AppName << " usage:\n\n"; |
248 out << AppName << " usage:\n\n"; |
204 } |
264 } |
205 } |
265 } |
206 return collected; |
266 return collected; |
207 } |
267 } |
208 |
268 |
209 InputFileList collectCssFiles(const QStringList &inputFilePaths) |
269 QMap<QString, QFileInfo> collectCssFiles(const QStringList &inputFilePaths) |
210 { |
270 { |
211 QStringList filters; |
271 QStringList filters; |
212 filters << "*.css"; |
272 filters << "*.css"; |
213 |
273 |
214 InputFileList inputFiles; |
274 QMap<QString, QFileInfo> cssFileMap; |
215 QFileInfoList inputPath; |
275 QFileInfoList inputPath; |
216 inputPath.append(QFileInfo()); |
276 inputPath.append(QFileInfo()); |
217 Q_FOREACH(const QString &path, inputFilePaths) { |
277 Q_FOREACH(const QString &path, inputFilePaths) { |
218 inputPath[0].setFile(path); |
278 inputPath[0].setFile(path); |
219 QFileInfoList allFiles = collectFiles(inputPath, filters); |
279 QFileInfoList allFiles = collectFiles(inputPath, filters); |
220 Q_FOREACH(const QFileInfo &info, allFiles) { |
280 Q_FOREACH(const QFileInfo &info, allFiles) { |
221 inputFiles.append(InputFile(info.fileName(), info)); |
281 QMap<QString, QFileInfo>::const_iterator i = cssFileMap.find(info.fileName()); |
222 } |
282 if (i == cssFileMap.end()) { |
223 } |
283 cssFileMap.insert(info.fileName(), info); |
224 return inputFiles; |
284 } else { |
225 } |
285 err << "duplicate css filenames found: " << i.value().absoluteFilePath() << |
226 |
286 " & " << info.absoluteFilePath(); |
227 bool writeCssBinary(const QStringList &inputFiles, const QString &targetFile) |
287 } |
|
288 } |
|
289 } |
|
290 return cssFileMap; |
|
291 } |
|
292 |
|
293 /*! |
|
294 Collects the css files from \a inputFiles, parses them to shared memory, stores |
|
295 offsets to \a offsetMap. |
|
296 returns true on success. |
|
297 */ |
|
298 bool parseCss(const QStringList &inputFiles, HbOffsetMapBuilder &offsetMap) |
228 { |
299 { |
229 if (inputFiles.isEmpty()) return false; |
300 if (inputFiles.isEmpty()) return false; |
230 InputFileList cssFiles = collectCssFiles(inputFiles); |
301 QMap<QString, QFileInfo> cssFiles = collectCssFiles(inputFiles); |
231 if (cssFiles.isEmpty()) return false; |
|
232 qSort(cssFiles); |
|
233 |
302 |
234 HbCss::Parser parser; |
303 HbCss::Parser parser; |
235 HbCss::StyleSheet *styleSheet = 0; |
304 HbCss::StyleSheet *styleSheet = 0; |
236 bool success = false; |
305 bool success = false; |
237 CssMap cssMap; |
306 |
238 GET_MEMORY_MANAGER(HbMemoryManager::SharedMemory); |
307 GET_MEMORY_MANAGER(HbMemoryManager::SharedMemory); |
239 Q_FOREACH(const InputFile &inputFile, cssFiles) { |
308 while (!cssFiles.isEmpty()) { |
240 const QFileInfo &file = inputFile.file; |
309 QMap<QString, QFileInfo>::iterator first = cssFiles.begin(); |
241 VERBOSE("processing " << file.absoluteFilePath() << "..."); |
310 QMap<QString, QFileInfo>::iterator CSSFiles[CSSFileTypeEnd]; |
242 success = false; |
311 |
243 int offset = manager->alloc(sizeof(HbCss::StyleSheet)); |
312 QString widgetName(first.key()); |
244 if (offset >= 0) { |
313 if (widgetName.endsWith(ColorCSSEnding)) { |
245 styleSheet = new (static_cast<char*>(manager->base()) + offset) |
314 //color css file, find the layout css pair. |
246 HbCss::StyleSheet(HbMemoryManager::SharedMemory); |
315 CSSFiles[ColorCSSFile] = first; |
247 parser.init(file.absoluteFilePath(), true); |
316 widgetName.remove(widgetName.size() - ColorCSSEnding.size(), |
248 success = parser.parse(styleSheet); |
317 ColorCSSEnding.size()); |
249 cssMap.add(inputFile.cacheName, offset); |
318 CSSFiles[CSSFile] = cssFiles.find(widgetName + CSSFileExtension); |
250 VERBOSE("cache key = " << inputFile.cacheName << "..."); |
319 } else { |
251 } |
320 //layout css file, find the color css pair. |
|
321 CSSFiles[CSSFile] = first; |
|
322 widgetName.remove(widgetName.size() - CSSFileExtension.size(), |
|
323 CSSFileExtension.size()); |
|
324 CSSFiles[ColorCSSFile] = cssFiles.find(widgetName + ColorCSSEnding); |
|
325 } |
|
326 int offsets[] = {-1, -1}; |
|
327 |
|
328 for (int i = 0; i < CSSFileTypeEnd; ++i) { |
|
329 if (CSSFiles[i] != cssFiles.end()) { |
|
330 const QFileInfo &file = CSSFiles[i].value(); |
|
331 VERBOSE("processing " << file.absoluteFilePath() << "..."); |
|
332 offsets[i] = manager->alloc(sizeof(HbCss::StyleSheet)); |
|
333 if (offsets[i] >= 0) { |
|
334 styleSheet = new (static_cast<char*>(manager->base()) + offsets[i]) |
|
335 HbCss::StyleSheet(HbMemoryManager::SharedMemory); |
|
336 parser.init(file.absoluteFilePath(), true); |
|
337 success = parser.parse(styleSheet); |
|
338 VERBOSE("cache key = " << CSSFiles[i].key() << "..."); |
|
339 } |
|
340 if (success) { |
|
341 VERBOSELN("ok"); |
|
342 } else { |
|
343 VERBOSELN("failed"); |
|
344 err << "Failed to parse: " << file.absoluteFilePath() << endl; |
|
345 break; |
|
346 } |
|
347 } |
|
348 } |
|
349 |
|
350 const QFileInfo *info = 0; |
|
351 QString tmp; |
|
352 if (CSSFiles[CSSFile] != cssFiles.end()) { |
|
353 tmp = CSSFiles[CSSFile].key(); |
|
354 info = &CSSFiles[CSSFile].value(); |
|
355 } |
|
356 if (!offsetMap.addWidgetOffsets(widgetName, info, offsets)) { |
|
357 return false; |
|
358 } |
|
359 |
|
360 //remove processed files from the map. |
|
361 cssFiles.erase(CSSFiles[ColorCSSFile]); |
|
362 if (!tmp.isEmpty()) { |
|
363 cssFiles.remove(tmp); |
|
364 } |
|
365 } |
|
366 return success; |
|
367 } |
|
368 |
|
369 /*! |
|
370 Parses widgetml file and all the layouts using the info from \a parseInput for a widget, |
|
371 which hash is \a widgetHash, add offsets to \a offsetMap. |
|
372 */ |
|
373 bool parseWidgetML(HbOffsetMapBuilder &offsetMap, |
|
374 quint32 widgetHash, |
|
375 const WidgetMLParseInput &parseInput) |
|
376 { |
|
377 HbWidgetLoader loader; |
|
378 |
|
379 VERBOSELN("processing: " << parseInput.filename); |
|
380 QFile file(parseInput.filename); |
|
381 if (!file.open(QFile::ReadOnly | QFile::Text)) { |
|
382 VERBOSELN("unable to open file: " << parseInput.filename); |
|
383 return false; |
|
384 } |
|
385 HbWidgetLoader::LayoutDefinition *layoutDef = 0; |
|
386 int layoutDefOffset = -1; |
|
387 bool success = true; |
|
388 |
|
389 GET_MEMORY_MANAGER(HbMemoryManager::SharedMemory); |
|
390 QList<LayoutItem> layoutInfoList; |
|
391 Q_FOREACH(const CSSLayoutInfo &info, parseInput.layouts) { |
|
392 VERBOSE("layout: " << info.layoutname << ", " << "section: " << info.section << "..."); |
|
393 |
|
394 layoutDefOffset = manager->alloc(sizeof(HbWidgetLoader::LayoutDefinition)); |
|
395 layoutDef = new(static_cast<char *>(manager->base()) + layoutDefOffset) |
|
396 HbWidgetLoader::LayoutDefinition(HbMemoryManager::SharedMemory); |
|
397 success = loader.loadLayoutDefinition(layoutDef, &file, info.layoutname, info.section); |
|
398 |
252 if (success) { |
399 if (success) { |
|
400 layoutInfoList.append(LayoutItem(&info)); |
|
401 layoutInfoList.last().offset = layoutDefOffset; |
253 VERBOSELN("ok"); |
402 VERBOSELN("ok"); |
254 } else { |
403 } else { |
255 VERBOSELN("failed"); |
404 VERBOSELN("failed"); |
256 err << "Failed to parse: " << file.absoluteFilePath() << endl; |
|
257 break; |
405 break; |
258 } |
406 } |
259 } |
407 file.seek(0); |
260 if (success) { |
408 } |
261 HbSharedMemoryManager *shared = static_cast<HbSharedMemoryManager*>(manager); |
409 success = offsetMap.addWidgetMLOffsets(parseInput.filename, widgetHash, layoutInfoList); |
262 |
410 return success; |
263 // Create shared cache to shared memory. |
411 } |
264 QByteArray data(cssMap.data()); |
412 |
265 |
413 /*! |
266 if (shared->createSharedCache(data.data(), data.size(), cssMap.size())) { |
414 Parse all the widgetmls to shared memory for widget's found in \a offsetMap, |
267 |
415 store the offsets to \a offsetMap. |
268 // Defragment the chunk contents before dumping it in a file |
416 */ |
269 int endOffset = HbCssConverterUtils::defragmentChunk(); |
417 bool parseWidgetML(HbOffsetMapBuilder &offsetMap) |
270 |
418 { |
271 if (verboseOn) { |
419 QList<HbBinMakerOffsetItem> itemList = offsetMap.items(); |
272 HbSharedCache *cache = shared->cache(); |
420 Q_FOREACH(const HbBinMakerOffsetItem &item, itemList) { |
273 |
421 if (item.offsetCSS >= 0) { |
274 for (int k=0; k<cache->mOffsetItemCount; ++k) { |
422 HbCss::StyleSheet *sheet = HbMemoryUtils::getAddress<HbCss::StyleSheet>( |
275 HbCss::StyleSheet *sheet = HbMemoryUtils::getAddress<HbCss::StyleSheet>( |
423 HbMemoryManager::SharedMemory, item.offsetCSS); |
276 HbMemoryManager::SharedMemory, cache->mOffsetItems[k].offset); |
424 WidgetMLParseInput file; |
277 |
425 if (collectLayouts(item.name, sheet, file)) { |
278 QString name(QLatin1String( ((char*)(cache->mOffsetItems)) + cache->mOffsetItems[k].nameOffset)); |
426 parseWidgetML(offsetMap, item.widgetHash, file); |
279 |
427 } |
280 VERBOSE("Cssmap item "); |
428 } |
281 VERBOSE(k); |
429 } |
282 VERBOSE("- name: \""); |
430 return true; |
283 VERBOSE(name); |
431 } |
284 VERBOSELN("\""); |
432 |
285 |
433 bool writeCssBinary(const QStringList &inputFiles, const QString &targetFile) |
286 // Tests the stylesheet offsets and prints info to verbose out |
434 { |
287 testStyleSheet(sheet); |
435 HbOffsetMapBuilder offsetMap; |
288 } |
436 if (!(parseCss(inputFiles, offsetMap) |
289 } |
437 && parseWidgetML(offsetMap))) { |
290 |
438 return false; |
291 VERBOSELN("writing the binary file"); |
439 } |
292 QFile binFile(targetFile); |
440 GET_MEMORY_MANAGER(HbMemoryManager::SharedMemory); |
293 if (!binFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { |
441 HbSharedMemoryManager *shared = static_cast<HbSharedMemoryManager*>(manager); |
294 err << "failed to open target binary file: " << binFile.fileName() << endl; |
442 |
295 return false; |
443 // Create shared cache to shared memory. |
296 } |
444 QByteArray data(offsetMap.result()); |
297 //int size = shared->size(); |
445 bool success = false; |
298 if (binFile.write(static_cast<char*>(manager->base()), endOffset) >= 0) { |
446 if (shared->createSharedCache(data.data(), data.size(), offsetMap.size())) { |
|
447 // Defragment the chunk contents before dumping it in a file |
|
448 int endOffset = HbCssConverterUtils::defragmentChunk(); |
|
449 if (verboseOn) testCss(); |
|
450 |
|
451 VERBOSELN("writing the binary file"); |
|
452 QFile binFile(targetFile); |
|
453 success = binFile.open(QIODevice::WriteOnly | QIODevice::Truncate); |
|
454 if (success) { |
|
455 success = (binFile.write(static_cast<char*>(manager->base()), endOffset) >= 0); |
|
456 if (success) { |
299 VERBOSELN("Wrote target binary file: " << binFile.fileName()); |
457 VERBOSELN("Wrote target binary file: " << binFile.fileName()); |
300 } else { |
458 } else { |
301 err << "failed to write to target binary file: " << binFile.fileName() << endl; |
459 err << "failed to write to target binary file: " << binFile.fileName() << endl; |
302 } |
460 } |
303 } else { |
461 } else { |
304 err << "failed to create shared cache." << endl; |
462 err << "failed to open target binary file: " << binFile.fileName() << endl; |
305 } |
463 } |
|
464 } else { |
|
465 err << "failed to create shared cache." << endl; |
306 } |
466 } |
307 return success; |
467 return success; |
308 } |
468 } |
309 |
469 |
310 int main(int argc, char **argv) |
470 int main(int argc, char **argv) |
311 { |
471 { |
312 QCoreApplication app(argc, argv); |
472 QCoreApplication app(argc, argv); |
|
473 int returnValue = 0; |
313 |
474 |
314 if(argc < 3) { |
475 if(argc < 3) { |
315 printHelp(); |
476 printHelp(); |
316 } else { |
477 } else { |
317 QStringList inputFiles; |
478 QStringList inputFiles; |