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