1.1 --- a/mapeditor.cpp Wed Feb 27 16:09:06 2008 +0000
1.2 +++ b/mapeditor.cpp Wed Feb 27 16:09:06 2008 +0000
1.3 @@ -145,6 +145,10 @@
1.4 autosaveTimer=new QTimer (this);
1.5 connect(autosaveTimer, SIGNAL(timeout()), this, SLOT(autosave()));
1.6
1.7 + fileChangedTimer=new QTimer (this);
1.8 + fileChangedTimer->start(3000);
1.9 + connect(fileChangedTimer, SIGNAL(timeout()), this, SLOT(fileChanged()));
1.10 +
1.11 // Network
1.12 netstate=Offline;
1.13
1.14 @@ -185,6 +189,7 @@
1.15 {
1.16 //cout <<"Destructor MapEditor\n";
1.17 autosaveTimer->stop();
1.18 + fileChangedTimer->stop();
1.19
1.20 // tmpMapDir is in tmpVymDir, so it gets removed automagically when vym closes
1.21
1.22 @@ -1498,7 +1503,7 @@
1.23 {
1.24 filePath=fpath; // becomes absolute path
1.25 fileName=fpath; // gets stripped of path
1.26 - destPath=destname; // needed for vymlinks
1.27 + destPath=destname; // needed for vymlinks and during load to reset fileChangedTime
1.28
1.29 // If fpath is not an absolute path, complete it
1.30 filePath=QDir(fpath).absPath();
1.31 @@ -1543,7 +1548,8 @@
1.32 ErrorCode err=success;
1.33
1.34 parseBaseHandler *handler;
1.35 - switch (ftype)
1.36 + fileType=ftype;
1.37 + switch (fileType)
1.38 {
1.39 case VymMap: handler=new parseVYMHandler; break;
1.40 case FreemindMap : handler=new parseFreemindHandler; break;
1.41 @@ -1575,14 +1581,72 @@
1.42 QString("Add map %1 to %2").arg(fname).arg(getName(bo)));
1.43 }
1.44
1.45 - QFile file( fname );
1.46 +
1.47 + // Create temporary directory for packing
1.48 + bool ok;
1.49 + QString tmpZipDir=makeTmpDir (ok,"vym-pack");
1.50 + if (!ok)
1.51 + {
1.52 + QMessageBox::critical( 0, tr( "Critical Load Error" ),
1.53 + tr("Couldn't create temporary directory before load\n"));
1.54 + return aborted;
1.55 + }
1.56 +
1.57 + // Try to unzip file
1.58 + err=unzipDir (tmpZipDir,fname);
1.59 + QString xmlfile;
1.60 + if (err==nozip)
1.61 + {
1.62 + xmlfile=fname;
1.63 + zipped=false;
1.64 + } else
1.65 + {
1.66 + zipped=true;
1.67 +
1.68 + // Look for mapname.xml
1.69 + xmlfile= fname.left(fname.findRev(".",-1,true));
1.70 + xmlfile=xmlfile.section( '/', -1 );
1.71 + QFile mfile( tmpZipDir + "/" + xmlfile + ".xml");
1.72 + if (!mfile.exists() )
1.73 + {
1.74 + // mapname.xml does not exist, well,
1.75 + // maybe someone renamed the mapname.vym file...
1.76 + // Try to find any .xml in the toplevel
1.77 + // directory of the .vym file
1.78 + QStringList flist=QDir (tmpZipDir).entryList("*.xml");
1.79 + if (flist.count()==1)
1.80 + {
1.81 + // Only one entry, take this one
1.82 + xmlfile=tmpZipDir + "/"+flist.first();
1.83 + } else
1.84 + {
1.85 + for ( QStringList::Iterator it = flist.begin(); it != flist.end(); ++it )
1.86 + *it=tmpZipDir + "/" + *it;
1.87 + // TODO Multiple entries, load all (but only the first one into this ME)
1.88 + //mainWindow->fileLoadFromTmp (flist);
1.89 + //returnCode=1; // Silently forget this attempt to load
1.90 + qWarning ("MainWindow::load (fn) multimap found...");
1.91 + }
1.92 +
1.93 + if (flist.isEmpty() )
1.94 + {
1.95 + QMessageBox::critical( 0, tr( "Critical Load Error" ),
1.96 + tr("Couldn't find a map (*.xml) in .vym archive.\n"));
1.97 + err=aborted;
1.98 + }
1.99 + } //file doesn't exist
1.100 + else
1.101 + xmlfile=mfile.name();
1.102 + }
1.103 +
1.104 + QFile file( xmlfile);
1.105
1.106 // I am paranoid: file should exist anyway
1.107 // according to check in mainwindow.
1.108 if (!file.exists() )
1.109 {
1.110 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1.111 - tr("Couldn't open map " +fname)+".");
1.112 + tr(QString("Couldn't open map %1").arg(file.name())));
1.113 err=aborted;
1.114 } else
1.115 {
1.116 @@ -1607,7 +1671,7 @@
1.117 file.close();
1.118 if ( ok )
1.119 {
1.120 - model->reposition();
1.121 + model->reposition(); // FIXME reposition the view instead...
1.122 xelection.update();
1.123 if (lmode==NewMap)
1.124 {
1.125 @@ -1616,6 +1680,9 @@
1.126 mapUnsaved=false;
1.127 autosaveTimer->stop();
1.128 }
1.129 +
1.130 + // Reset timestamp to check for later updates of file
1.131 + fileChangedTime=QFileInfo (destPath).lastModified();
1.132 } else
1.133 {
1.134 QMessageBox::critical( 0, tr( "Critical Parse Error" ),
1.135 @@ -1625,22 +1692,102 @@
1.136 // partially read by the parser
1.137 }
1.138 }
1.139 +
1.140 + // Delete tmpDir
1.141 + removeDir (QDir(tmpZipDir));
1.142 +
1.143 updateActions();
1.144 return err;
1.145 }
1.146
1.147 -int MapEditor::save (const SaveMode &savemode)
1.148 -{
1.149 +ErrorCode MapEditor::save (const SaveMode &savemode)
1.150 +{
1.151 + cout <<"ME::save zipped="<<zipped<<endl;
1.152 // Create mapName and fileDir
1.153 makeSubDirs (fileDir);
1.154 - QString fname;
1.155 - if (saveZipped())
1.156 + QString tmpZipDir;
1.157 + QString mapFileName;
1.158 + QString safeFilePath;
1.159 +
1.160 + ErrorCode err=success;
1.161 +
1.162 + if (zipped)
1.163 // save as .xml
1.164 - fname=mapName+".xml";
1.165 + mapFileName=mapName+".xml";
1.166 else
1.167 // use name given by user, even if he chooses .doc
1.168 - fname=fileName;
1.169 -
1.170 + mapFileName=fileName;
1.171 +
1.172 + // Look, if we should zip the data:
1.173 + if (!zipped)
1.174 + {
1.175 + QMessageBox mb( vymName,
1.176 + tr("The map %1\ndid not use the compressed "
1.177 + "vym file format.\nWriting it uncompressed will also write images \n"
1.178 + "and flags and thus may overwrite files in the "
1.179 + "given directory\n\nDo you want to write the map").arg(filePath),
1.180 + QMessageBox::Warning,
1.181 + QMessageBox::Yes | QMessageBox::Default,
1.182 + QMessageBox::No ,
1.183 + QMessageBox::Cancel | QMessageBox::Escape);
1.184 + mb.setButtonText( QMessageBox::Yes, tr("compressed (vym default)") );
1.185 + mb.setButtonText( QMessageBox::No, tr("uncompressed") );
1.186 + mb.setButtonText( QMessageBox::Cancel, tr("Cancel"));
1.187 + switch( mb.exec() )
1.188 + {
1.189 + case QMessageBox::Yes:
1.190 + // save compressed (default file format)
1.191 + zipped=true;
1.192 + break;
1.193 + case QMessageBox::No:
1.194 + // save uncompressed
1.195 + zipped=false;
1.196 + break;
1.197 + case QMessageBox::Cancel:
1.198 + // do nothing
1.199 + return aborted;
1.200 + break;
1.201 + }
1.202 + }
1.203 +
1.204 + // First backup existing file, we
1.205 + // don't want to add to old zip archives
1.206 + QFile f(destPath);
1.207 + if (f.exists())
1.208 + {
1.209 + if ( settings.value ("/mapeditor/writeBackupFile").toBool())
1.210 + {
1.211 + cout << "ME::doing backup...\n";//FIXME
1.212 + QString backupFileName(destPath + "~");
1.213 + QFile backupFile(backupFileName);
1.214 + if (backupFile.exists() && !backupFile.remove())
1.215 + {
1.216 + QMessageBox::warning(0, tr("Save Error"),
1.217 + tr("%1\ncould not be removed before saving").arg(backupFileName));
1.218 + }
1.219 + else if (!f.rename(backupFileName))
1.220 + {
1.221 + QMessageBox::warning(0, tr("Save Error"),
1.222 + tr("%1\ncould not be renamed before saving").arg(destPath));
1.223 + }
1.224 + }
1.225 + }
1.226 +
1.227 + if (zipped)
1.228 + {
1.229 + // Create temporary directory for packing
1.230 + bool ok;
1.231 + tmpZipDir=makeTmpDir (ok,"vym-zip");
1.232 + if (!ok)
1.233 + {
1.234 + QMessageBox::critical( 0, tr( "Critical Load Error" ),
1.235 + tr("Couldn't create temporary directory before save\n"));
1.236 + return aborted;
1.237 + }
1.238 +
1.239 + safeFilePath=filePath;
1.240 + setFilePath (tmpZipDir+"/"+ mapName+ ".xml", safeFilePath);
1.241 + } // zipped
1.242
1.243 QString saveFile;
1.244 if (savemode==CompleteMap || xelection.isEmpty())
1.245 @@ -1661,11 +1808,27 @@
1.246 // TODO take care of multiselections
1.247 }
1.248
1.249 - if (!saveStringToDisk(fileDir+fname,saveFile))
1.250 - return 1;
1.251 + if (!saveStringToDisk(fileDir+mapFileName,saveFile))
1.252 + {
1.253 + err=aborted;
1.254 + qWarning ("ME::saveStringToDisk failed!");
1.255 + }
1.256 +
1.257 + if (zipped)
1.258 + {
1.259 + // zip
1.260 + if (err==success) err=zipDir (tmpZipDir,destPath);
1.261 +
1.262 + // Delete tmpDir
1.263 + removeDir (QDir(tmpZipDir));
1.264 +
1.265 + // Restore original filepath outside of tmp zip dir
1.266 + setFilePath (safeFilePath);
1.267 + }
1.268
1.269 updateActions();
1.270 - return 0;
1.271 + fileChangedTime=QFileInfo (destPath).lastModified();
1.272 + return err;
1.273 }
1.274
1.275 void MapEditor::setZipped (bool z)
1.276 @@ -3937,7 +4100,7 @@
1.277 {
1.278 case QMessageBox::Yes:
1.279 // save
1.280 - break;;
1.281 + break;
1.282 case QMessageBox::Cancel:
1.283 // do nothing
1.284 delete (fd);
1.285 @@ -5046,13 +5209,65 @@
1.286
1.287 void MapEditor::autosave()
1.288 {
1.289 + QDateTime now=QDateTime().currentDateTime();
1.290 + /* FIXME debug
1.291 + */
1.292 + cout << "ME::autosave checking "<<qPrintable(filePath)<<"...\n";
1.293 + cout << "fsaved: "<<qPrintable (fileChangedTime.toString())<<endl;
1.294 + cout << " fnow: "<<qPrintable (QFileInfo(filePath).lastModified().toString())<<endl;
1.295 + cout << " time: "<<qPrintable (now.toString())<<endl;
1.296 // Disable autosave, while we have gone back in history
1.297 int redosAvail=undoSet.readNumEntry (QString("/history/redosAvail"));
1.298 if (redosAvail>0) return;
1.299
1.300
1.301 if (mapUnsaved &&mapChanged && settings.value ("/mapeditor/autosave/use",true).toBool() )
1.302 - mainWindow->fileSave (this);
1.303 + {
1.304 + if (QFileInfo(filePath).lastModified()<=fileChangedTime)
1.305 + mainWindow->fileSave (this);
1.306 + else
1.307 + if (debug)
1.308 + cout <<" ME::autosave rejected, file on disk is newer than last save.\n";
1.309 +
1.310 + }
1.311 +}
1.312 +
1.313 +void MapEditor::fileChanged()
1.314 +{
1.315 + // Check if file on disk has changed meanwhile
1.316 + if (!filePath.isEmpty())
1.317 + {
1.318 + QDateTime tmod=QFileInfo (filePath).lastModified();
1.319 + if (tmod>fileChangedTime)
1.320 + {
1.321 +
1.322 + /* FIXME debug message, sometimes there's a glitch in the metrics...
1.323 + cout << "ME::fileChanged()\n"
1.324 + << " last saved: "<<qPrintable (fileChangedTime.toString())<<endl
1.325 + << " last modififed: "<<qPrintable (tmod.toString())<<endl;
1.326 + */
1.327 + // FIXME switch to current mapeditor and finish lineedits...
1.328 + QMessageBox mb( vymName,
1.329 + tr("The file of the map on disk has changed:\n\n"
1.330 + " %1\n\nDo you want to reload this map with the new file?").arg(filePath),
1.331 + QMessageBox::Question,
1.332 + QMessageBox::Yes ,
1.333 + QMessageBox::Cancel | QMessageBox::Default,
1.334 + QMessageBox::NoButton );
1.335 +
1.336 + mb.setButtonText( QMessageBox::Yes, tr("Reload"));
1.337 + mb.setButtonText( QMessageBox::No, tr("Ignore"));
1.338 + switch( mb.exec() )
1.339 + {
1.340 + case QMessageBox::Yes:
1.341 + // Reload map
1.342 + load (filePath,NewMap,fileType);
1.343 + case QMessageBox::Cancel:
1.344 + fileChangedTime=tmod; // allow autosave to overwrite newer file!
1.345 + }
1.346 + }
1.347 + }
1.348 +
1.349 }
1.350
1.351