From: <dhu...@us...> - 2007-02-09 20:26:38
|
Revision: 300 http://svn.sourceforge.net/qcell/?rev=300&view=rev Author: dhubleizh Date: 2007-02-09 12:26:35 -0800 (Fri, 09 Feb 2007) Log Message: ----------- - exporting works - no data checks - if it isn't a LIF function, things could happen... - menu Export option and so on... Modified Paths: -------------- trunk/qcell/parsers/Life-1.05/Life105ParserPlugin.cpp trunk/qcell/parsers/Life-1.05/Life105ParserPlugin.h trunk/qcell/visgui/MainWindow.cpp trunk/qcell/visgui/MainWindow.h trunk/qcell/visgui/MainWindow.ui Modified: trunk/qcell/parsers/Life-1.05/Life105ParserPlugin.cpp =================================================================== --- trunk/qcell/parsers/Life-1.05/Life105ParserPlugin.cpp 2007-02-09 13:16:59 UTC (rev 299) +++ trunk/qcell/parsers/Life-1.05/Life105ParserPlugin.cpp 2007-02-09 20:26:35 UTC (rev 300) @@ -13,10 +13,10 @@ << "Neighbourhood" << "LocalFunction" << "World"; - supported_file_types << "LIF"; + supported_file_types << "LIF" + << "LIFE"; } -/// @todo Incorporate genreal Function file to output resulting XML QString Life105ParserPlugin::realParser(const QByteArray content, const QString type, const QString subtype) { QStringList lines; @@ -28,8 +28,8 @@ LocalFunction lf; // Keep track of header bool header = true; - CalculationData cd; - QHash<QPoint, Universe> objects; + CalculationData *cd; + int version = -1; // Set up MCells Neighbourhood (Conways) Neighbourhood N; @@ -69,25 +69,31 @@ } // Function type - format = QRegExp("^#Life1\\.05$"); + format = QRegExp("^#Life 1\\.05$"); + QRegExp format2("^#Life 1\\.06$"); lines[0] = lines[0].trimmed(); if(format.exactMatch(lines[0])) { - lines.removeFirst(); - line_nr++; + version = 105; } + else if (format2.exactMatch(lines[0])) + { + version = 106; + } else { qDebug(tr("Wrong file specification in header line %1. Should be %2, but is %3.") .arg(line_nr) - .arg("#Life1.05") + .arg("#Life 1.05") .arg(lines[0]) .toAscii() ); return QString(); } + lines.removeFirst(); + line_nr++; // Dealing with the header - QRegExp comment("^#D.*$"); + QRegExp comment("^#(D|C|O).*$"); QRegExp conway("^#N$"); QRegExp rule("^#R [1-8]{1,8}/[1-8]{1,8}"); while (header) @@ -169,18 +175,178 @@ return QString(); } lines[0] = lines[0].trimmed(); - format = QRegExp("^(\\.|\\*)*$"); + switch (version) + { + case 105: + { + cd = parseIn105(&lines, line_nr); + break; + } + case 106: + { + cd = parseIn106(&lines, line_nr); + break; + } + } + // If error occurred while parsing, cd could be null + if (cd == NULL) + { + return QString(); + } + + if (type == "Neighbourhood") + { +// qDebug(N.toXmlString().toAscii()); + delete cd; + return N.toXmlString(); + } + else if (type == "LocalFunction") + { +// qDebug(lf.toXmlString().toAscii()); + delete cd; + return lf.toXmlString(); + } + else if (type == "World") + { +// qDebug(cd->toXmlString().toAscii()); + QString ret = cd->toXmlString(); + delete cd; + return ret; + } +} + +/// @todo Check N LF and CD if they really are apropriate to save them in LIF +QByteArray Life105ParserPlugin::parseOut(QString content, const QString type, const QString subtype) +{ + // The resulting array to write to file by the backend + QByteArray result; + + if (type == "Neighbourhood") + { + Neighbourhood N; + N.fromXmlString(&content); + // Check if we can use the generic type from the XML string + if(!N.fromXmlString(&content)) + { + qDebug(tr("Unable to parse out LocalFunction data!").toAscii()); + return QByteArray(); + } + + // Header + result.append("#Life 1.05\n"); + result.append("#D Generated by QCell\n"); + result.append("#D http://www.qcell.sourceforge.net"); + result.append("#O Cezary Krzy\xBFanowsky & Leszek Smentek 2007"); + } + else if (type == "LocalFunction") + { + LocalFunction lf; + // Check if we can use the generic type from the XML string + if(!lf.fromXmlString(&content)) + { + qDebug(tr("Unable to parse out Neighbourhood data!").toAscii()); + return QByteArray(); + } + + // Parse out LocalFunction + QList<int> survive_sums, born_sums; + for (int i = 0; i < 8; i++) + { + // When cell is 0 + if (lf.getValueAt(i * 2) == 1) + { + survive_sums.append(i); + } + // When cell i 1 + if (lf.getValueAt(i * 2 + 1)) + { + born_sums.append(i); + } + } + + result.append("#R "); + // Write down survive values + for (int i = 0; i < survive_sums.size(); i++) + { + result.append(QString::number(survive_sums[i]).toAscii()); + } + // Separator + result.append('/'); + // Write down born values + for (int i = 0; i < born_sums.size(); i++) + { + result.append(QString::number(born_sums[i]).toAscii()); + } + // Finally the line ends + result.append('\n'); + } + else if (type == "World") + { + CalculationData cd; + // Check if we can use the generic type from the XML string + if (!cd.setFromXmlString(&content)) + { + qDebug(tr("Unable to parse out Neighbourhood data!").toAscii()); + return QByteArray(); + } + // #P to place the object in the middle + result.append(QString("#P %1 %2\n") + .arg(-(cd.getSizeX() / 2 + 1)) + .arg(-(cd.getSizeY() / 2 + 1)) + .toAscii() + ); + + // Finally the universe writing + for (int y = 0; y < cd.getSizeY(); y++) + { + for (int x = 0; x < cd.getSizeX(); x++) + { + if (cd.getValueAt_i(x, y) == 0) + { + result.append('.'); + } + else + { + result.append('*'); + } + } + + // Break for each line + result.append('\n'); + } + } + + return result; +} + +CalculationData* Life105ParserPlugin::parseIn105(QStringList *lines, int line_nr) +{ + // The return object + CalculationData* cd = new CalculationData; + // Parsed objects holder + QHash<QPoint, Universe> objects; + + // Content line fotmat + QRegExp format = QRegExp("^(\\.|\\*)*$"); + // Coordinates line QRegExp coords("^#P (-)?(\\d)* (-)?(\\d)*$"); + // Empty line QRegExp line_separator("^\\.$"); + // Needed for universe size determination int min_x, max_x, min_y, max_y; min_x = max_x = min_y = max_y = 0; + // Holds the #P's line value QPoint tmp_point(0, 0); + // The object being read Universe tmp_object; - foreach(QString line, lines) + foreach(QString line, *lines) { if(format.exactMatch(line)) { + // Append new line to output for each input line tmp_object.append(QVector<bool>(line.size(), 0)); + // Parse the line in search of 1-s, as the resulting + // table is filled with 0-s by default for (int i = 0; i < line.size(); i++) { if (line[i] == '*') @@ -189,6 +355,7 @@ } } + // Check max exceeding if ((tmp_point.x() + line.size()) > max_x) { max_x = tmp_point.x() + line.size(); @@ -227,6 +394,7 @@ } else if (line_separator.exactMatch(line)) { + // Empty line while separator tmp_object.append(QVector<bool>()); } else if (!line.isEmpty()) @@ -236,7 +404,7 @@ .toAscii() ); - return QString(); + return NULL; } // To keep count of current line nr @@ -266,7 +434,7 @@ qDebug(tr("This file doesn't contain any object.") .toAscii() ); - return QString(); + return NULL; } //// Prepare the actual structures in QCell @@ -281,10 +449,10 @@ { size_y++; } - cd.resizeData(size_x, size_y); - QPoint center(cd.getSizeX()/2, cd.getSizeY()/2); + cd->resizeData(size_x, size_y); + QPoint center(cd->getSizeX()/2, cd->getSizeY()/2); // Fill the whole universe with 0-s - cd.fillData(0); + cd->fillData(0); // Actual object placement in the universe QHash<QPoint, Universe>::const_iterator i = objects.begin(); @@ -294,7 +462,7 @@ { for (int dx = 0; dx < i.value()[dy].size(); dx++) { - cd.setValueAt( + cd->setValueAt( (int)i.value()[dy][dx], /*value*/ center.x() + (i.key().x() + dx), /*x*/ center.y() + (i.key().y() + dy) /*y*/ @@ -304,68 +472,93 @@ ++i; } - if (type == "Neighbourhood") - { -// qDebug(N.toXmlString().toAscii()); - return N.toXmlString(); - } - else if (type == "LocalFunction") - { -// qDebug(lf.toXmlString().toAscii()); - return lf.toXmlString(); - } - else if (type == "World") - { -// qDebug(cd.toXmlString().toAscii()); - return cd.toXmlString(); - } + return cd; } - -QByteArray Life105ParserPlugin::parseOut(QString content, const QString type, const QString subtype) +CalculationData* Life105ParserPlugin::parseIn106(QStringList *lines, int line_nr) { - // The resulting array to write to file by the backend - QByteArray result; - // Generic type to parse XML request - LocalFunction lf; + CalculationData* cd = new CalculationData; - // Check if we can use the generic type from the XML string - if(!lf.fromXmlString(&content)); + QRegExp format = QRegExp("^-?(\\d)* -?(\\d)*$"); + QRegExp line_separator("^\\.$"); + int min_x, max_x, min_y, max_y; + min_x = max_x = min_y = max_y = 0; + QList<QPoint> points; + QPoint tmp_point; + QStringList numbers; + foreach(QString line, *lines) { - qDebug(tr("Unable to parse out internal data!").toAscii()); + if(format.exactMatch(line)) + { + // Split the line + numbers = line.split(' '); + tmp_point.setX(numbers[0].toInt()); + tmp_point.setY(numbers[1].toInt()); - return QByteArray(); + // Actually append the point + points.append(tmp_point); + + // Borders check + if (tmp_point.x() > max_x) + { + max_x = tmp_point.x(); + } + else if (tmp_point.x() < min_x) + { + min_x = tmp_point.x(); + } + + if (tmp_point.y() > max_y) + { + max_y = tmp_point.y(); + } + else if (tmp_point.y() < min_y) + { + min_y = tmp_point.y(); + } + } + else if (!line.isEmpty()) + { + qDebug(tr("Bogus characters in line %1.") + .arg(line_nr) + .toAscii() + ); + + return NULL; + } + + // To keep count of current line nr + line_nr++; } - // Header - result.append("Life105"); - result.append('\n'); - - // Second line - // Num of args - result.append(lf.getNumberOfArgs()); - result.append(' '); - // Num of arg values - result.append(lf.getAlphabetSize()); - result.append(' '); - // Num of return values - result.append(lf.getMaxReturnValues()); - result.append(' '); - result.append('\n'); + //// Prepare the actual structures in QCell + // Scale the universe to be SCALE times bigger then the object from file take + int size_x = (abs(min_x) + max_x) * SCALE; + if ((size_x % 2) == 0) + { + size_x++; + } + int size_y = (abs(min_y) + max_y) * SCALE; + if ((size_y % 2) == 0) + { + size_y++; + } - // Third line - summed args - foreach(int arg, lf.getSummedArguments()) + cd->resizeData(size_x, size_y); + QPoint center(cd->getSizeX()/2, cd->getSizeY()/2); + // Fill the whole universe with 0-s + cd->fillData(0); + + for (int i = 0; i < points.size(); i++) { - result.append(QString::number(arg)[0].toAscii()); - result.append(','); + cd->setValueAt( + 1, /*value*/ + center.x() + points[i].x(), /*x*/ + center.y() + points[i].y() /*y*/ + ); } - // Get rid of the penging `,' - result.chop(1); - result.append('\n'); - /// @todo Main function writing - - return result; + return cd; } Q_EXPORT_PLUGIN2(Life105FileParser, Life105ParserPlugin) Modified: trunk/qcell/parsers/Life-1.05/Life105ParserPlugin.h =================================================================== --- trunk/qcell/parsers/Life-1.05/Life105ParserPlugin.h 2007-02-09 13:16:59 UTC (rev 299) +++ trunk/qcell/parsers/Life-1.05/Life105ParserPlugin.h 2007-02-09 20:26:35 UTC (rev 300) @@ -14,6 +14,7 @@ #include <QList> #include <QHash> #include <QPoint> +#include <QDomDocument> #include "GenericParserPlugin.h" #include "Neighbourhood.h" @@ -21,7 +22,7 @@ #include "CalculationData.h" #define LIFE105_PARSER_TYPE "Function" -#define SCALE 5 +#define SCALE 2 typedef QVector<QVector<bool> > Universe; int qHash(const QPoint &point) @@ -33,6 +34,8 @@ { protected: QString realParser(const QByteArray content, const QString type, const QString subtype); + CalculationData* parseIn105(QStringList *lines, int line_nr); + CalculationData* parseIn106(QStringList *lines, int line_nr); public: Life105ParserPlugin(); Modified: trunk/qcell/visgui/MainWindow.cpp =================================================================== --- trunk/qcell/visgui/MainWindow.cpp 2007-02-09 13:16:59 UTC (rev 299) +++ trunk/qcell/visgui/MainWindow.cpp 2007-02-09 20:26:35 UTC (rev 300) @@ -275,7 +275,6 @@ } /// @todo This function doesn't belong here. It initializes things not fore GUI setupEngine(); - } void MainWindow::on_action_About_activated() @@ -667,6 +666,46 @@ /// @todo Wait for toXmlString file.write(world_parsers[subtype]->parseOut(sw->getStorage()->toXmlString(), type, subtype)); } + else if (type == "Import") + { + if (!import_parsers.contains(subtype)) + { + qDebug(tr("Exporting to %1 isn't supported") + .arg(subtype) + .toAscii() + ); + return; + } + + QByteArray result, tmp_result; + + // Neighbourhood checking + tmp_result = import_parsers[subtype]->parseOut(neighbourhood->toXmlString(), "Neighbourhood", subtype); + if (tmp_result.isEmpty()) + { + return; + } + result.append(QByteArray(tmp_result)); + + // LocalFunction parsing + tmp_result = import_parsers[subtype]->parseOut(local_function->toXmlString(), "LocalFunction", subtype); + if (tmp_result.isEmpty()) + { + return; + } + result.append(QByteArray(tmp_result)); + + // World parsing + tmp_result = import_parsers[subtype]->parseOut(sw->getStorage()->toXmlString(), "World", subtype); + if (tmp_result.isEmpty()) + { + return; + } + result.append(QByteArray(tmp_result)); + + // Finally - write to the file + file.write(result); + } else { qDebug(tr("Unsupported file type to parse.").toAscii()); @@ -1464,4 +1503,49 @@ action_World_save->setEnabled(true); } +void MainWindow::on_action_Export_activated() +{ + if(import_parsers.count() == 0) + { + QMessageBox::warning( + /*parent*/ this, + /*title*/ tr("Plugins warning"), + /*message*/ tr("There are no plugins loaded to handle exporting.") + ); + return; + } + + QFileDialog fd( + /*parent*/ this, + /*cation*/ tr("Export Experiment"), + /*dir*/ "." + ); + + fd.setAcceptMode(QFileDialog::AcceptSave); + fd.setFileMode(QFileDialog::AnyFile); + + QStringList filters; + QString filter; + // Add filter in format %{name} files (*.%{name}) + foreach(QString key, import_parsers.keys()) + { + // Don't shorten this, as it is made for translations + // purposes + filter = key + " " + tr("files") + " (*." + key + ")"; + filters << filter; + } + fd.setFilters(filters); + /// @todo Forge some real suffix adding + fd.setDefaultSuffix("*"); + + if(fd.exec()) + { + if(!fd.selectedFiles().isEmpty()) + { + callSaver(fd.selectedFiles().first(), "Import"); + + } + } +} + Modified: trunk/qcell/visgui/MainWindow.h =================================================================== --- trunk/qcell/visgui/MainWindow.h 2007-02-09 13:16:59 UTC (rev 299) +++ trunk/qcell/visgui/MainWindow.h 2007-02-09 20:26:35 UTC (rev 300) @@ -57,6 +57,7 @@ void on_action_Function_activated(); void on_action_World_activated(); void on_action_Import_activated(); + void on_action_Export_activated(); void on_action_World_save_activated(); void on_action_Neighbourhood_save_activated(); Modified: trunk/qcell/visgui/MainWindow.ui =================================================================== --- trunk/qcell/visgui/MainWindow.ui 2007-02-09 13:16:59 UTC (rev 299) +++ trunk/qcell/visgui/MainWindow.ui 2007-02-09 20:26:35 UTC (rev 300) @@ -102,6 +102,7 @@ <addaction name="action_Open_experiment" /> <addaction name="action_Continue_experiment" /> <addaction name="action_Import" /> + <addaction name="action_Export" /> <addaction name="menu_Save" /> <addaction name="action_Save_experiment" /> <addaction name="separator" /> @@ -167,7 +168,7 @@ <bool>false</bool> </property> <property name="text" > - <string>Open &experiment</string> + <string>Open ex&periment</string> </property> <property name="statusTip" > <string>Opens a predefined experiment.</string> @@ -334,6 +335,11 @@ <string>Imports experiments from other programs.</string> </property> </action> + <action name="action_Export" > + <property name="text" > + <string>&Export</string> + </property> + </action> </widget> <resources/> <connections/> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |