1 #include <QApplication>
2 #include <QFileDialog>
3 #include <QFileInfo>
4 #include <QFile>
5 #include <QTextStream>
6 #include <QDateTime>
7 #include <QByteArray>
8 #include <QBuffer>
9 #include <QXmlQuery>
10 #include <QMultiMap>
11 #include <QMessageBox>
12
13 #include "missingdumpsviewer.h"
14 #include "romalyzer.h"
15 #include "settings.h"
16 #include "options.h"
17 #include "macros.h"
18
19 extern Settings *qmc2Config;
20 extern Options *qmc2Options;
21
MissingDumpsViewer(QString settingsKey,QWidget * parent)22 MissingDumpsViewer::MissingDumpsViewer(QString settingsKey, QWidget *parent) :
23 #if defined(QMC2_OS_WIN)
24 QDialog(parent, Qt::Dialog)
25 #else
26 QDialog(parent, Qt::Dialog | Qt::SubWindow)
27 #endif
28 {
29 m_settingsKey = settingsKey;
30 setVisible(false);
31 setDefaultEmulator(false);
32 setupUi(this);
33 progressBar->hide();
34 }
35
on_toolButtonExportToDataFile_clicked()36 void MissingDumpsViewer::on_toolButtonExportToDataFile_clicked()
37 {
38 toolButtonExportToDataFile->setEnabled(false);
39 QString storedPath(qmc2Config->value(QMC2_FRONTEND_PREFIX + m_settingsKey + "/LastDataFilePath", QString()).toString());
40 QString dataFilePath(QFileDialog::getSaveFileName(this, tr("Choose data file to export to"), storedPath, tr("Data files (*.dat)") + ";;" + tr("All files (*)"), 0, qmc2Options->useNativeFileDialogs() ? (QFileDialog::Options)0 : QFileDialog::DontUseNativeDialog));
41 if ( !dataFilePath.isNull() ) {
42 QFile dataFile(dataFilePath);
43 QFileInfo fi(dataFilePath);
44 if ( dataFile.open(QIODevice::WriteOnly | QIODevice::Text) ) {
45 QTextStream ts(&dataFile);
46 ts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
47 ts << "<!DOCTYPE datafile PUBLIC \"-//Logiqx//DTD ROM Management Datafile//EN\" \"http://www.logiqx.com/Dats/datafile.dtd\">\n\n";
48 ts << "<datafile>\n";
49 ts << "\t<header>\n";
50 ts << "\t\t<name>" << fi.completeBaseName() << "</name>\n";
51 ts << "\t\t<description>" << fi.completeBaseName() << "</description>\n";
52 ts << "\t\t<category>FIXDATFILE</category>\n";
53 ts << "\t\t<version>" << QDateTime::currentDateTime().toString("MM/dd/yy hh:mm:ss") << "</version>\n";
54 ts << "\t\t<date>" << QDateTime::currentDateTime().toString("yyyy-MM-dd") << "</date>\n";
55 ts << "\t\t<author>auto-create</author>\n";
56 ts << "\t\t<email></email>\n";
57 ts << "\t\t<homepage></homepage>\n";
58 ts << "\t\t<url></url>\n";
59 ts << "\t\t<comment>" << tr("Created by QMC2 v%1").arg(XSTR(QMC2_VERSION)) << "</comment>\n";
60 ts << "\t</header>\n";
61 QString mainEntityName("machine");
62 QMultiMap<QString, DumpRecord *> dumpMap;
63 progressBar->setFormat(tr("Preparing"));
64 progressBar->setRange(0, treeWidget->topLevelItemCount());
65 progressBar->setValue(0);
66 progressBar->show();
67 for (int i = 0; i < treeWidget->topLevelItemCount(); i++) {
68 QTreeWidgetItem *item = treeWidget->topLevelItem(i);
69 if ( !checkBoxSelectedDumpsOnly->isChecked() || item->isSelected() )
70 dumpMap.insertMulti(item->text(QMC2_MDV_COLUMN_ID), new DumpRecord(item->text(QMC2_MDV_COLUMN_NAME), item->text(QMC2_MDV_COLUMN_TYPE), item->text(QMC2_MDV_COLUMN_SIZE), item->text(QMC2_MDV_COLUMN_CRC), item->text(QMC2_MDV_COLUMN_SHA1)));
71 progressBar->setValue(i);
72 }
73 QStringList dumpKeys(dumpMap.uniqueKeys());
74 progressBar->setFormat(tr("Exporting"));
75 progressBar->setRange(0, dumpKeys.count());
76 progressBar->setValue(0);
77 for (int i = 0; i < dumpKeys.count(); i++) {
78 QString id(dumpKeys.at(i));
79 if ( defaultEmulator() ) {
80 QString sourcefile, isbios, cloneof, romof, sampleof, description, year, manufacturer, merge;
81 QByteArray xmlDocument(ROMAlyzer::getXmlData(id, true).toUtf8());
82 QBuffer xmlQueryBuffer(&xmlDocument);
83 xmlQueryBuffer.open(QIODevice::ReadOnly);
84 QXmlQuery xmlQuery(QXmlQuery::XQuery10);
85 xmlQuery.bindVariable("xmlDocument", &xmlQueryBuffer);
86 xmlQuery.setQuery(QString("doc($xmlDocument)//%1/@sourcefile/string()").arg(mainEntityName));
87 xmlQuery.evaluateTo(&sourcefile);
88 sourcefile = sourcefile.trimmed();
89 xmlQuery.setQuery(QString("doc($xmlDocument)//%1/@isbios/string()").arg(mainEntityName));
90 xmlQuery.evaluateTo(&isbios);
91 isbios = isbios.trimmed();
92 xmlQuery.setQuery(QString("doc($xmlDocument)//%1/@cloneof/string()").arg(mainEntityName));
93 xmlQuery.evaluateTo(&cloneof);
94 cloneof = cloneof.trimmed();
95 xmlQuery.setQuery(QString("doc($xmlDocument)//%1/@romof/string()").arg(mainEntityName));
96 xmlQuery.evaluateTo(&romof);
97 romof = romof.trimmed();
98 xmlQuery.setQuery(QString("doc($xmlDocument)//%1/@sampleof/string()").arg(mainEntityName));
99 xmlQuery.evaluateTo(&sampleof);
100 sampleof = sampleof.trimmed();
101 xmlQuery.setQuery(QString("doc($xmlDocument)//%1/description/string()").arg(mainEntityName));
102 xmlQuery.evaluateTo(&description);
103 description = description.trimmed();
104 xmlQuery.setQuery(QString("doc($xmlDocument)//%1/year/string()").arg(mainEntityName));
105 xmlQuery.evaluateTo(&year);
106 year = year.trimmed();
107 xmlQuery.setQuery(QString("doc($xmlDocument)//%1/manufacturer/string()").arg(mainEntityName));
108 xmlQuery.evaluateTo(&manufacturer);
109 manufacturer = manufacturer.trimmed();
110 ts << "\t<machine name=\"" << id << "\"";
111 if ( !sourcefile.isEmpty() )
112 ts << " sourcefile=\"" << sourcefile << "\"";
113 if ( !isbios.isEmpty() && isbios != "no" )
114 ts << " isbios=\"" << isbios << "\"";
115 if ( !cloneof.isEmpty() )
116 ts << " cloneof=\"" << cloneof << "\"";
117 if ( !romof.isEmpty() )
118 ts << " romof=\"" << romof << "\"";
119 if ( !sampleof.isEmpty() )
120 ts << " sampleof=\"" << sampleof << "\"";
121 ts << ">\n";
122 if ( !description.isEmpty() )
123 ts << "\t\t<description>" << description << "</description>\n";
124 if ( !year.isEmpty() )
125 ts << "\t\t<year>" << year << "</year>\n";
126 if ( !manufacturer.isEmpty() )
127 ts << "\t\t<manufacturer>" << manufacturer << "</manufacturer>\n";
128 foreach (DumpRecord *dr, dumpMap.values(id)) {
129 if ( dr->type() == "ROM" ) {
130 ts << "\t\t<rom name=\"" << dr->name() << "\"";
131 xmlQuery.setQuery(QString("doc($xmlDocument)//%1/rom[@name='%2']/@merge/string()").arg(mainEntityName).arg(dr->name()));
132 xmlQuery.evaluateTo(&merge);
133 merge = merge.trimmed();
134 if ( !merge.isEmpty() )
135 ts << " merge=\"" << merge << "\"";
136 if ( !dr->size().isEmpty() )
137 ts << " size=\"" << dr->size() << "\"";
138 if ( !dr->crc().isEmpty() )
139 ts << " crc=\"" << dr->crc() << "\"";
140 if ( !dr->sha1().isEmpty() )
141 ts << " sha1=\"" << dr->sha1() << "\"";
142 ts << "/>\n";
143 } else {
144 ts << "\t\t<disk name=\"" << dr->name() << "\"";
145 xmlQuery.setQuery(QString("doc($xmlDocument)//%1/disk[@name='%2']/@merge/string()").arg(mainEntityName).arg(dr->name()));
146 xmlQuery.evaluateTo(&merge);
147 merge = merge.trimmed();
148 if ( !merge.isEmpty() )
149 ts << " merge=\"" << merge << "\"";
150 if ( !dr->sha1().isEmpty() )
151 ts << " sha1=\"" << dr->sha1() << "\"";;
152 ts << "/>\n";
153 }
154 delete dr;
155 }
156 ts << "\t</machine>\n";
157 } else {
158 // FIXME "non-default emulator"
159 }
160 if ( i % QMC2_FIXDAT_EXPORT_RESPONSE == 0 ) {
161 progressBar->setValue(i);
162 qApp->processEvents();
163 }
164 }
165 ts << "</datafile>\n";
166 dataFile.close();
167 dumpMap.clear();
168 progressBar->hide();
169 } else
170 QMessageBox::critical(this, tr("Error"), tr("Can't open '%1' for writing!").arg(dataFilePath));
171 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + m_settingsKey + "/LastDataFilePath", dataFilePath);
172 }
173 toolButtonExportToDataFile->setEnabled(true);
174 }
175
showEvent(QShowEvent * e)176 void MissingDumpsViewer::showEvent(QShowEvent *e)
177 {
178 restoreGeometry(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/" + m_settingsKey + "/Geometry", QByteArray()).toByteArray());
179 treeWidget->header()->restoreState(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/" + m_settingsKey + "/HeaderState", QByteArray()).toByteArray());
180 checkBoxSelectedDumpsOnly->setChecked(qmc2Config->value(QMC2_FRONTEND_PREFIX + m_settingsKey + "/SelectedDumpsOnly", false).toBool());
181 if ( e )
182 QDialog::showEvent(e);
183 }
184
hideEvent(QHideEvent * e)185 void MissingDumpsViewer::hideEvent(QHideEvent *e)
186 {
187 closeEvent(0);
188 if ( e )
189 QDialog::hideEvent(e);
190 }
191
closeEvent(QCloseEvent * e)192 void MissingDumpsViewer::closeEvent(QCloseEvent *e)
193 {
194 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/" + m_settingsKey + "/Geometry", saveGeometry());
195 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/" + m_settingsKey + "/HeaderState", treeWidget->header()->saveState());
196 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + m_settingsKey + "/SelectedDumpsOnly", checkBoxSelectedDumpsOnly->isChecked());
197 if ( e )
198 QDialog::closeEvent(e);
199 }
200