19 #include "filemanager.h"
20 #include "pencildef.h"
21 #include "JlCompress.h"
22 #include "fileformat.h"
26 FileManager::FileManager( QObject *parent ) : QObject( parent ),
29 ENABLE_DEBUG_LOG( mLog,
true );
32 Object* FileManager::load( QString strFileName )
34 if ( !QFile::exists( strFileName ) )
36 qCDebug( mLog ) <<
"ERROR - File doesn't exist.";
37 return cleanUpWithErrorCode( Status::FILE_NOT_FOUND );
40 emit progressUpdated( 0.f );
43 obj->setFilePath( strFileName );
44 obj->createWorkingDir();
46 QString strMainXMLFile;
47 QString strDataFolder;
50 bool oldFormat = isOldForamt( strFileName );
54 qCDebug( mLog ) <<
"Recognized Old Pencil File Format (*.pcl) !";
56 strMainXMLFile = strFileName;
57 strDataFolder = strMainXMLFile +
"." + PFF_OLD_DATA_DIR;
61 qCDebug( mLog ) <<
"Recognized New zipped Pencil File Format (*.pclx) !";
63 unzip( strFileName, obj->workingDir() );
65 strMainXMLFile = QDir( obj->workingDir() ).filePath( PFF_XML_FILE_NAME );
66 strDataFolder = QDir( obj->workingDir() ).filePath( PFF_DATA_DIR );
69 qDebug() <<
"XML=" << strMainXMLFile;
70 qDebug() <<
"Data Folder=" << strDataFolder;
71 qDebug() <<
"Working Folder=" << obj->workingDir();
73 obj->setDataDir( strDataFolder );
74 obj->setMainXMLFile( strMainXMLFile );
76 QFile file( strMainXMLFile );
77 if ( !file.open( QFile::ReadOnly ) )
79 return cleanUpWithErrorCode( Status::ERROR_FILE_CANNOT_OPEN );
82 qCDebug( mLog ) <<
"Checking main XML file...";
84 if ( !xmlDoc.setContent( &file ) )
86 return cleanUpWithErrorCode( Status::ERROR_INVALID_XML_FILE );
89 QDomDocumentType type = xmlDoc.doctype();
90 if ( !( type.name() ==
"PencilDocument" || type.name() ==
"MyObject" ) )
92 return cleanUpWithErrorCode( Status::ERROR_INVALID_PENCIL_FILE );
95 QDomElement root = xmlDoc.documentElement();
98 return cleanUpWithErrorCode( Status::ERROR_INVALID_PENCIL_FILE );
102 qCDebug( mLog ) <<
"Start to load object..";
108 if ( root.tagName() ==
"document" )
110 ok = loadObject( obj, root );
112 else if ( root.tagName() ==
"object" || root.tagName() ==
"MyOject" )
114 ok = loadObjectOldWay( obj, root );
120 return cleanUpWithErrorCode( Status::ERROR_INVALID_PENCIL_FILE );
128 bool FileManager::loadObject(
Object*
object,
const QDomElement& root )
130 QDomElement e = root.firstChildElement(
"object" );
137 for ( QDomNode node = root.firstChild(); !node.isNull(); node = node.nextSibling() )
139 QDomElement element = node.toElement();
140 if ( element.isNull() )
145 if ( element.tagName() ==
"object" )
147 qCDebug( mLog ) <<
"Load object";
148 isOK =
object->loadXML( element, [
this] (
float f )
150 emit progressUpdated( f );
153 else if ( element.tagName() ==
"editor" || element.tagName() ==
"projectdata" )
155 ObjectData* projectData = loadProjectData( element );
156 object->setData( projectData );
169 bool FileManager::loadObjectOldWay(
Object*
object,
const QDomElement& root )
171 return object->loadXML( root, [
this](
float f )
173 emit progressUpdated( f );
177 bool FileManager::isOldForamt(
const QString& fileName )
179 QStringList zippedFileList = JlCompress::getFileList( fileName );
180 return ( zippedFileList.empty() );
183 Status FileManager::save(
Object*
object, QString strFileName )
185 QStringList debugDetails = QStringList() <<
"FileManager::save" << QString(
"strFileName = " ).append( strFileName );
186 if (
object ==
nullptr )
188 return Status( Status::INVALID_ARGUMENT, debugDetails <<
"object parameter is null" );
191 QFileInfo fileInfo( strFileName );
192 if ( fileInfo.isDir() )
194 debugDetails <<
"strFileName points to a directory";
195 return Status( Status::INVALID_ARGUMENT,
197 tr(
"Invalid Save Path" ),
198 tr(
"The file path you have specified (\"%1\") points to a directory, so the file cannot be saved." ).arg( fileInfo.absoluteFilePath() ) );
200 if ( fileInfo.exists() && !fileInfo.isWritable() )
202 debugDetails <<
"strFileName points to a file that is not writable";
203 return Status( Status::INVALID_ARGUMENT,
205 tr(
"Invalid Save Path" ),
206 tr(
"The file path you have specified (\"%1\") cannot be written to, so the file cannot be saved. Please make sure that you have sufficient permissions to save to that location and try again." ).arg( fileInfo.absoluteFilePath() ) );
209 QString strTempWorkingFolder;
210 QString strMainXMLFile;
211 QString strDataFolder;
213 bool isOldFile = strFileName.endsWith( PFF_OLD_EXTENSION );
216 qCDebug( mLog ) <<
"Save in Old Pencil File Format (*.pcl) !";
218 strMainXMLFile = strFileName;
219 strDataFolder = strMainXMLFile +
"." + PFF_OLD_DATA_DIR;
223 qCDebug( mLog ) <<
"Save in New zipped Pencil File Format (*.pclx) !";
225 strTempWorkingFolder =
object->workingDir();
226 Q_ASSERT( QDir( strTempWorkingFolder ).exists() );
227 debugDetails << QString(
"strTempWorkingFolder = " ).append( strTempWorkingFolder );
229 qCDebug( mLog ) <<
"Temp Folder=" << strTempWorkingFolder;
230 strMainXMLFile = QDir( strTempWorkingFolder ).filePath( PFF_XML_FILE_NAME );
231 strDataFolder = QDir( strTempWorkingFolder ).filePath( PFF_OLD_DATA_DIR );
234 QFileInfo dataInfo( strDataFolder );
235 if ( !dataInfo.exists() )
237 QDir dir( strDataFolder );
240 if( !dir.mkpath( strDataFolder ) )
242 debugDetails << QString(
"dir.absolutePath() = %1" ).arg( dir.absolutePath() );
244 return Status( Status::ERROR_FILE_CANNOT_OPEN, debugDetails, tr(
"Cannot Create Data Directory" ), tr(
"Cannot create the data directory at \"%1\". Please make sure that you have sufficient permissions to save to that location and try again. Alternatively try saving as pclx format." ).arg( strDataFolder ) );
247 return Status( Status::FAIL, debugDetails, tr(
"Internal Error"), tr(
"Cannot create the data directory at temporary location \"%1\". Please make sure that you have sufficient permissions to save to that location and try again. Alternatively try saving as pcl format." ).arg( strDataFolder ) );
251 if( !dataInfo.isDir() )
253 debugDetails << QString(
"dataInfo.absoluteFilePath() = ").append(dataInfo.absoluteFilePath());
256 return Status( Status::ERROR_FILE_CANNOT_OPEN, debugDetails, tr(
"Cannot Create Data Directory" ), tr(
"Cannot use the path \"%1\" as a data directory since that currently points to a file. Please move or delete that file and try again. Alternatively try saving with the pclx format." ).arg( dataInfo.absoluteFilePath() ) );
260 return Status( Status::FAIL, debugDetails, tr(
"Internal Error" ), tr(
"Cannot use the data directory at temporary location \"%1\" since it is a file. Please move or delete that file and try again. Alternatively try saving with the pcl format." ).arg( dataInfo.absoluteFilePath() ) );
265 int layerCount =
object->getLayerCount();
266 debugDetails << QString(
"layerCount = %1").arg(layerCount);
267 qCDebug( mLog ) << QString(
"Total layers = %1" ).arg( layerCount );
270 for (
int i = 0; i < layerCount; ++i )
272 Layer* layer =
object->getLayer( i );
273 qCDebug( mLog ) << QString(
"Saving Layer %1" ).arg( i ).arg( layer->mName );
277 debugDetails << QString(
"layer[%1] = Layer[id=%2, name=%3, type=%4]").arg( i ).arg( layer->id() ).arg( layer->name() ).arg( layer->type() );
278 switch ( layer->type() )
284 Status st = layer->save( strDataFolder );
288 QStringList layerDetails = st.detailsList();
289 for ( QString detail : layerDetails )
291 detail.prepend(
" " );
293 debugDetails << QString(
"- Layer[%1] failed to save" ).arg( i ) << layerDetails;
299 case Layer::UNDEFINED:
306 return Status( Status::FAIL, debugDetails, tr(
"Internal Error" ), tr(
"An internal error occurred while trying to save the file. Some or all of your file may not have saved." ) );
311 object->savePalette( strDataFolder );
314 QScopedPointer<QFile> file(
new QFile( strMainXMLFile ) );
315 if ( !file->open( QFile::WriteOnly | QFile::Text ) )
317 return Status::ERROR_FILE_CANNOT_OPEN;
320 QDomDocument xmlDoc(
"PencilDocument" );
321 QDomElement root = xmlDoc.createElement(
"document" );
322 QDomProcessingInstruction encoding = xmlDoc.createProcessingInstruction(
"xml",
"version=\"1.0\" encoding=\"UTF-8\"");
323 xmlDoc.appendChild( encoding );
324 xmlDoc.appendChild( root );
327 QDomElement projectDataElement = saveProjectData( object->data(), xmlDoc );
328 root.appendChild( projectDataElement );
329 qCDebug( mLog ) <<
"Save Project Data";
332 QDomElement objectElement =
object->saveXML( xmlDoc );
333 root.appendChild( objectElement );
334 qCDebug( mLog ) <<
"Save Object Node";
336 const int IndentSize = 2;
338 QTextStream out( file.data() );
339 xmlDoc.save( out, IndentSize );
343 qCDebug( mLog ) <<
"Now compressing data to PFF - PCLX ...";
345 bool ok = JlCompress::compressDir( strFileName, strTempWorkingFolder );
351 qCDebug( mLog ) <<
"Compressed. File saved.";
354 object->setFilePath( strFileName );
355 object->setModified(
false );
360 ObjectData* FileManager::loadProjectData(
const QDomElement& docElem )
363 if ( docElem.isNull() )
368 QDomNode tag = docElem.firstChild();
370 while ( !tag.isNull() )
372 QDomElement element = tag.toElement();
373 if ( element.isNull() )
378 extractProjectData( element, data );
380 tag = tag.nextSibling();
386 QDomElement FileManager::saveProjectData(
ObjectData* data, QDomDocument& xmlDoc )
388 QDomElement rootTag = xmlDoc.createElement(
"projectdata" );
391 QDomElement currentFrameTag = xmlDoc.createElement(
"currentFrame" );
392 currentFrameTag.setAttribute(
"value", data->getCurrentFrame() );
393 rootTag.appendChild( currentFrameTag );
396 QDomElement currentColorTag = xmlDoc.createElement(
"currentColor" );
397 QColor color = data->getCurrentColor();
398 currentColorTag.setAttribute(
"r", color.red() );
399 currentColorTag.setAttribute(
"g", color.green() );
400 currentColorTag.setAttribute(
"b", color.blue() );
401 currentColorTag.setAttribute(
"a", color.alpha() );
402 rootTag.appendChild( currentColorTag );
405 QDomElement currentLayerTag = xmlDoc.createElement(
"currentLayer" );
406 currentLayerTag.setAttribute(
"value", data->getCurrentLayer() );
407 rootTag.appendChild( currentLayerTag );
410 QDomElement currentViewTag = xmlDoc.createElement(
"currentView" );
411 QTransform view = data->getCurrentView();
412 currentViewTag.setAttribute(
"m11", view.m11() );
413 currentViewTag.setAttribute(
"m12", view.m12() );
414 currentViewTag.setAttribute(
"m21", view.m21() );
415 currentViewTag.setAttribute(
"m22", view.m22() );
416 currentViewTag.setAttribute(
"dx", view.dx() );
417 currentViewTag.setAttribute(
"dy", view.dy() );
418 rootTag.appendChild( currentViewTag );
421 QDomElement fpsTag = xmlDoc.createElement(
"fps" );
422 fpsTag.setAttribute(
"value", data->getFrameRate() );
423 rootTag.appendChild( fpsTag );
426 QDomElement tagIsLoop = xmlDoc.createElement(
"isLoop" );
427 tagIsLoop.setAttribute(
"value", data->isLooping() ?
"true" :
"false" );
428 rootTag.appendChild( tagIsLoop );
431 QDomElement tagRangedPlayback = xmlDoc.createElement(
"isRangedPlayback" );
432 tagRangedPlayback.setAttribute(
"value", data->isRangedPlayback() ?
"true" :
"false" );
433 rootTag.appendChild( tagRangedPlayback );
436 QDomElement tagMarkInFrame = xmlDoc.createElement(
"markInFrame" );
437 tagMarkInFrame.setAttribute(
"value", data->getMarkInFrameNumber() );
438 rootTag.appendChild( tagMarkInFrame );
441 QDomElement tagMarkOutFrame = xmlDoc.createElement(
"markOutFrame" );
442 tagMarkOutFrame.setAttribute(
"value", data->getMarkOutFrameNumber() );
443 rootTag.appendChild( tagMarkOutFrame );
448 void FileManager::extractProjectData(
const QDomElement& element,
ObjectData* data )
452 QString strName = element.tagName();
453 if ( strName ==
"currentFrame" )
455 data->setCurrentFrame( element.attribute(
"value" ).toInt() );
457 else if ( strName ==
"currentColor" )
459 int r = element.attribute(
"r",
"255" ).toInt();
460 int g = element.attribute(
"g",
"255" ).toInt();
461 int b = element.attribute(
"b",
"255" ).toInt();
462 int a = element.attribute(
"a",
"255" ).toInt();
464 data->setCurrentColor( QColor( r, g, b, a ) );
466 else if ( strName ==
"currentLayer" )
468 data->setCurrentLayer( element.attribute(
"value",
"0" ).toInt() );
470 else if ( strName ==
"currentView" )
472 double m11 = element.attribute(
"m11",
"1" ).toDouble();
473 double m12 = element.attribute(
"m12",
"0" ).toDouble();
474 double m21 = element.attribute(
"m21",
"0" ).toDouble();
475 double m22 = element.attribute(
"m22",
"1" ).toDouble();
476 double dx = element.attribute(
"dx",
"0" ).toDouble();
477 double dy = element.attribute(
"dy",
"0" ).toDouble();
479 data->setCurrentView( QTransform( m11, m12, m21, m22, dx, dy ) );
481 else if ( strName ==
"fps" || strName ==
"currentFps" )
483 data->setFrameRate( element.attribute(
"value",
"12" ).toInt() );
485 else if ( strName ==
"isLoop" )
487 data->setLooping ( element.attribute(
"value",
"false" ) ==
"true" );
489 else if ( strName ==
"isRangedPlayback" )
491 data->setRangedPlayback( ( element.attribute(
"value",
"false" ) ==
"true" ) );
493 else if ( strName ==
"markInFrame" )
495 data->setMarkInFrameNumber( element.attribute(
"value",
"0" ).toInt() );
497 else if ( strName ==
"markOutFrame" )
499 data->setMarkOutFrameNumber( element.attribute(
"value",
"15" ).toInt() );
503 Object* FileManager::cleanUpWithErrorCode(
Status error )
506 removePFFTmpDirectory( mstrLastTempFolder );
510 bool FileManager::loadPalette(
Object* obj )
512 qCDebug( mLog ) <<
"Load Palette..";
514 QString paletteFilePath = obj->dataDir() +
"/" + PFF_PALETTE_FILE;
515 if ( !obj->importPalette( paletteFilePath ) )
517 obj->loadDefaultPalette();
522 void FileManager::unzip(
const QString& strZipFile,
const QString& strUnzipTarget )
525 removePFFTmpDirectory( strUnzipTarget );
528 JlCompress::extractDir( strZipFile, strUnzipTarget );
530 mstrLastTempFolder = strUnzipTarget;
535 QFileInfo fileInfo( strFilename );
536 if ( !fileInfo.exists() )
548 int curLayer = obj->data()->getCurrentLayer();
549 int maxLayer = obj->getLayerCount();
550 if ( curLayer >= maxLayer )
552 obj->data()->setCurrentLayer(maxLayer - 1);