removed PrefixPath debug line
[opentx.git] / companion / src / mdichild.cpp
bloba43005840fc8782958b715f8dd043d56a686f7bf
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the examples of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial Usage
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** GNU General Public License Usage
29 ** Alternatively, this file may be used under the terms of the GNU
30 ** General Public License version 3.0 as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL included in the
32 ** packaging of this file. Please review the following information to
33 ** ensure the GNU General Public License version 3.0 requirements will be
34 ** met: http://www.gnu.org/copyleft/gpl.html.
36 ** If you have questions regarding the use of this file, please contact
37 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include "mdichild.h"
43 #include "ui_mdichild.h"
44 #include "xmlinterface.h"
45 #include "hexinterface.h"
46 #include "mainwindow.h"
47 #include "modeledit/modeledit.h"
48 #include "generaledit/generaledit.h"
49 #include "burnconfigdialog.h"
50 #include "printdialog.h"
51 #include "flasheepromdialog.h"
52 #include "helpers.h"
53 #include "appdata.h"
54 #include "wizarddialog.h"
55 #include "flashfirmwaredialog.h"
56 #include <QFileInfo>
58 #if defined WIN32 || !defined __GNUC__
59 #include <windows.h>
60 #define sleep(x) Sleep(x*1000)
61 #else
62 #include <unistd.h>
63 #endif
65 MdiChild::MdiChild():
66 QWidget(),
67 ui(new Ui::mdiChild),
68 firmware(GetCurrentFirmware()),
69 isUntitled(true),
70 fileChanged(false)
72 ui->setupUi(this);
73 setWindowIcon(CompanionIcon("open.png"));
74 ui->SimulateTxButton->setIcon(CompanionIcon("simulate.png"));
75 setAttribute(Qt::WA_DeleteOnClose);
77 eepromInterfaceChanged();
79 if (!(this->isMaximized() || this->isMinimized())) {
80 adjustSize();
84 MdiChild::~MdiChild()
86 delete ui;
89 void MdiChild::qSleep(int ms)
91 if (ms<0)
92 return;
94 #if defined WIN32 || !defined __GNUC__
95 Sleep(uint(ms));
96 #else
97 struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
98 nanosleep(&ts, NULL);
99 #endif
102 void MdiChild::eepromInterfaceChanged()
104 ui->modelsList->refreshList();
105 ui->SimulateTxButton->setEnabled(GetCurrentFirmware()/*firmware*/->getCapability(Simulation));
106 updateTitle();
109 void MdiChild::cut()
111 ui->modelsList->cut();
114 void MdiChild::copy()
116 ui->modelsList->copy();
119 void MdiChild::paste()
121 ui->modelsList->paste();
124 bool MdiChild::hasPasteData()
126 return ui->modelsList->hasPasteData();
129 bool MdiChild::hasSelection()
131 return ui->modelsList->hasSelection();
134 void MdiChild::updateTitle()
136 QString title = userFriendlyCurrentFile() + "[*]" + " (" + GetCurrentFirmware()->getName() + QString(")");
137 if (!IS_SKY9X(GetCurrentFirmware()->getBoard()))
138 title += QString(" - %1 ").arg(EEPromAvail) + tr("free bytes");
139 setWindowTitle(title);
142 void MdiChild::setModified()
144 ui->modelsList->refreshList();
145 fileChanged = true;
146 updateTitle();
147 documentWasModified();
150 void MdiChild::on_SimulateTxButton_clicked()
152 startSimulation(this, radioData, -1);
155 void MdiChild::checkAndInitModel(int row)
157 ModelData &model = radioData.models[row - 1];
158 if (model.isempty()) {
159 model.setDefaultValues(row - 1, radioData.generalSettings);
160 setModified();
164 void MdiChild::generalEdit()
166 GeneralEdit *t = new GeneralEdit(this, radioData, GetCurrentFirmware()/*firmware*/);
167 connect(t, SIGNAL(modified()), this, SLOT(setModified()));
168 t->show();
171 void MdiChild::modelEdit()
173 int row = ui->modelsList->currentRow();
175 if (row == 0){
176 generalEdit();
178 else {
179 QApplication::setOverrideCursor(Qt::WaitCursor);
180 checkAndInitModel( row );
181 ModelData &model = radioData.models[row - 1];
182 ModelEdit *t = new ModelEdit(this, radioData, (row - 1), GetCurrentFirmware()/*firmware*/);
183 t->setWindowTitle(tr("Editing model %1: ").arg(row) + model.name);
184 connect(t, SIGNAL(modified()), this, SLOT(setModified()));
185 t->show();
186 QApplication::restoreOverrideCursor();
190 void MdiChild::wizardEdit()
192 int row = ui->modelsList->currentRow();
193 if (row > 0) {
194 checkAndInitModel(row);
195 WizardDialog * wizard = new WizardDialog(radioData.generalSettings, row, this);
196 wizard->exec();
197 if (wizard->mix.complete /*TODO rather test the exec() result?*/) {
198 radioData.models[row - 1] = wizard->mix;
199 setModified();
204 void MdiChild::openEditWindow()
206 int row = ui->modelsList->currentRow();
207 if (row == 0){
208 generalEdit();
210 else{
211 ModelData &model = radioData.models[row - 1];
212 if (model.isempty() && g.useWizard()) {
213 wizardEdit();
215 else {
216 modelEdit();
221 void MdiChild::newFile()
223 static int sequenceNumber = 1;
225 isUntitled = true;
226 curFile = QString("document%1.eepe").arg(sequenceNumber++);
227 updateTitle();
230 bool MdiChild::loadFile(const QString &fileName, bool resetCurrentFile)
232 QFile file(fileName);
234 if (!file.exists()) {
235 QMessageBox::critical(this, tr("Error"), tr("Unable to find file %1!").arg(fileName));
236 return false;
239 int fileType = getFileType(fileName);
241 #if 0
242 if (fileType==FILE_TYPE_XML) {
243 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { //reading HEX TEXT file
244 QMessageBox::critical(this, tr("Error"),
245 tr("Error opening file %1:\n%2.")
246 .arg(fileName)
247 .arg(file.errorString()));
248 return false;
250 QTextStream inputStream(&file);
251 XmlInterface(inputStream).load(radioData);
253 else
254 #endif
255 if (fileType==FILE_TYPE_HEX || fileType==FILE_TYPE_EEPE) { //read HEX file
256 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { //reading HEX TEXT file
257 QMessageBox::critical(this, tr("Error"),
258 tr("Error opening file %1:\n%2.")
259 .arg(fileName)
260 .arg(file.errorString()));
261 return false;
264 QDomDocument doc(ER9X_EEPROM_FILE_TYPE);
265 bool xmlOK = doc.setContent(&file);
266 if(xmlOK) {
267 if (loadEEpromXml(radioData, doc)){
268 ui->modelsList->refreshList();
269 if(resetCurrentFile) setCurrentFile(fileName);
270 return true;
273 file.reset();
275 QTextStream inputStream(&file);
277 if (fileType==FILE_TYPE_EEPE) { // read EEPE file header
278 QString hline = inputStream.readLine();
279 if (hline!=EEPE_EEPROM_FILE_HEADER) {
280 file.close();
281 return false;
285 QByteArray eeprom(EESIZE_MAX, 0);
286 int eeprom_size = HexInterface(inputStream).load((uint8_t *)eeprom.data(), EESIZE_MAX);
287 if (!eeprom_size) {
288 QMessageBox::critical(this, tr("Error"),
289 tr("Invalid EEPROM File %1")
290 .arg(fileName));
291 file.close();
292 return false;
295 file.close();
297 if (!loadEEprom(radioData, (uint8_t *)eeprom.data(), eeprom_size)) {
298 QMessageBox::critical(this, tr("Error"),
299 tr("Invalid EEPROM File %1")
300 .arg(fileName));
301 return false;
304 ui->modelsList->refreshList();
305 if(resetCurrentFile) setCurrentFile(fileName);
307 return true;
309 else if (fileType==FILE_TYPE_BIN) { //read binary
310 int eeprom_size = file.size();
312 if (!file.open(QFile::ReadOnly)) { //reading binary file - TODO HEX support
313 QMessageBox::critical(this, tr("Error"),
314 tr("Error opening file %1:\n%2.")
315 .arg(fileName)
316 .arg(file.errorString()));
317 return false;
319 uint8_t *eeprom = (uint8_t *)malloc(eeprom_size);
320 memset(eeprom, 0, eeprom_size);
321 long result = file.read((char*)eeprom, eeprom_size);
322 file.close();
324 if (result != eeprom_size) {
325 QMessageBox::critical(this, tr("Error"),
326 tr("Error reading file %1:\n%2.")
327 .arg(fileName)
328 .arg(file.errorString()));
330 return false;
333 if (!loadEEprom(radioData, eeprom, eeprom_size) && !::loadBackup(radioData, eeprom, eeprom_size, 0)) {
334 QMessageBox::critical(this, tr("Error"),
335 tr("Invalid binary EEPROM File %1")
336 .arg(fileName));
337 return false;
340 ui->modelsList->refreshList();
341 if(resetCurrentFile) setCurrentFile(fileName);
343 free(eeprom);
344 return true;
347 return false;
350 bool MdiChild::save()
352 if (isUntitled) {
353 return saveAs(true);
355 else {
356 return saveFile(curFile);
360 bool MdiChild::saveAs(bool isNew)
362 QString fileName;
363 if (IS_SKY9X(GetEepromInterface()->getBoard())) {
364 curFile.replace(".eepe", ".bin");
365 QFileInfo fi(curFile);
366 #ifdef __APPLE__
367 fileName = QFileDialog::getSaveFileName(this, tr("Save As"), g.eepromDir() + "/" +fi.fileName());
368 #else
369 fileName = QFileDialog::getSaveFileName(this, tr("Save As"), g.eepromDir() + "/" +fi.fileName(), tr(BIN_FILES_FILTER));
370 #endif
372 else {
373 QFileInfo fi(curFile);
374 #ifdef __APPLE__
375 fileName = QFileDialog::getSaveFileName(this, tr("Save As"), g.eepromDir() + "/" +fi.fileName());
376 #else
377 fileName = QFileDialog::getSaveFileName(this, tr("Save As"), g.eepromDir() + "/" +fi.fileName(), tr(EEPROM_FILES_FILTER));
378 #endif
380 if (fileName.isEmpty())
381 return false;
382 g.eepromDir( QFileInfo(fileName).dir().absolutePath() );
383 if (isNew)
384 return saveFile(fileName);
385 else
386 return saveFile(fileName,true);
389 bool MdiChild::saveFile(const QString &fileName, bool setCurrent)
391 QString myFile;
392 myFile = fileName;
393 if (IS_SKY9X(GetEepromInterface()->getBoard())) {
394 myFile.replace(".eepe", ".bin");
396 QFile file(myFile);
398 int fileType = getFileType(myFile);
400 uint8_t *eeprom = (uint8_t*)malloc(GetEepromInterface()->getEEpromSize());
401 int eeprom_size = 0;
403 if (fileType != FILE_TYPE_XML) {
404 eeprom_size = GetEepromInterface()->save(eeprom, radioData, GetCurrentFirmware()->getVariantNumber(), 0/*last version*/);
405 if (!eeprom_size) {
406 QMessageBox::warning(this, tr("Error"),tr("Cannot write file %1:\n%2.").arg(myFile).arg(file.errorString()));
407 return false;
411 if (!file.open(fileType == FILE_TYPE_BIN ? QIODevice::WriteOnly : (QIODevice::WriteOnly | QIODevice::Text))) {
412 QMessageBox::warning(this, tr("Error"),tr("Cannot write file %1:\n%2.").arg(myFile).arg(file.errorString()));
413 return false;
416 QTextStream outputStream(&file);
418 #if 0
419 if (fileType==FILE_TYPE_XML) {
420 if (!XmlInterface(outputStream).save(radioData)) {
421 QMessageBox::warning(this, tr("Error"),tr("Cannot write file %1:\n%2.").arg(myFile).arg(file.errorString()));
422 file.close();
423 return false;
426 else
427 #endif
428 if (fileType==FILE_TYPE_HEX || fileType==FILE_TYPE_EEPE) { // write hex
429 if (fileType==FILE_TYPE_EEPE)
430 outputStream << EEPE_EEPROM_FILE_HEADER << "\n";
432 if (!HexInterface(outputStream).save(eeprom, eeprom_size)) {
433 QMessageBox::warning(this, tr("Error"),tr("Cannot write file %1:\n%2.").arg(myFile).arg(file.errorString()));
434 file.close();
435 return false;
438 else if (fileType==FILE_TYPE_BIN) // write binary
440 long result = file.write((char*)eeprom, eeprom_size);
441 if(result!=eeprom_size) {
442 QMessageBox::warning(this, tr("Error"),tr("Error writing file %1:\n%2.").arg(myFile).arg(file.errorString()));
443 return false;
446 else {
447 QMessageBox::warning(this, tr("Error"),tr("Error writing file %1:\n%2.").arg(myFile).arg("Unknown format"));
448 return false;
451 free(eeprom); // TODO free in all cases ...
452 file.close();
453 if(setCurrent) setCurrentFile(myFile);
455 return true;
458 QString MdiChild::userFriendlyCurrentFile()
460 return strippedName(curFile);
463 void MdiChild::closeEvent(QCloseEvent *event)
465 if (maybeSave()) {
466 event->accept();
468 else {
469 event->ignore();
473 void MdiChild::documentWasModified()
475 setWindowModified(fileChanged);
478 bool MdiChild::maybeSave()
480 if (fileChanged) {
481 QMessageBox::StandardButton ret;
482 ret = QMessageBox::warning(this, tr("Companion"),
483 tr("%1 has been modified.\n"
484 "Do you want to save your changes?").arg(userFriendlyCurrentFile()),
485 QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
487 if (ret == QMessageBox::Save)
488 return save();
489 else if (ret == QMessageBox::Cancel)
490 return false;
492 return true;
495 void MdiChild::setCurrentFile(const QString &fileName)
497 curFile = QFileInfo(fileName).canonicalFilePath();
498 isUntitled = false;
499 fileChanged = false;
500 setWindowModified(false);
501 updateTitle();
502 int MaxRecentFiles = g.historySize();
503 QStringList files = g.recentFiles();
504 files.removeAll(fileName);
505 files.prepend(fileName);
506 while (files.size() > MaxRecentFiles)
507 files.removeLast();
509 g.recentFiles( files );
512 QString MdiChild::strippedName(const QString &fullFileName)
514 return QFileInfo(fullFileName).fileName();
517 void MdiChild::writeEeprom() // write to Tx
519 QString tempFile = generateProcessUniqueTempFileName("temp.bin");
520 saveFile(tempFile, false);
521 if(!QFileInfo(tempFile).exists()) {
522 QMessageBox::critical(this, tr("Error"), tr("Cannot write temporary file!"));
523 return;
526 FlashEEpromDialog *cd = new FlashEEpromDialog(this, tempFile);
527 cd->exec();
530 void MdiChild::simulate()
532 if (ui->modelsList->currentRow() >= 1) {
533 startSimulation(this, radioData, ui->modelsList->currentRow()-1);
537 void MdiChild::print(int model, QString filename)
539 PrintDialog * pd = NULL;
541 if (model>=0 && !filename.isEmpty()) {
542 pd = new PrintDialog(this, GetCurrentFirmware()/*firmware*/, &radioData.generalSettings, &radioData.models[model], filename);
544 else if (ui->modelsList->currentRow() > 0) {
545 pd = new PrintDialog(this, GetCurrentFirmware()/*firmware*/, &radioData.generalSettings, &radioData.models[ui->modelsList->currentRow()-1]);
548 if (pd) {
549 pd->setAttribute(Qt::WA_DeleteOnClose, true);
550 pd->show();
554 void MdiChild::viableModelSelected(bool viable)
556 emit copyAvailable(viable);
559 void MdiChild::setEEpromAvail(int eavail)
561 EEPromAvail=eavail;
564 bool MdiChild::loadBackup()
566 QString fileName = QFileDialog::getOpenFileName(this, tr("Open backup Models and Settings file"), g.eepromDir(),tr(EEPROM_FILES_FILTER));
567 if (fileName.isEmpty())
568 return false;
569 QFile file(fileName);
571 if (!file.exists()) {
572 QMessageBox::critical(this, tr("Error"), tr("Unable to find file %1!").arg(fileName));
573 return false;
575 if(ui->modelsList->currentRow()<1) return false;
576 int index=ui->modelsList->currentRow()-1;
578 int eeprom_size = file.size();
579 if (!file.open(QFile::ReadOnly)) { //reading binary file - TODO HEX support
580 QMessageBox::critical(this, tr("Error"),
581 tr("Error opening file %1:\n%2.")
582 .arg(fileName)
583 .arg(file.errorString()));
584 return false;
586 QByteArray eeprom(eeprom_size, 0);
587 long result = file.read((char*)eeprom.data(), eeprom_size);
588 file.close();
590 if (result != eeprom_size) {
591 QMessageBox::critical(this, tr("Error"),
592 tr("Error reading file %1:\n%2.")
593 .arg(fileName)
594 .arg(file.errorString()));
596 return false;
599 if (!::loadBackup(radioData, (uint8_t *)eeprom.data(), eeprom_size, index)) {
600 QMessageBox::critical(this, tr("Error"),
601 tr("Invalid binary backup File %1")
602 .arg(fileName));
603 return false;
606 ui->modelsList->refreshList();
608 return true;