ViewVC Help
View File | Revision Log | View Changeset | Root Listing
root/Oni2/s10k/Vago/mainwindow.cpp
(Generate patch)

Comparing:
Vago/trunk/Vago/mainwindow.cpp (file contents), Revision 815 by s10k, Sat Apr 13 13:44:29 2013 UTC vs.
s10k/Vago/mainwindow.cpp (file contents), Revision 1093 by s10k, Sat Dec 30 13:57:32 2017 UTC

# Line 7 | Line 7 | MainWindow::MainWindow(QWidget *parent)
7      QMainWindow(parent),
8      ui(new Ui::MainWindow)
9   {
10 <    ui->setupUi(this);
11 <
12 <    this->AppDir=getOSIndependentAppPath();
10 >    // We use this appender because it is the native way to have \r\n in windows in plog library
11 >    // example: https://github.com/SergiusTheBest/plog/blob/master/samples/NativeEOL/Main.cpp
12 >    static plog::RollingFileAppender<plog::TxtFormatter, plog::NativeEOLConverter<>> fileAppender
13 >            (QSTR_TO_CSTR(Util::FileSystem::getAppPath() + "/" + GlobalVars::AppLogName), 1024*5 /* 5 Mb max log size */, 3);
14 >    plog::init(plog::info, &fileAppender);
15  
16 <    this->myLogger = new Logger(this->AppDir); //start logger
16 >    ui->setupUi(this);
17  
18 <    this->myLogger->writeString("Detected AppDir: "+this->AppDir);
19 <    this->myLogger->writeString("True app dir: "+QDir::currentPath());
18 >    LOG_INFO << "Detected AppDir: " + UtilVago::getAppPath();
19 >    LOG_INFO << "True app dir: "+QDir::currentPath();
20  
21 <    this->setWindowTitle("Vago v"+GlobalVars::AppVersion);
21 >    setVagoWindowTitle();
22  
23 <    if(!QFile::exists(this->AppDir+"/"+GlobalVars::OniSplitString)){
24 <        Util::showErrorPopUp("OniSplit not found. Please download it at "+GlobalVars::ModsDomain+" and put it in the same folder of Vago. \n\nProgram will now exit.");
23 >    if(!QFile::exists(UtilVago::getOniSplitExecutableAbsolutePath())){
24 >        UtilVago::showAndLogErrorPopUp("OniSplit not found. Please download it at "+GlobalVars::ModsDomain+" and put it the Vago's tools folder. \n\nProgram will now exit.");
25          exit(1);
26      }
27  
28 <    if(!QFile::exists(this->AppDir+"/"+GlobalVars::XmlToolsString)){
29 <        Util::showErrorPopUp("xmlTools not found. Please download it at "+GlobalVars::ModsDomain+" and put it in the same folder of Vago. \n\nProgram will now exit.");
28 >    if(!QFile::exists(UtilVago::getXmlToolsExecutableAbsolutePath())){
29 >        UtilVago::showAndLogErrorPopUp("XmlTools not found. Please download it at "+GlobalVars::ModsDomain+" and put it the Vago's tools folder. \n\nProgram will now exit.");
30          exit(1);
31      }
32  
33 <    this->vagoSettings = new QSettings(this->AppDir + "/" + this->VagoSettingsName, QSettings::IniFormat);
33 >    this->vagoSettings = new QSettings(UtilVago::getAppPath() + "/" + this->VagoSettingsName, QSettings::IniFormat);
34  
35      //First Execution? Old configuration? Settings missed?
36      bool iniChanged=false;
# Line 37 | Line 39 | MainWindow::MainWindow(QWidget *parent)
39          iniChanged=true;
40      }
41      if(!this->vagoSettings->contains("Workspace")){
42 <        this->vagoSettings->setValue("Workspace", this->AppDir+"/VagoWorkspace");
42 >        this->vagoSettings->setValue("Workspace", UtilVago::getAppPath()+"/VagoWorkspace");
43          iniChanged=true;
44      }
45      if(!this->vagoSettings->contains("AeFolder")){
46  
47 <        Util::showPopUp("Seems it's the first time you are executing Vago. \n\nPlease input your Anniversary Edition (AE) Folder.");
48 <        QString aefolder=Util::normalizePath(QFileDialog::getExistingDirectory(this,"Choose Anniversary Edition (AE) folder..."));
47 >        Util::Dialogs::showInfo("Seems it's the first time you are executing Vago. \n\nPlease input your Anniversary Edition (AE) Folder.");
48 >        QString aefolder=Util::FileSystem::normalizePath(QFileDialog::getExistingDirectory(this,"Choose Anniversary Edition (AE) folder..."));
49  
50          if(aefolder.isEmpty()){
51 <            Util::showErrorPopUp("AE folder is mandatory. Application will now exit.");
51 >            UtilVago::showAndLogErrorPopUp("AE folder is mandatory. Application will now exit.");
52              exit(1);
53          }
54  
55          if(!aefolder.endsWith("AE")){
56 <            Util::showWarningPopUp("Seems the folder you selected isn't called 'AE'. \n\nIf you run in any problems you can always change it in Vago preferences window.");
56 >            Util::Dialogs::showWarning("Seems the folder you selected isn't called 'AE'. \n\nIf you run in any problems you can always change it in Vago preferences window.");
57          }
58  
59          this->vagoSettings->setValue("AeFolder", aefolder);
60          iniChanged=true;
61      }
62 +    if(!this->vagoSettings->contains("WindowWidth")){
63 +        this->vagoSettings->setValue("WindowWidth", GlobalVars::DefaultWindowWidth);
64 +        iniChanged=true;
65 +    }
66 +    if(!this->vagoSettings->contains("WindowHeight")){
67 +        this->vagoSettings->setValue("WindowHeight", GlobalVars::DefaultWindowHeight);
68 +        iniChanged=true;
69 +    }
70      if(!this->vagoSettings->contains("OniWindow")){
71          this->vagoSettings->setValue("OniWindow", true);
72          iniChanged=true;
# Line 65 | Line 75 | MainWindow::MainWindow(QWidget *parent)
75          this->vagoSettings->setValue("SeparateInWorkspace",true);
76          iniChanged=true;
77      }
78 <    if(!this->vagoSettings->contains("ConfirmExit")){
79 <        this->vagoSettings->setValue("ConfirmExit", false);
78 >    if(!this->vagoSettings->contains("AskSaveProject")){
79 >        this->vagoSettings->setValue("AskSaveProject", true);
80 >        iniChanged=true;
81 >    }
82 >    if(!this->vagoSettings->contains("AskToOpenLastProject")){
83 >        this->vagoSettings->setValue("AskToOpenLastProject", false);
84          iniChanged=true;
85      }
86 +    if(!this->vagoSettings->contains("LastProjectPath")){
87 +        this->vagoSettings->setValue("LastProjectPath", this->vagoSettings->value("Workspace"));
88 +        iniChanged=true;
89 +    }
90 +    for(int i=0; i<this->recentProjectsMaxSize; i++){
91 +        if(!this->vagoSettings->contains("RecentProject" + QString::number(i+1))){
92 +            this->vagoSettings->setValue("RecentProject" + QString::number(i+1), "");
93 +            iniChanged=true;
94 +        }
95 +    }
96 + #ifdef Q_OS_MAC
97 +    if(!this->vagoSettings->contains("useYesAsDefaultWhenRemovingItems")){
98 +        this->vagoSettings->setValue("useYesAsDefaultWhenRemovingItems", false);
99 +        iniChanged=true;
100 +    }
101 + #endif
102  
103      if(iniChanged){
104          this->vagoSettings->sync();
# Line 79 | Line 109 | MainWindow::MainWindow(QWidget *parent)
109      this->workspaceWizardsLocation=this->workspaceLocation+"/Wizards";
110      this->AeLocation=this->vagoSettings->value("AeFolder").toString();
111      this->outputFolder=this->workspaceLocation;
112 +    this->startedWindowWidth=this->vagoSettings->value("WindowWidth").toInt();
113 +    this->startedWindowHeight=this->vagoSettings->value("WindowHeight").toInt();
114 + #ifdef Q_OS_MAC
115 +    this->useYesAsDefaultWhenRemovingItems=this->vagoSettings->value("useYesAsDefaultWhenRemovingItems").toBool();
116 + #endif
117  
118      //Create our workspace if it doesn't exists yet
119      if(!QDir(this->workspaceLocation).exists()){
# Line 92 | Line 127 | MainWindow::MainWindow(QWidget *parent)
127      this->myBar->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Fixed);
128      this->myBar->setMinimumWidth(150);
129      this->myBar->hide(); //hide while not being used
130 +    ui->tbAbortConversion->hide(); //hide while not being used
131  
132 <    ui->statusBar->addPermanentWidget(myBar); //this adds automatically in right
133 <
98 <    //Initialize list pointers
99 <    this->listToProccess = new QStringList;
100 <
101 <    //Create a thread for do the conversion in background
102 <    this->myConverter = new Converter(this->AppDir,this->myLogger,this->listToProccess);
132 >    ui->statusBar->addPermanentWidget(this->myBar); //this adds automatically in right
133 >    ui->statusBar->addPermanentWidget(ui->tbAbortConversion);
134  
135      // User interface
136      ui->mainToolBar->addWidget(ui->tbAE); //add ae installer launch button
# Line 108 | Line 139 | MainWindow::MainWindow(QWidget *parent)
139      ui->mainToolBar->addWidget(ui->emptySpacerLabel2); //same as before
140      ui->mainToolBar->addWidget(ui->tbCommand); //add option to manual onisplit commands
141      ui->mainToolBar->addWidget(ui->emptySpacerLabel3); //same as before
142 +    ui->mainToolBar->addWidget(ui->tbXmlToolsInterface); //add option to manual onisplit commands
143 +    ui->mainToolBar->addWidget(ui->emptySpacerLabel4); //same as before
144      ui->mainToolBar->addWidget(ui->tbOpenFolder); //add option to open folder with files converted etc
145  
146      ui->mainToolBar->setLayoutDirection(Qt::RightToLeft);
147  
148 <    setConverterButtonsSize();
148 >    ui->pbConvert->setMinimumHeight(ui->pbConvert->sizeHint().height()*1.5); // This is OS indepented. It maintain size ratio over the Windows and Mac.
149 >
150  
151 < #ifdef Q_WS_MAC
151 > #ifdef Q_OS_MAC
152      // setUnifiedTitleAndToolBarOnMac(true); // Qt suggests to use it on mac | http://www.slideshare.net/qtbynokia/how-to-make-your-qt-app-look-native // align on left doesn't work if active
153      ui->tbOni->setIcon(QIcon(":/new/icons/oni_icon_mac.png")); // Oni executable on mac have a different icon than windows
154      // Set mac platform the first one in the menu, and also make it checkable by default
# Line 122 | Line 156 | MainWindow::MainWindow(QWidget *parent)
156      ui->menuTarget_Platform->addAction(ui->actionWindows);
157      ui->actionWindows->setChecked(false);
158      ui->actionMac_Windows_demo->setChecked(true);
159 <    resize(800,600); // Mac OS pcs should be able to render this resolution without any problem. It's also better
160 <    // because the components on mac use more space
127 < #else
128 <    resize(640,480);
159 >    // resize(800,600); // Mac OS pcs should be able to render this resolution without any problem. It's also better
160 >    //// because the components on mac use more space
161   #endif
162  
163 <    connectSlots();
163 >    resize(this->startedWindowWidth,this->startedWindowHeight);
164 >
165 > #ifdef Q_OS_MAC
166 >    ui->pbConvert->setToolTip(ui->pbConvert->toolTip() + " (⌘ + Enter)");
167 > #else
168 >    ui->pbConvert->setToolTip(ui->pbConvert->toolTip() + " (Ctrl + Enter)");
169 > #endif
170  
171      //Commands Mapping
172      this->commandMap = QHash<QString, QString>();
173      mapCommands();
174  
175 <    updateItemsLoaded(ui->twSourcesGeneral);
175 >    updateItemsLoaded(ui->twSourcesXML);
176  
177 <    this->myLogger->writeString("Application started.");
177 >    loadRecentProjects();
178   }
179  
180   MainWindow::~MainWindow()
181   {
182      delete ui;
183 <    this->myLogger->writeString("Application Exited.");
183 >    LOG_INFO << "Application Exited.";
184 > }
185 >
186 >
187 > void MainWindow::showEvent(QShowEvent *e)
188 > {
189 >    // If we don't have a converter yet, application wasn't started.
190 >    if(!this->applicationIsFullyLoaded)
191 >    {
192 >        // Apparently Qt doesn't contains a slot to when the application was fully load (mainwindow). So we do our own implementation instead.
193 >        connect(this, SIGNAL(signalAppIsLoaded()), this, SLOT(applicationWasLoaded()), Qt::ConnectionType::QueuedConnection);
194 >        emit signalAppIsLoaded();
195 >    }
196 >
197 >    e->accept();
198   }
199  
200 + // Called only when the MainWindow was fully loaded and painted on the screen. This slot is only called once.
201 + void MainWindow::applicationWasLoaded(){
202 + #ifdef Q_OS_WIN
203 +    // QProgressBar only works after the windows was shown
204 +    // http://stackoverflow.com/questions/24840941/qwintaskbarprogress-wont-show (Kervala answer)
205 +
206 +    this->win7TaskBarButton = new QWinTaskbarButton();
207 +
208 +    this->win7TaskBarButton->setWindow(this->windowHandle());
209 +
210 +    this->win7TaskBarProgress = this->win7TaskBarButton->progress();
211 +
212 +    //Create a thread for do the conversion in background
213 +    this->myConverter = new Converter(UtilVago::getAppPath(), &this->listToProccess, this->win7TaskBarProgress);
214 + #else
215 +    this->myConverter = new Converter(UtilVago::getAppPath(), &this->listToProccess);
216 + #endif
217 +
218 +    connectSlots();
219 +
220 +    LOG_INFO << "Application started.";
221 +
222 +    this->applicationIsFullyLoaded = true;
223 +
224 +    QString lastSavedProject = this->vagoSettings->value("RecentProject1").toString();
225 +
226 +    if(!lastSavedProject.isEmpty() && this->vagoSettings->value("AskToOpenLastProject").toBool()){
227 +        if(Util::Dialogs::showQuestion(this,"Do you want to load latest project?\n\nLatest project was '" + Util::FileSystem::cutNameWithoutBackSlash(lastSavedProject) + "'.")){
228 +            loadProjectState(lastSavedProject);
229 +        }
230 +    }
231 + }
232 +
233 +
234   void MainWindow::on_actionExit_triggered()
235   {
236      close();
# Line 159 | Line 245 | void MainWindow::on_actionAbout_triggere
245  
246   void MainWindow::on_actionAE_Package_Creator_triggered()
247   {
248 <    PackageWizard myWizard = PackageWizard(this->workspaceWizardsLocation, this->vagoSettings, this->myLogger);
249 <    myWizard.exec();
248 >    // it deletes itself once closed
249 >    WizardFactory<PackageWizard>::startInstance(UtilVago::getAppPath(), this->workspaceWizardsLocation, this->vagoSettings);
250   }
251  
252   void MainWindow::on_actionSound_Wizard_triggered()
253   {
254 <    SoundWizard myWizard (this->AppDir, this->workspaceWizardsLocation, this->myLogger, &this->commandMap);
255 <    myWizard.exec();
254 >    // it deletes itself once closed
255 >    WizardFactory<SoundWizard>::startInstance(UtilVago::getAppPath(), this->workspaceWizardsLocation, this->vagoSettings, &this->commandMap);
256 > }
257 >
258 > void MainWindow::on_actionBackground_Image_Wizard_triggered()
259 > {
260 >    // it deletes itself once closed
261 >    WizardFactory<BGImageWizard>::startInstance(UtilVago::getAppPath(), this->workspaceWizardsLocation, this->vagoSettings);
262 > }
263 >
264 > void MainWindow::on_actionWindow_Messages_Wizard_triggered()
265 > {
266 >    // it deletes itself once closed
267 >    WizardFactory<WmWizard>::startInstance(UtilVago::getAppPath(), this->workspaceWizardsLocation, this->vagoSettings);
268   }
269  
270   void MainWindow::on_tbOni_clicked()
# Line 176 | Line 274 | void MainWindow::on_tbOni_clicked()
274      if(this->vagoSettings->value("OniWindow").toBool()){ // Run in a window?
275          arguments << "-noswitch";
276      }
277 < #ifdef Q_WS_WIN
277 > #ifdef Q_OS_WIN
278      else{
279          arguments << "-switch"; // only supported on windows. Was added by daodan dll.
280      }
# Line 185 | Line 283 | void MainWindow::on_tbOni_clicked()
283      arguments << "-debugfiles";
284  
285      if(!QProcess::startDetached(this->AeLocation+"/"+GlobalVars::OniExe,arguments,this->AeLocation)){
286 <        showErrStatusMessage("Oni could not be started!");
286 >        Util::StatusBar::showError(ui->statusBar, "Oni could not be started!");
287      }
288   }
289  
# Line 194 | Line 292 | void MainWindow::on_tbAE_clicked()
292      // If the app turn out someday to a native app use QProcess::startDetached instead...
293  
294      if(!QDesktopServices::openUrl("file:///"+this->AeLocation+"/AEInstaller/bin/AEInstaller2.jar")){
295 <        showErrStatusMessage("Could not start AE Installer!");
295 >        Util::StatusBar::showError(ui->statusBar, "Could not start AE Installer!");
296      }
297   }
298  
# Line 203 | Line 301 | void MainWindow::on_tbOpenFolder_clicked
301      QDesktopServices::openUrl(QUrl("file:///"+this->outputFolder));
302   }
303  
304 +
305 + void MainWindow::on_tbXmlToolsInterface_clicked()
306 + {
307 +    //We pass no parent because we want to have an independent window for XmlToolsInterface,
308 +    //so we can minimize it or maximize indepently from the MainWindow
309 +    XmlToolsInterface *xmlToolsWindow = new XmlToolsInterface();
310 +    xmlToolsWindow->show(); //it destroys itself when finished.
311 + }
312 +
313 + void MainWindow::on_tbAbortConversion_clicked()
314 + {
315 +    if(Util::Dialogs::showQuestion(this,"Are you sure you want to abort the current conversion?")){
316 +        emit terminateCurrProcess();
317 +    }
318 + }
319 +
320   void MainWindow::on_cbEnvMap_toggled(bool checked)
321   {
322      ui->leEnvMapTexture->setEnabled(checked);
# Line 213 | Line 327 | void MainWindow::on_cbTexture_toggled(bo
327      ui->leTextureName->setEnabled(checked);
328   }
329  
330 < void MainWindow::on_cbWithAnimation_toggled(bool checked)
330 > void MainWindow::on_cbSpecificFilesLevels_toggled(bool checked)
331   {
332 <    ui->leAnimationName->setEnabled(checked);
219 < }
220 <
221 < void MainWindow::on_cbCamera_toggled(bool checked)
222 < {
223 <    if(checked){
224 <        ui->cbGeometry->setChecked(false);
225 <    }
332 >    ui->leSpecificFilesLevels->setEnabled(checked);
333   }
334  
335 < void MainWindow::on_cbGeometry_toggled(bool checked)
335 > void MainWindow::on_cbWithAnimation_toggled(bool checked)
336   {
337 <    ui->leGeometryName->setEnabled(checked);
231 <    if(checked){
232 <        ui->cbCamera->setChecked(false);
233 <    }
337 >    ui->leAnimationName->setEnabled(checked);
338   }
339  
340   void MainWindow::on_actionCheck_For_Updates_triggered()
# Line 256 | Line 360 | void MainWindow::checkVagoLastVersion(QN
360          QString newVersion = sc.property("field_version").toObject().property("und").toObject().property("0").toObject().property("value").toString();
361  
362          if(newVersion!=GlobalVars::AppVersion){
363 <            Util::showRichPopUp("There's a new version of Vago! (v"+newVersion+")<br/><br/>"+
364 <                                "You can download it <a href='"+GlobalVars::VagoWebUrl+"'>here</a>.");
363 >            Util::Dialogs::showRichInfo("There's a new version of Vago! (v"+newVersion+")<br/><br/>"+
364 >                                        "You can download it <a href='"+GlobalVars::VagoWebUrl+"'>here</a>.");
365          }
366          else{
367 <            Util::showPopUp("You are using last version.");
367 >            Util::Dialogs::showInfo("You are using last version.");
368          }
369      }
370      else{
371 <        Util::showErrorPopUp("An error occurred checking last version:\n\n"+result->errorString());
371 >        UtilVago::showAndLogErrorPopUp("An error occurred checking last version:\n\n"+result->errorString());
372      }
373      result->deleteLater();
374   }
375  
376 < void MainWindow::on_pbAddSourceGeneral_clicked()
376 > void MainWindow::on_pbAddSourceXML_clicked()
377   {
378 <    if(QString::compare(ui->cbFromGeneral->currentText(),"ONI",Qt::CaseSensitive)==0 && QString::compare(ui->cbToGeneral->currentText(),"DAT",Qt::CaseSensitive)==0){ //CaseSensitive is faster)
275 <        addFilesSource(ui->twSourcesGeneral,Util::multipleDirDialog("Choose folders with ONIs..."));
276 <    }
277 <    else{
278 <        addFilesSource( ui->twSourcesGeneral,QFileDialog::getOpenFileNames(this,"Choose the files...","./" , "All Files (*.*)"));
279 <    }
378 >    addFilesSource( ui->twSourcesXML,QFileDialog::getOpenFileNames(this,"Choose the files...","./" , "All Files (*.*)"));
379   }
380  
381   void MainWindow::on_pbAddSourceTextures_clicked()
# Line 284 | Line 383 | void MainWindow::on_pbAddSourceTextures_
383      addFilesSource( ui->twSourcesTextures, QFileDialog::getOpenFileNames(this,"Choose the files...","./" , "All Files (*.*)"));
384   }
385  
386 < void MainWindow::on_pbAddSourceModels_clicked()
386 > void MainWindow::on_pbAddSourceObjects_clicked()
387   {
388 <    addFilesSource( ui->twSourcesModels,QFileDialog::getOpenFileNames(this,"Choose the files...","./" , "All Files (*.*)"));
388 >    addFilesSource( ui->twSourcesObjects,QFileDialog::getOpenFileNames(this,"Choose the files...","./" , "All Files (*.*)"));
389   }
390  
391 < void MainWindow::on_pbAddSourceAnimations_clicked()
391 > void MainWindow::on_pbAddSourceCharacters_clicked()
392   {
393 <    addFilesSource( ui->twSourcesAnimations,QFileDialog::getOpenFileNames(this,"Choose the files...","./" , "All Files (*.*)"));
393 >    addFilesSource( ui->twSourcesCharacters,QFileDialog::getOpenFileNames(this,"Choose the files...","./" , "All Files (*.*)"));
394   }
395  
396   void MainWindow::on_pbAddSourceLevels_clicked()
397   {
398 <    addFilesSource( ui->twSourcesLevels,QFileDialog::getOpenFileNames(this,"Choose the files...","./" , "All Files (*.*)"));
398 >    if(QString::compare(ui->cbFromLevels->currentText(),"ONI FILES",Qt::CaseSensitive)==0 && QString::compare(ui->cbToLevels->currentText(),"DAT",Qt::CaseSensitive)==0){ //CaseSensitive is faster)
399 >        addFilesSource(ui->twSourcesLevels,Util::Dialogs::multipleDirSelection("Choose folders with ONIs..."));
400 >    }
401 >    else{
402 >        addFilesSource(ui->twSourcesLevels,QFileDialog::getOpenFileNames(this,"Choose the files...","./" , "All Files (*.*)"));
403 >    }
404   }
405  
406   void MainWindow::on_pbAddSourceMisc_clicked()
# Line 314 | Line 418 | QString MainWindow::getFileOutputFolder(
418          myOutputFolder+="/"+ui->tabWidget->tabText(ui->tabWidget->currentIndex());
419          myOutputFolder+="/"+QString(fromTo).replace(" / ","_").replace(" > "," - ");
420      }
421 <    return Util::insertQuotes(myOutputFolder+"/");
421 >    return Util::String::insertQuotes(myOutputFolder+"/");
422   }
423  
424   void MainWindow::addFilesSource(DropTableWidget *myTable, QStringList files){
# Line 327 | Line 431 | void MainWindow::addFilesSource(DropTabl
431      from = QString(fromTo).remove(fromTo.indexOf(" >"),fromTo.size()-1); //parse the string to get the from, only 1 time parsed by each group of files = very fast
432      to = QString(fromTo).remove(0,fromTo.lastIndexOf("> ")+2); //+2 to start after "> "
433  
434 <    //Pre-processing (check if the files/folders received are valid), e.g. check for ONI->DAT if are only given folders and not files
435 <    if(QString::compare(from,"ONI",Qt::CaseSensitive)==0 && QString::compare(to,"DAT",Qt::CaseSensitive)==0){
434 >    //Pre-processing (check if the files/folders received are valid), e.g. check for ONI FILES->DAT if are only given folders and not files
435 >    if(from=="ONI FILES" && to=="DAT"){
436          //check if it's a folder
437 <        foreach(QString myFile, files){
437 >        for(const QString &myFile : files){
438              if(!QDir(myFile).exists()){
439 <                showErrStatusMessage("Only folders are allowed for this operation.");
439 >                Util::StatusBar::showError(ui->statusBar, "Only folders are allowed for this operation.");
440                  return;
441              }
442          }
443  
444      }
445      else{
446 <        foreach(QString myFile, files){
446 >        for(const QString &myFile : files){
447 >
448              //check if it's a file
449              if(QDir(myFile).exists()){
450 <                showErrStatusMessage("Only files are allowed for this operation.");
450 >                Util::StatusBar::showError(ui->statusBar, "Only files are allowed for this operation.");
451 >                return;
452 >            }
453 >
454 >            // Check if the given files have the expected extensions
455 >            QFileInfo fileInfo(myFile);
456 >
457 >            QStringList expectedExtensions;
458 >
459 >            bool extensionIsValid = false;
460 >
461 >            if(
462 >                    from == "DAT / TXMP ONI" ||
463 >                    from == "DAT / SNDD ONI" ||
464 >                    from == "DAT / SUBT ONI"
465 >                    ){
466 >                expectedExtensions << "DAT" << "ONI";
467 >            }
468 >            else if(from == "TGA / DDS / PNG / JPG"){
469 >                expectedExtensions << "TGA" << "DDS" << "PNG" << "JPG";
470 >            }
471 >            else if(
472 >                    from == "TRAM ONI" ||
473 >                    from == "TRBS / ONCC ONI" ||
474 >                    from == "M3GM ONI" ||
475 >                    from == "ONWC ONI" ||
476 >                    from == "OBAN ONI (cam)" ||
477 >                    from == "AKEV ONI"
478 >                    ){
479 >                expectedExtensions << "ONI";
480 >            }
481 >            else if(from == "TRBS XML" || from == "MASTER XML"){
482 >                expectedExtensions << "XML";
483 >            }
484 >            else if(from == "TRBS DAE"){
485 >                expectedExtensions << "DAE";
486 >            }
487 >            else if(from == "FILM DAT"){
488 >                expectedExtensions << "DAT";
489 >            }
490 >            else if(from == "WAV / AIF"){
491 >                expectedExtensions << "WAV" << "AIF";
492 >            }
493 >            else{
494 >                expectedExtensions << from;
495 >            }
496 >
497 >            for(const QString &currExpectedExtension : expectedExtensions){
498 >                if(fileInfo.suffix().toUpper() == currExpectedExtension){
499 >                    extensionIsValid = true;
500 >                    break;
501 >                }
502 >            }
503 >
504 >            if(!extensionIsValid){
505 >                QString errorMsg = "Can't add the file '" + fileInfo.fileName() + "'. It isn't a " + expectedExtensions.join(" or ") + " file.";
506 >                Util::Dialogs::showError(errorMsg);
507 >                Util::StatusBar::showError(ui->statusBar, errorMsg);
508                  return;
509              }
510          }
# Line 354 | Line 516 | void MainWindow::addFilesSource(DropTabl
516      QString myOutputFolder=getFileOutputFolder(fromTo);
517  
518      //if folder doesn't exist onisplit will create it for us :)
519 <    foreach(QString currentFile, files){
519 >    for(QString currentFile : files){
520  
521 <        currentFile=Util::normalizeAndQuote(currentFile); //insert quotes ("") in file
521 >        currentFile=Util::FileSystem::normalizeAndQuote(currentFile); //insert quotes ("") in file
522  
523          if(lastFileName.isEmpty()){ //Optimization: all commands are the same for each file, just replace the filename
524  
# Line 365 | Line 527 | void MainWindow::addFilesSource(DropTabl
527              if(command.isEmpty()){ //something wrong was happening (not inputted a texture name?)
528                  return; //stop adding files
529              }
530 <            currentFile=Util::cutName(currentFile);
530 >            currentFile=Util::FileSystem::cutName(currentFile);
531          }else{ //one parsing was already made just replace the filename by the old one in the command
532  
533 <            currentFile=Util::cutName(currentFile);
533 >            currentFile=Util::FileSystem::cutName(currentFile);
534  
535              command.replace(lastFileName,currentFile,Qt::CaseSensitive); //case sentive is faster
536          }
# Line 378 | Line 540 | void MainWindow::addFilesSource(DropTabl
540          addRowTable(myTable,lastFileName,fromTo,command);
541      }
542      updateItemsLoaded(myTable);
543 +    rowsWereChangedInDropTableWidget();
544   }
545  
546 < QString MainWindow::fileParsingGeneral(QString myOutputFolder, QString from, QString to , QString file){
546 > QString MainWindow::fileParsingXML(QString tabTitle, QString myOutputFolder, QString from, QString to , QString file){
547  
548      QString command;
549  
550 <    if(QString::compare(from,"ONI",Qt::CaseSensitive)==0 && QString::compare(to,"DAT",Qt::CaseSensitive)==0){ //CaseSensitive is faster
551 <
389 <        QString datName;
390 <
391 <        if(ui->cbDatGeneral->isChecked()){
392 <            if(ui->leTargetDatGeneral->text().isEmpty()){
393 <                showErrStatusMessage("Checkbox '"+ui->cbDatGeneral->text()+"' is selected. The name cannot be empty.");
394 <                return "";
395 <            }
396 <            datName+=QString(myOutputFolder).insert(myOutputFolder.size()-1,ui->leTargetDatGeneral->text()); //set name inputted by user
397 <            if(!ui->leTargetDatGeneral->text().toUpper().endsWith(".DAT")){
398 <                datName.insert(datName.size()-1,".dat"); //append extension if necessary (-1 to maintain final quote)
399 <            }
400 <        }
401 <        else{
402 <            datName=QString(myOutputFolder).insert(myOutputFolder.size()-1,Util::cutName(file).remove("/")+".dat"); //if none iputted set the same name of input file
403 <        }
404 <
405 <        if(ui->actionWindows->isChecked()){ //is target plataform select windows?
406 <            return command=this->commandMap.value("general->"+from+"->"+to+"(PC)")+" "+ file + " "+datName;
407 <        }
408 <        else{
409 <            return command=this->commandMap.value("general->"+from+"->"+to+"(demoPCMAC)")+" "+ file + " "+datName;
410 <        }
411 <    }
412 <    else if(QString::compare(from,"ONI",Qt::CaseSensitive)==0 && QString::compare(to,"XML",Qt::CaseSensitive)==0 && ui->cbTRAMGeneral->isChecked()){
413 <        if(ui->leTRAMGeneral->text().isEmpty()){
414 <            showErrStatusMessage("Checkbox '"+ui->cbTRAMGeneral->text()+"' is selected. The source cannot be empty.");
415 <            return "";
416 <        }
417 <        return command=this->commandMap.value("general->"+from+"->"+to)+" "+myOutputFolder+" "+this->commandMap.value("general->"+ui->cbTRAMGeneral->text())+file + " "+ Util::normalizeAndQuote(ui->leTRAMGeneral->text());
550 >    if(from=="ONI" && to=="XML"){
551 >        return command=this->commandMap.value(tabTitle+"->"+from+"->"+to)+" "+myOutputFolder+" "+file;
552      }
553 <    else{
554 <        return command=this->commandMap.value("general->"+from+"->"+to)+" "+myOutputFolder+" "+file;
553 >    else if(from=="XML" && to=="ONI"){
554 >        return command=this->commandMap.value(tabTitle+"->"+from+"->"+to)+" "+myOutputFolder+" "+file;
555      }
556  
557 +    return "";
558 +
559   }
560  
561 < QString MainWindow::fileParsingTextures(QString myOutputFolder, QString from, QString to , QString file){
561 > QString MainWindow::fileParsingTextures(QString tabTitle, QString myOutputFolder, QString from, QString to , QString file){
562  
563 <    QString command=this->commandMap.value("textures->"+from+"->"+to)+" "+myOutputFolder;
563 >    QString command=this->commandMap.value(tabTitle+"->"+from+"->"+to)+" "+myOutputFolder;
564  
565      if(ui->gbTextures->isEnabled()){ //faster than compare strings (if is DAT/ONI)
566  
567 <        if(ui->cbMipMapsTextures->isChecked()){
568 <            command+=" "+this->commandMap.value("textures->"+ui->cbMipMapsTextures->text());
567 >        if(ui->cbMipMapsTextures->isEnabled() && ui->cbMipMapsTextures->isChecked()){
568 >            command+=" "+this->commandMap.value(tabTitle+"->"+ui->cbMipMapsTextures->text());
569          }
570  
571 <        if(ui->cbNoUwrap->isChecked()){
572 <            command+=" "+this->commandMap.value("textures->"+ui->cbNoUwrap->text());
571 >        if(ui->cbNoUwrap->isEnabled() && ui->cbNoUwrap->isChecked()){
572 >            command+=" "+this->commandMap.value(tabTitle+"->"+ui->cbNoUwrap->text());
573          }
574  
575 <        if(ui->cbNoVwrap->isChecked()){
576 <            command+=" "+this->commandMap.value("textures->"+ui->cbNoVwrap->text());
575 >        if(ui->cbNoVwrap->isEnabled() && ui->cbNoVwrap->isChecked()){
576 >            command+=" "+this->commandMap.value(tabTitle+"->"+ui->cbNoVwrap->text());
577          }
578  
579 <        if(ui->cbLarge->isChecked()){
580 <            command+=" "+this->commandMap.value("textures->"+ui->cbLarge->text());
579 >        if(ui->cbLarge->isEnabled() && ui->cbLarge->isChecked()){
580 >            command+=" "+this->commandMap.value(tabTitle+"->"+ui->cbLarge->text());
581          }
582  
583 <        if(ui->rbBGR32->isChecked()){
448 <            command+=" "+this->commandMap.value("textures->"+ui->rbBGR32->text());
449 <        }
450 <        else if(ui->rbBGRA32->isChecked()){
451 <            command+=" "+this->commandMap.value("textures->"+ui->rbBGRA32->text());
452 <        }
453 <        else if(ui->rbBGR555->isChecked()){
454 <            command+=" "+this->commandMap.value("textures->"+ui->rbBGR555->text());
455 <        }
456 <        else if(ui->rbBGRA5551->isChecked()){
457 <            command+=" "+this->commandMap.value("textures->"+ui->rbBGRA5551->text());
458 <        }
459 <        else if(ui->rbBGRA444->isChecked()){
460 <            command+=" "+this->commandMap.value("textures->"+ui->rbBGRA444->text());
461 <        }
462 <        else{ //dxt1 checked
463 <            command+=" "+this->commandMap.value("textures->"+ui->rbDxt1->text());
464 <        }
583 >        command+=" "+this->commandMap.value(tabTitle+"->"+getTextureRBCheckedTypeTexture()->text());
584  
585 <        if(ui->cbEnvMap->isChecked()){
585 >        if(ui->cbEnvMap->isEnabled() && ui->cbEnvMap->isChecked()){
586              if(ui->leEnvMapTexture->text().isEmpty()){
587 <                showErrStatusMessage("Checkbox '"+ui->cbEnvMap->text()+"' is selected. The name texture name cannot be empty.");
587 >                Util::StatusBar::showError(ui->statusBar, "Checkbox '"+ui->cbEnvMap->text()+"' is selected. The name texture name cannot be empty.");
588                  return "";
589              }
590 <            command+=" "+this->commandMap.value("textures->"+ui->cbEnvMap->text()) + ui->leEnvMapTexture->text().remove(".oni",Qt::CaseInsensitive);
590 >            command+=" "+this->commandMap.value(tabTitle+"->"+ui->cbEnvMap->text()) + ui->leEnvMapTexture->text().remove(".oni",Qt::CaseInsensitive);
591          }
592      }
593  
594      return command+=" "+file; //add source
595   }
596  
597 < QString MainWindow::fileParsingModels(QString myOutputFolder, QString from, QString to , QString file){
597 > QString MainWindow::fileParsingCharacters(QString tabTitle, QString myOutputFolder, QString from, QString to , QString file){
598  
599 <    QString command=this->commandMap.value("models->"+from+"->"+to)+" "+myOutputFolder;
599 >    QString command=this->commandMap.value(tabTitle + "->" + from + "->" + to) + " " + myOutputFolder + " " + file ;
600  
601 <    //TODO: This can be optimized. When some are not enable others are.
602 <    if(ui->cbTexture->isChecked()){
603 <        if(ui->leTextureName->text().isEmpty()){
485 <            showErrStatusMessage("Checkbox '"+ui->cbTexture->text()+"' is selected. The name cannot be empty.");
486 <            return "";
487 <        }
488 <        command+=" "+this->commandMap.value("models->"+ui->cbTexture->text()) + ui->leTextureName->text().remove(".oni",Qt::CaseInsensitive);
601 >
602 >    if(ui->cbCellShading->isEnabled() && ui->cbCellShading->isChecked()){
603 >        command+=" "+this->commandMap.value(tabTitle + "->" + ui->cbCellShading->text());
604      }
605  
606 <    if(ui->cbCellShading->isChecked()){
607 <        command+=" "+this->commandMap.value("models->"+ui->cbCellShading->text());
606 >    if(ui->cbNormals->isEnabled() && ui->cbNormals->isChecked()){
607 >        command+=" "+this->commandMap.value(tabTitle + "->" + ui->cbNormals->text());
608      }
609  
610 <    if(ui->cbNormals->isChecked()){
611 <        command+=" "+this->commandMap.value("models->"+ui->cbNormals->text());
610 >    if(ui->cbStandingPose->isEnabled() && ui->cbStandingPose->isChecked()){
611 >        command+=" "+this->commandMap.value(tabTitle + "->" + ui->cbStandingPose->text());
612      }
613  
614 <    if(ui->cbWithAnimation->isEnabled()){
615 <        if(ui->cbWithAnimation->isChecked()){
616 <            command+=" "+this->commandMap.value("models->"+ui->cbWithAnimation->text())+ui->leAnimationName->text().remove(".oni",Qt::CaseInsensitive);
617 <        }
503 <        else{
504 <            command+=" "+this->commandMap.value("models->No Animation");
614 >    if(ui->cbWithTRBS_ONCC->isEnabled() && ui->cbWithTRBS_ONCC->isChecked()){
615 >        if(ui->leTRBS_ONCC->text().isEmpty()){
616 >            Util::StatusBar::showError(ui->statusBar, "Checkbox '" + ui->cbWithTRBS_ONCC->text() + "' is selected. The name cannot be empty.");
617 >            return "";
618          }
506    }
619  
620 +        command+= " " + this->commandMap.value(tabTitle + "->" + ui->cbWithTRBS_ONCC->text()) + Util::FileSystem::normalizeAndQuote(ui->leTRBS_ONCC->text());
621 +    }
622  
623 <    return command+=" "+file; //add source
623 >    return command;
624   }
625  
512 QString MainWindow::fileParsingAnimations(QString myOutputFolder, QString from, QString to , QString file){
626  
627 <    QString command=this->commandMap.value("animations->"+from+"->"+to)+" "+myOutputFolder + " " + file ;
627 > QString MainWindow::fileParsingObjects(QString tabTitle, QString myOutputFolder, QString from, QString to , QString file){
628 >
629 >    QString command=this->commandMap.value(tabTitle+"->"+from+"->"+to)+" "+myOutputFolder;
630  
631 <    if(ui->cbCamera->isChecked()){
632 <        command+=" "+this->commandMap.value("animations->"+ui->cbCamera->text());
631 >    if(ui->cbTexture->isEnabled() && ui->cbTexture->isChecked()){
632 >        if(ui->leTextureName->text().isEmpty()){
633 >            Util::StatusBar::showError(ui->statusBar, "Checkbox '"+ui->cbTexture->text()+"' is selected. The file source cannot be empty.");
634 >            return "";
635 >        }
636 >        command+=" "+this->commandMap.value(tabTitle+"->"+ui->cbTexture->text()) + ui->leTextureName->text();
637      }
638 <    else if(ui->cbGeometry->isChecked()){
639 <        if(ui->leGeometryName->text().isEmpty()){
640 <            showErrStatusMessage("Checkbox '"+ui->cbGeometry->text()+"' is selected. The geometry file path cannot be empty.");
638 >    else if(ui->cbWithAnimation->isEnabled() && ui->cbWithAnimation->isChecked()){
639 >        if(ui->leAnimationName->text().isEmpty()){
640 >            Util::StatusBar::showError(ui->statusBar, "Checkbox '"+ui->cbWithAnimation->text()+"' is selected. The file source cannot be empty.");
641              return "";
642          }
643 <        command+=" "+this->commandMap.value("animations->"+ui->cbGeometry->text()) + (ui->leGeometryName->text().startsWith('"')?ui->leGeometryName->text():Util::insertQuotes(ui->leGeometryName->text()));
643 >        command+=" "+Util::FileSystem::normalizeAndQuote(ui->leAnimationName->text()) + " " + this->commandMap.value(tabTitle+"->"+ui->cbWithAnimation->text()) + file;
644 >        return command;
645      }
646  
647 <    return command;
647 >    if(from=="OBAN ONI (cam)"){
648 >        command+=" -geom:camera";
649 >    }
650 >
651 >    return command+=" "+file; //add source
652   }
653  
654 < QString MainWindow::fileParsingLevels(QString myOutputFolder, QString from, QString to , QString file){
654 > QString MainWindow::fileParsingLevels(QString tabTitle, QString myOutputFolder, QString from, QString to , QString file){
655  
656      QString datName, command;
657  
658 <    command=this->commandMap.value("levels->"+from+"->"+to)+" "+myOutputFolder+" "+file;
658 >    if(!(from=="ONI FILES" && to=="DAT")){ // to all except this one
659 >
660 >        command=this->commandMap.value(tabTitle+"->"+from+"->"+to);
661 >
662 >        if(ui->cbSpecificFilesLevels->isEnabled() && ui->cbSpecificFilesLevels->isChecked()){
663 >
664 >            if(ui->leSpecificFilesLevels->text().isEmpty()){
665 >                Util::StatusBar::showError(ui->statusBar, "Checkbox '"+ui->cbSpecificFilesLevels->text()+"' is selected. The files pattern cannot be empty.");
666 >                return "";
667 >            }
668 >
669 >            command+=":"+ui->leSpecificFilesLevels->text();
670 >        }
671 >
672 >        if(from=="DAT" && to=="ONI FILES"){ // extract files to a subdir with the files name ex: level0_Final
673 >            command += " " + myOutputFolder.insert(myOutputFolder.size()-2,QString(Util::FileSystem::cutName(file)).replace(".dat","")) + " " + file;
674 >        }
675 >        else{
676 >            command+=" "+myOutputFolder+" "+file;
677 >        }
678  
679 <    if(from=="MASTER XML" && to=="DAT"){
537 <        command+=GlobalVars::OniSplitProcSeparator; //insert mark so we know this action will take 2 commands
679 >    }
680  
681 +    if((from=="ONI FILES" || from=="MASTER XML") && to=="DAT"){ // almost the same command for both
682          QString datName;
683 <        if(ui->cbDatLevels->isChecked()){
683 >
684 >        if(from=="MASTER XML"){
685 >            command+=GlobalVars::OniSplitProcSeparator; //insert mark so we know this action will take 2 commands
686 >        }
687 >
688 >        if(ui->cbDatLevels->isEnabled() && ui->cbDatLevels->isChecked()){
689              if(ui->leTargetDatLevels->text().isEmpty()){
690 <                showErrStatusMessage("Checkbox '"+ui->cbDatLevels->text()+"' is selected. The name cannot be empty.");
690 >                Util::StatusBar::showError(ui->statusBar, "Checkbox '"+ui->cbDatLevels->text()+"' is selected. The name cannot be empty.");
691                  return "";
692              }
693              datName+=QString(myOutputFolder).insert(myOutputFolder.size()-1,ui->leTargetDatLevels->text()); //set name inputted by user
# Line 548 | Line 696 | QString MainWindow::fileParsingLevels(QS
696              }
697          }
698          else{
699 <            datName=QString(myOutputFolder).insert(myOutputFolder.size()-1,Util::cutName(file).remove("/").replace(".xml",".dat",Qt::CaseInsensitive)); //if none iputted set the same name of input file
699 >            if(from=="ONI FILES"){
700 >                datName=QString(myOutputFolder).insert(myOutputFolder.size()-1,Util::FileSystem::cutName(file).remove("/")+".dat"); //if none iputted set the same name of input file
701 >            }
702 >            else if(from=="MASTER XML"){
703 >                datName=QString(myOutputFolder).insert(myOutputFolder.size()-1,Util::FileSystem::cutName(file).remove("/").replace(".xml",".dat",Qt::CaseInsensitive)); //if none iputted set the same name of input file
704 >            }
705          }
706 <
707 <        if(ui->actionWindows->isChecked()){ //is target plataform select windows?
708 <            command+=this->commandMap.value("general->ONI->"+to+"(PC)")+" "+myOutputFolder+" "+datName; //add second command
706 >        if(from=="ONI FILES"){
707 >            if(ui->actionWindows->isEnabled() && ui->actionWindows->isChecked()){ //is target plataform select windows?
708 >                return command=this->commandMap.value(tabTitle+"->"+from+"->"+to+"(PC)")+" "+ file + " "+datName;
709 >            }
710 >            else{
711 >                return command=this->commandMap.value(tabTitle+"->"+from+"->"+to+"(demoPCMAC)")+" "+ file + " "+datName;
712 >            }
713          }
714 <        else{
715 <            command+=this->commandMap.value("general->ONI->"+to+"(demoPCMAC)")+" "+myOutputFolder+" "+datName; //add second command
714 >        else if(from=="MASTER XML"){
715 >            if(ui->actionWindows->isEnabled() && ui->actionWindows->isChecked()){ //is target plataform select windows?
716 >                command+=this->commandMap.value(tabTitle+"->ONI FILES->"+to+"(PC)")+" "+myOutputFolder+" "+datName; //add second command
717 >            }
718 >            else{
719 >                command+=this->commandMap.value(tabTitle+"->ONI FILES->"+to+"(demoPCMAC)")+" "+myOutputFolder+" "+datName; //add second command
720 >            }
721          }
722      }
723  
724 <    if(ui->cbBnvLevels->isChecked()){
724 >    if(ui->cbBnvLevels->isEnabled() && ui->cbBnvLevels->isChecked()){
725  
726 <        if(ui->leBnvLevels->text().isEmpty()){
727 <            showErrStatusMessage("Checkbox '"+ui->cbBnvLevels->text()+"' is selected. The BNV file cannot be empty.");
726 >        if(ui->leBnvLevels->isEnabled() && ui->leBnvLevels->text().isEmpty()){
727 >            Util::StatusBar::showError(ui->statusBar, "Checkbox '"+ui->cbBnvLevels->text()+"' is selected. The BNV file cannot be empty.");
728              return "";
729          }
730 <        command+=" "+Util::normalizeAndQuote(ui->leBnvLevels->text());
730 >        command+=" "+Util::FileSystem::normalizeAndQuote(ui->leBnvLevels->text());
731      }
732  
733 <    if(ui->cbAdditionalSourcesLevels->isChecked()){
733 >    if(ui->cbAdditionalSourcesLevels->isEnabled() && ui->cbAdditionalSourcesLevels->isChecked()){
734  
735          if(ui->leAdditSourcesLevels->text().isEmpty()){
736 <            showErrStatusMessage("Checkbox '"+ui->cbAdditionalSourcesLevels->text()+"' is selected. The source files cannot be empty.");
736 >            Util::StatusBar::showError(ui->statusBar, "Checkbox '"+ui->cbAdditionalSourcesLevels->text()+"' is selected. The source files cannot be empty.");
737              return "";
738          }
739  
# Line 581 | Line 743 | QString MainWindow::fileParsingLevels(QS
743  
744          //parse all files (separated by spaces)
745          while(true){
746 <            nextIndex=additionalFiles.indexOf(" ",currentIndex+1);
746 >            nextIndex=additionalFiles.indexOf(";",currentIndex+1);
747  
748 <            command += " "+Util::normalizeAndQuote(additionalFiles.mid(currentIndex,(nextIndex-currentIndex)));
748 >            command += " "+Util::FileSystem::normalizeAndQuote(additionalFiles.mid(currentIndex,(nextIndex-currentIndex)));
749  
750              if(nextIndex==-1){ //we got to the end, stop parsing
751                  break;
# Line 592 | Line 754 | QString MainWindow::fileParsingLevels(QS
754          }
755      }
756  
757 <    if(ui->cbGridsLevels->isChecked()){
758 <        command+=GlobalVars::OniSplitProcSeparator+this->commandMap.value("levels->"+ui->cbGridsLevels->text())+" "+Util::normalizeAndQuote(ui->leBnvLevels->text())+" "+file+" -out:"+myOutputFolder;
757 >    if(ui->cbGridsLevels->isEnabled() && ui->cbGridsLevels->isChecked()){
758 >        command+=GlobalVars::OniSplitProcSeparator+this->commandMap.value(tabTitle+"->"+ui->cbGridsLevels->text())+" "+Util::FileSystem::normalizeAndQuote(ui->leBnvLevels->text())+" "+file+" -out:"+myOutputFolder;
759      }
760  
761      return command;
# Line 603 | Line 765 | QString MainWindow::fileParsingMisc(QStr
765      return this->commandMap.value("misc->"+from+"->"+to)+" "+myOutputFolder+" "+file;
766   }
767  
768 < void MainWindow::addRowTable(DropTableWidget *myTable, QString fileName, QString fromTo, QString command){
768 > void MainWindow::addRowTable(DropTableWidget *myTable, QString fileName, QString fromTo, QString command, bool isToDisabled){
769      //Get actual number rows
770      int twSize=myTable->rowCount();
771  
# Line 615 | Line 777 | void MainWindow::addRowTable(DropTableWi
777      QTableWidgetItem *newConversion = new QTableWidgetItem(fromTo);
778      QTableWidgetItem *newCommand = new QTableWidgetItem(command);
779  
780 +    if(isToDisabled){
781 +        myTable->setDisableStyleWidgetItem(newFile);
782 +        myTable->setDisableStyleWidgetItem(newConversion);
783 +        myTable->setDisableStyleWidgetItem(newCommand);
784 +    }
785 +
786      myTable->setItem(twSize,0,newFile);
787      myTable->setItem(twSize,1,newConversion);
788      myTable->setItem(twSize,2,newCommand);
# Line 622 | Line 790 | void MainWindow::addRowTable(DropTableWi
790      myTable->updateTableToolTips(twSize); //Update tool tips
791   }
792  
793 < void MainWindow::on_pbConvertGeneral_clicked()
626 < {
627 <    startConversion(ui->twSourcesGeneral);
628 < }
629 <
630 < void MainWindow::on_pbConvertTextures_clicked()
631 < {
632 <    startConversion(ui->twSourcesTextures);
633 < }
634 <
635 < void MainWindow::on_pbConvertModels_clicked()
636 < {
637 <    startConversion(ui->twSourcesModels);
638 < }
639 <
640 < void MainWindow::on_pbConvertAnimations_clicked()
641 < {
642 <    startConversion(ui->twSourcesAnimations);
643 < }
644 <
645 < void MainWindow::on_pbConvertLevels_clicked()
793 > void MainWindow::on_pbConvert_clicked()
794   {
795 <    startConversion(ui->twSourcesLevels);
795 >    startConversion();
796   }
797  
798 < void MainWindow::on_pbConvertMisc_clicked()
651 < {
652 <    startConversion(ui->twSourcesMisc);
653 < }
798 > void MainWindow::startConversion(){
799  
800 < void MainWindow::startConversion(DropTableWidget *myTable){
800 >    DropTableWidget* currTable = getCurrentTableWidget();
801  
802      bool ready=false;
803 <    for(int i=0; i<myTable->rowCount(); i++){ //There are items to process?
804 <        if(myTable->item(i,2)->background()!=myTable->disabledBackStyle){
803 >    for(int i=0; i<currTable->rowCount(); i++){ //There are items to process?
804 >        if(currTable->item(i,2)->background()!=currTable->disabledBackStyle){
805              ready=true;
806              break;
807          }
808      }
809  
810      if(!ready){
811 <        showErrStatusMessage("Please add sources to convert first.");
811 >        Util::StatusBar::showError(ui->statusBar, "Please add sources to convert first.");
812          return;
813      }
814  
815 <    if(myBar->isVisible()){
816 <        Util::showErrorPopUp("Another conversion is progress. Please wait until it finishes.");
815 >    if(this->myBar->isVisible()){
816 >        Util::Dialogs::showError("Another conversion is progress. Please wait until it finishes.");
817          return;
818      }
819  
820 <    for(int i=0; i<myTable->rowCount(); i++){
820 >    for(int i=0; i<currTable->rowCount(); i++){
821          //Only process enabled items
822 <        if(myTable->item(i,2)->background()!=myTable->disabledBackStyle){
823 <            this->listToProccess->append(myTable->item(i,2)->text());
822 >        if(currTable->item(i,2)->background()!=currTable->disabledBackStyle){
823 >            this->listToProccess.append(currTable->item(i,2)->text());
824          }
825      }
826  
# Line 686 | Line 831 | void MainWindow::TsetupProgressBar(int m
831      this->myBar->setValue(0);
832      this->myBar->show();
833      this->myBar->setMaximum(max);
834 +    ui->tbAbortConversion->show();
835   }
836  
837   void  MainWindow::TupdateProgressBar(){
# Line 695 | Line 841 | void  MainWindow::TupdateProgressBar(){
841   void MainWindow::TresultConversion(QString result, int numErrors){
842      QApplication::alert(this); //Show a notification if window is not active
843      this->myBar->hide();
844 +    ui->tbAbortConversion->hide();
845  
846      if(numErrors!=0){
847          QString sNumErrors=QString::number(numErrors);
848          if(numErrors>1){
849 <            Util::showErrorLogPopUp(result+"\n This is the last of "+sNumErrors+" Errors.");
850 <            showErrStatusMessage("Something gone wrong. Check log file ("+sNumErrors+" Errors).");
849 >            UtilVago::showErrorPopUpLogButton(result+"\n This is the last of "+sNumErrors+" errors.");
850 >            Util::StatusBar::showError(ui->statusBar, "Something gone wrong. Check log file ("+sNumErrors+" errors).");
851          }
852          else{
853 <            Util::showErrorLogPopUp(result);
854 <            showErrStatusMessage("Something gone wrong. Check log file.");
853 >            UtilVago::showErrorPopUpLogButton(result);
854 >            Util::StatusBar::showError(ui->statusBar, "Something gone wrong. Check log file.");
855          }
709
856      }
857      else{
858 <        showSuccessStatusMessage("Everything went well!");
858 >        Util::StatusBar::showSuccess(ui->statusBar, "Everything went well!");
859      }
860   }
861  
862 < void MainWindow::showErrStatusMessage(QString message){
863 <
864 <    QPalette myPalete = QPalette();
719 <    myPalete.setColor( QPalette::WindowText, QColor(255,0,0));
720 <    statusBar()->setPalette( myPalete );
721 <    ui->statusBar->showMessage(message,10000); //display by 10 seconds
722 <
723 < }
724 <
725 < void MainWindow::showSuccessStatusMessage(QString message){
726 <
727 <    QPalette myPalete = QPalette();
728 <    myPalete.setColor( QPalette::WindowText, QColor(0,150,0));
729 <    statusBar()->setPalette( myPalete );
730 <    ui->statusBar->showMessage(message,10000); //display by 10 seconds
862 > void MainWindow::TconversionAborted(){
863 >    this->myBar->hide();
864 >    ui->tbAbortConversion->hide();
865  
866 +    Util::StatusBar::showError(ui->statusBar, "Conversion was aborted.");
867   }
868  
869   void MainWindow::mapCommands(){
870 <    ////////////////////////////////////////////////////////////////////////General Commands
871 <    this->commandMap.insert("general->DAT->ONI","-export");
872 <    //this->commandMap.insert("general->ONI->DAT","-import"); //Not used.
738 <    this->commandMap.insert("general->ONI->DAT(PC)","-import:nosep");
739 <    this->commandMap.insert("general->ONI->DAT(demoPCMAC)","-import:sep");
740 <    this->commandMap.insert("general->ONI->XML","-extract:xml");
741 <    this->commandMap.insert("general->XML->ONI","-create");
870 >    ////////////////////////////////////////////////////////////////////////XML Commands
871 >    this->commandMap.insert("xml->ONI->XML","-extract:xml");
872 >    this->commandMap.insert("xml->XML->ONI","-create");
873      //######################General Options
874 <    this->commandMap.insert("general->"+ui->cbTRAMGeneral->text(),"-anim-body:");
874 >
875      //Possible Combinations
876 <    this->commandMap.insertMulti("general->DAT","ONI");
877 <    this->commandMap.insertMulti("general->ONI","DAT");
747 <    this->commandMap.insertMulti("general->ONI","XML");
748 <    this->commandMap.insertMulti("general->XML","ONI");
876 >    this->commandMap.insertMulti("xml->ONI","XML");
877 >    this->commandMap.insertMulti("xml->XML","ONI");
878  
879      ////////////////////////////////////////////////////////////////////////Textures Commands
880 <    this->commandMap.insert("textures->DAT / ONI->DDS","-extract:dds");
881 <    this->commandMap.insert("textures->DAT / ONI->TGA","-extract:tga");
882 <    this->commandMap.insert("textures->DAT / ONI->PNG","-extract:png");
883 <    this->commandMap.insert("textures->DAT / ONI->JPG","-extract:jpg");
884 <    this->commandMap.insert("textures->DDS / TGA / PNG / JPG->ONI","-create:txmp");
880 >    this->commandMap.insert("textures->DAT / TXMP ONI->DDS","-extract:dds");
881 >    this->commandMap.insert("textures->DAT / TXMP ONI->TGA","-extract:tga");
882 >    this->commandMap.insert("textures->DAT / TXMP ONI->PNG","-extract:png");
883 >    this->commandMap.insert("textures->DAT / TXMP ONI->JPG","-extract:jpg");
884 >    this->commandMap.insert("textures->TGA / DDS / PNG / JPG->TXMP ONI","-create:txmp");
885      //######################Textures Options
886      this->commandMap.insert("textures->"+ui->rbBGR32->text(),"-format:bgr32");
887      this->commandMap.insert("textures->"+ui->rbBGRA32->text(),"-format:bgra32");
# Line 766 | Line 895 | void MainWindow::mapCommands(){
895      this->commandMap.insert("textures->"+ui->cbLarge->text(),"-large");
896      this->commandMap.insert("textures->"+ui->cbEnvMap->text(),"-envmap:");
897      //Possible Combinations
898 <    this->commandMap.insertMulti("textures->DAT / ONI","DDS");
899 <    this->commandMap.insertMulti("textures->DAT / ONI","TGA");
900 <    this->commandMap.insertMulti("textures->DAT / ONI","PNG");
901 <    this->commandMap.insertMulti("textures->DAT / ONI","JPG");
902 <    this->commandMap.insertMulti("textures->DDS / TGA / PNG / JPG","ONI");
903 <
904 <    ////////////////////////////////////////////////////////////////////////Models Commands
905 <    this->commandMap.insert("models->ONI->OBJ","-extract:obj");
906 <    this->commandMap.insert("models->ONI->DAE","-extract:dae -search "+Util::insertQuotes(this->AeLocation+"/GameDataFolder/level0_Final"));
907 <    this->commandMap.insert("models->OBJ->ONI","-create:m3gm");
908 <    this->commandMap.insert("models->DAE->ONI","-create:trbs");
909 <    //######################Models Options
910 <    this->commandMap.insert("models->"+ui->cbCellShading->text(),"-cel");
911 <    this->commandMap.insert("models->"+ui->cbNormals->text(),"-normals");
912 <    this->commandMap.insert("models->"+ui->cbTexture->text(),"-tex:");
913 <    this->commandMap.insert("models->"+ui->cbWithAnimation->text(),"-anim:");
914 <    this->commandMap.insert("models->No Animation","-noanim"); //No label with this name so can't be dynamic
898 >    this->commandMap.insertMulti("textures->DAT / TXMP ONI","TGA");
899 >    this->commandMap.insertMulti("textures->DAT / TXMP ONI","DDS");
900 >    this->commandMap.insertMulti("textures->DAT / TXMP ONI","PNG");
901 >    this->commandMap.insertMulti("textures->DAT / TXMP ONI","JPG");
902 >    this->commandMap.insertMulti("textures->TGA / DDS / PNG / JPG","TXMP ONI");
903 >
904 >    ////////////////////////////////////////////////////////////////////////Characters Commands
905 >    this->commandMap.insert("characters->TRAM ONI->XML / XML & DAE","-extract:xml");
906 >    this->commandMap.insert("characters->TRBS / ONCC ONI->DAE","-extract:dae");
907 >    this->commandMap.insert("characters->TRBS XML->TRBS ONI","-create");
908 >    this->commandMap.insert("characters->TRBS DAE->TRBS ONI","-create:trbs");
909 >    this->commandMap.insert("characters->FILM DAT->XML","film2xml");
910 >
911 >    //######################Characters Options
912 >    this->commandMap.insert("characters->"+ui->cbWithTRBS_ONCC->text(),"-anim-body:");
913 >    this->commandMap.insert("characters->"+ui->cbCellShading->text(),"-cel");
914 >    this->commandMap.insert("characters->"+ui->cbNormals->text(),"-normals");
915 >    this->commandMap.insert("characters->"+ui->cbStandingPose->text(),"-noanim");
916      //Possible Combinations
917 <    this->commandMap.insertMulti("models->ONI","OBJ");
918 <    this->commandMap.insertMulti("models->ONI","DAE");
919 <    this->commandMap.insertMulti("models->OBJ","ONI");
920 <    this->commandMap.insertMulti("models->DAE","ONI");
921 <
922 <    ////////////////////////////////////////////////////////////////////////Animations Commands
923 <    this->commandMap.insert("animations->ONI->DAE","-extract:dae");
924 <    this->commandMap.insert("animations->FILM DAT->XML","film2xml");
925 <    //######################Animations Options
926 <    this->commandMap.insert("animations->"+ui->cbCamera->text(),"-geom:camera");
927 <    this->commandMap.insert("animations->"+ui->cbGeometry->text(),"-geom:");
917 >    this->commandMap.insertMulti("characters->TRAM ONI","XML / XML & DAE");
918 >    this->commandMap.insertMulti("characters->TRBS / ONCC ONI","DAE");
919 >    this->commandMap.insertMulti("characters->DAE","TRBS ONI");
920 >    this->commandMap.insertMulti("characters->TRBS DAE","TRBS ONI");
921 >    this->commandMap.insertMulti("characters->TRBS XML","TRBS ONI");
922 >    this->commandMap.insertMulti("characters->FILM DAT","XML");
923 >
924 >    ////////////////////////////////////////////////////////////////////////Objects Commands
925 >    this->commandMap.insert("objects->M3GM ONI->OBJ","-extract:obj");
926 >    this->commandMap.insert("objects->M3GM ONI->DAE","-extract:dae");
927 >    this->commandMap.insert("objects->ONWC ONI->OBJ","-extract:obj");
928 >    this->commandMap.insert("objects->ONWC ONI->DAE","-extract:dae");
929 >    this->commandMap.insert("objects->OBAN ONI (cam)->DAE","-extract:dae");
930 >    this->commandMap.insert("objects->OBJ->M3GM ONI","-create:m3gm");
931 >    //######################Objects Options
932 >    this->commandMap.insert("objects->"+ui->cbTexture->text(),"-tex:");
933 >    this->commandMap.insert("objects->"+ui->cbWithAnimation->text(),"-geom:");
934      //Possible Combinations
935 <    this->commandMap.insertMulti("animations->ONI","DAE");
936 <    this->commandMap.insertMulti("animations->DAE","ONI");
937 <    this->commandMap.insertMulti("animations->FILM DAT","XML");
935 >    this->commandMap.insertMulti("objects->M3GM ONI","OBJ");
936 >    this->commandMap.insertMulti("objects->M3GM ONI","DAE");
937 >    this->commandMap.insertMulti("objects->ONWC ONI","OBJ");
938 >    this->commandMap.insertMulti("objects->ONWC ONI","DAE");
939 >    this->commandMap.insertMulti("objects->OBAN ONI (cam)","DAE");
940 >    this->commandMap.insertMulti("objects->OBJ","M3GM ONI");
941 >
942  
943      ////////////////////////////////////////////////////////////////////////Levels Commands
944 <    this->commandMap.insert("levels->ONI->DAE","-extract:dae -search "+Util::insertQuotes(this->AeLocation+"/GameDataFolder/level0_Final"));
945 <    this->commandMap.insert("levels->DAE->ONI","-create:akev");
944 >    this->commandMap.insert("levels->DAT->ONI FILES","-export");
945 >    //this->commandMap.insert("levels->ONI FILES->DAT","-import"); //Not used.
946 >    this->commandMap.insert("levels->ONI FILES->DAT(PC)","-import:nosep");
947 >    this->commandMap.insert("levels->ONI FILES->DAT(demoPCMAC)","-import:sep");
948 >    this->commandMap.insert("levels->AKEV ONI->DAE","-extract:dae");
949 >    this->commandMap.insert("levels->DAE->AKEV ONI","-create:akev");
950      this->commandMap.insert("levels->MASTER XML->DAT","-create:level");
951      this->commandMap.insert("levels->MASTER XML->ONI FILES","-create:level");
952      //######################Levels Options
953      this->commandMap.insert("levels->"+ui->cbGridsLevels->text(),"-grid:create");
954      //Possible Combinations
955 <    this->commandMap.insertMulti("levels->ONI","DAE");
956 <    this->commandMap.insertMulti("levels->DAE","ONI");
955 >    this->commandMap.insertMulti("levels->DAT","ONI FILES");
956 >    this->commandMap.insertMulti("levels->ONI FILES","DAT");
957 >    this->commandMap.insertMulti("levels->AKEV ONI","DAE");
958 >    this->commandMap.insertMulti("levels->DAE","AKEV ONI");
959      this->commandMap.insertMulti("levels->MASTER XML","DAT");
960      this->commandMap.insertMulti("levels->MASTER XML","ONI FILES");
961  
962      ////////////////////////////////////////////////////////////////////////Misc Commands
963 <    this->commandMap.insert("misc->DAT / ONI->WAV","-extract:wav");
964 <    this->commandMap.insert("misc->DAT / ONI->AIF","-extract:aif");
965 <    this->commandMap.insert("misc->DAT / ONI->TXT","-extract:txt");
966 <    this->commandMap.insert("misc->WAV / AIF->ONI","-create");
967 <    this->commandMap.insert("misc->TXT->ONI","-create:subt");
963 >    this->commandMap.insert("misc->DAT / SNDD ONI->WAV","-extract:wav");
964 >    this->commandMap.insert("misc->DAT / SNDD ONI->AIF","-extract:aif");
965 >    this->commandMap.insert("misc->DAT / SUBT ONI->TXT","-extract:txt");
966 >    this->commandMap.insert("misc->WAV / AIF->SNDD ONI","-create");
967 >    this->commandMap.insert("misc->TXT->SUBT ONI","-create:subt");
968      //Possible Combinations
969 <    this->commandMap.insertMulti("misc->DAT / ONI","WAV");
970 <    this->commandMap.insertMulti("misc->DAT / ONI","AIF");
971 <    this->commandMap.insertMulti("misc->DAT / ONI","TXT");
972 <    this->commandMap.insertMulti("misc->WAV / AIF","ONI");
973 <    this->commandMap.insertMulti("misc->TXT","ONI");
969 >    this->commandMap.insertMulti("misc->DAT / SNDD ONI","WAV");
970 >    this->commandMap.insertMulti("misc->DAT / SNDD ONI","AIF");
971 >    this->commandMap.insertMulti("misc->DAT / SUBT ONI","TXT");
972 >    this->commandMap.insertMulti("misc->WAV / AIF","SNDD ONI");
973 >    this->commandMap.insertMulti("misc->TXT","SUBT ONI");
974  
975   }
976  
977 < void MainWindow::on_cbFromGeneral_currentIndexChanged(const QString &arg1)
977 > void MainWindow::on_cbFromXML_currentIndexChanged(const QString &arg1)
978   {
979 <    updateComboBox(arg1, ui->cbToGeneral, "general");
979 >    updateComboBox(arg1, ui->cbToXML);
980   }
981  
982 +
983   void MainWindow::on_cbFromTextures_currentIndexChanged(const QString &arg1)
984   {
985 <    //Options are only used for DAT/ONI -> Image
839 <    if(QString::compare(arg1,"DAT / ONI",Qt::CaseSensitive)==0){ //case sensitive is faster
840 <        ui->gbTextures->setEnabled(false);
841 <    }
842 <    else{
843 <        ui->gbTextures->setEnabled(true);
844 <    }
845 <
846 <    updateComboBox(arg1, ui->cbToTextures, "textures");
985 >    updateComboBox(arg1, ui->cbToTextures);
986   }
987  
988 < void MainWindow::on_cbFromModels_currentIndexChanged(const QString &arg1)
988 > void MainWindow::on_cbFromObjects_currentIndexChanged(const QString &arg1)
989   {
990 <
852 <    ui->cbCellShading->setEnabled(false);
853 <    ui->cbCellShading->setChecked(false);
854 <    ui->cbNormals->setEnabled(false);
855 <    ui->cbNormals->setChecked(false);
856 <    ui->cbTexture->setEnabled(false);
857 <    ui->cbTexture->setChecked(false);
858 <    ui->cbWithAnimation->setEnabled(false);
859 <    ui->cbWithAnimation->setChecked(false);
860 <
861 <    if(QString::compare(arg1,"OBJ",Qt::CaseSensitive)==0){ //case sensitive is faster
862 <        ui->cbTexture->setEnabled(true);
863 <    }
864 <    else if(QString::compare(arg1,"DAE",Qt::CaseSensitive)==0){
865 <        ui->cbCellShading->setEnabled(true);
866 <        ui->cbNormals->setEnabled(true);
867 <    }
868 <
869 <    updateComboBox(arg1, ui->cbToModels, "models");
990 >    updateComboBox(arg1, ui->cbToObjects);
991   }
992  
993 < void MainWindow::on_cbFromAnimations_currentIndexChanged(const QString &arg1)
993 > void MainWindow::on_cbFromCharacters_currentIndexChanged(const QString &arg1)
994   {
995 <    ui->cbCamera->setEnabled(false);
875 <    ui->cbCamera->setChecked(false);
876 <    ui->cbGeometry->setEnabled(false);
877 <    ui->cbGeometry->setChecked(false);
878 <
879 <    if(QString::compare(arg1,"ONI",Qt::CaseSensitive)==0){ //case sensitive is faster
880 <        ui->cbCamera->setEnabled(true);
881 <        ui->cbGeometry->setEnabled(true);
882 <    }
883 <
884 <    updateComboBox(arg1, ui->cbToAnimations, "animations");
995 >    updateComboBox(arg1, ui->cbToCharacters);
996   }
997  
998   void MainWindow::on_cbFromLevels_currentIndexChanged(const QString &arg1)
999   {
1000 <    updateComboBox(arg1, ui->cbToLevels, "levels");
1000 >    updateComboBox(arg1, ui->cbToLevels);
1001   }
1002  
1003   void MainWindow::on_cbFromMisc_currentIndexChanged(const QString &arg1)
1004   {
1005 <    updateComboBox(arg1, ui->cbToMisc, "misc");
1005 >    updateComboBox(arg1, ui->cbToMisc);
1006   }
1007  
1008 < void MainWindow::updateComboBox(const QString &arg1, QComboBox *comboBox, const QString &identifier){
1008 > void MainWindow::updateComboBox(const QString &arg1, QComboBox *comboBox){
1009 >
1010 >    QString identifier;
1011 >
1012 >    if(comboBox == ui->cbToXML){
1013 >        identifier = ui->tabWidget->tabText(XMLTabIndex);
1014 >    }
1015 >    else if(comboBox == ui->cbToTextures){
1016 >        identifier = ui->tabWidget->tabText(TexturesTabIndex);
1017 >
1018 >        //Options are only used for DAT/TXMP ONI -> Image
1019 >        if(QString::compare(arg1,"DAT / TXMP ONI",Qt::CaseSensitive)==0){ //case sensitive is faster
1020 >            ui->gbTextures->setEnabled(false);
1021 >        }
1022 >        else{
1023 >            ui->gbTextures->setEnabled(true);
1024 >            ui->leEnvMapTexture->setEnabled(ui->cbEnvMap->isChecked());
1025 >        }
1026 >    }
1027 >    else if(comboBox == ui->cbToCharacters){
1028 >        identifier = ui->tabWidget->tabText(CharactersTabIndex);
1029 >
1030 >        ui->cbWithTRBS_ONCC->setEnabled(false);
1031 >        ui->cbCellShading->setEnabled(false);
1032 >        ui->cbNormals->setEnabled(false);
1033 >        ui->cbStandingPose->setEnabled(false);
1034 >        ui->leTRBS_ONCC->setEnabled(false);
1035 >
1036 >        //#error add drag and drop to Extract TRAM with TRBS/ONCC
1037 >        if(QString::compare(arg1,"TRAM ONI",Qt::CaseSensitive)==0){ //case sensitive is faster
1038 >            ui->cbWithTRBS_ONCC->setEnabled(true);
1039 >            ui->leTRBS_ONCC->setEnabled(ui->cbWithTRBS_ONCC->isChecked());
1040 >        }
1041 >        else if(QString::compare(arg1,"TRBS DAE",Qt::CaseSensitive)==0){
1042 >            ui->cbNormals->setEnabled(true);
1043 >            ui->cbCellShading->setEnabled(true);
1044 >        }
1045 >        else if(QString::compare(arg1,"TRBS / ONCC ONI",Qt::CaseSensitive)==0){
1046 >            ui->cbStandingPose->setEnabled(true);
1047 >        }
1048 >
1049 >    }
1050 >    else if(comboBox == ui->cbToObjects){
1051 >        identifier = ui->tabWidget->tabText(ObjectsTabIndex);
1052 >
1053 >        ui->cbTexture->setEnabled(false);
1054 >        ui->leTextureName->setEnabled(false);
1055 >        ui->cbWithAnimation->setEnabled(false);
1056 >        ui->leAnimationName->setEnabled(false);
1057 >
1058 >        if(QString::compare(arg1,"M3GM ONI",Qt::CaseSensitive)==0){ //case sensitive is faster
1059 >            ui->cbWithAnimation->setEnabled(true);
1060 >            ui->leAnimationName->setEnabled(ui->cbWithAnimation->isChecked());
1061 >        }
1062 >        else if(QString::compare(arg1,"OBJ",Qt::CaseSensitive)==0){
1063 >            ui->cbTexture->setEnabled(true);
1064 >            ui->leTextureName->setEnabled(ui->cbTexture->isChecked());
1065 >        }
1066 >    }
1067 >    else if(comboBox == ui->cbToLevels){
1068 >        identifier = ui->tabWidget->tabText(LevelsTabIndex);
1069 >
1070 >        ui->cbSpecificFilesLevels->setEnabled(false);
1071 >        ui->leSpecificFilesLevels->setEnabled(false);
1072 >        ui->cbDatLevels->setEnabled(false);
1073 >        ui->leTargetDatLevels->setEnabled(false);
1074 >        ui->cbBnvLevels->setEnabled(false);
1075 >        ui->leBnvLevels->setEnabled(false);
1076 >        ui->cbAdditionalSourcesLevels->setEnabled(false);
1077 >        ui->leAdditSourcesLevels->setEnabled(false);
1078 >        ui->cbGridsLevels->setEnabled(false);
1079 >
1080 >        if(arg1=="DAT"){ //case sensitive is faster
1081 >            ui->cbSpecificFilesLevels->setEnabled(true);
1082 >            ui->leSpecificFilesLevels->setEnabled( ui->cbSpecificFilesLevels->isChecked());
1083 >        }
1084 >        else if(arg1=="ONI FILES"){ //case sensitive is faster
1085 >            ui->cbDatLevels->setEnabled(true);
1086 >            ui->leTargetDatLevels->setEnabled(ui->cbDatLevels->isChecked());
1087 >        }
1088 >        else if(arg1=="DAE"){
1089 >            ui->cbBnvLevels->setEnabled(true);
1090 >            ui->leBnvLevels->setEnabled(ui->cbBnvLevels->isChecked());
1091 >            ui->cbAdditionalSourcesLevels->setEnabled(true);
1092 >            ui->leAdditSourcesLevels->setEnabled(ui->cbAdditionalSourcesLevels->isChecked());
1093 >        }
1094 >    }
1095 >    else{ // Misc
1096 >        identifier = ui->tabWidget->tabText(MiscTabIndex);
1097 >    }
1098 >
1099 >    identifier = identifier.toLower(); // get current tab title text (lower case)
1100 >
1101      comboBox->clear();
1102  
1103      QStringList toUpdate=QStringList();
# Line 921 | Line 1124 | void MainWindow::on_actionMac_Windows_de
1124      ui->actionWindows->setChecked(false);
1125   }
1126  
1127 < void MainWindow::on_pbRemoveSourceGeneral_clicked()
1127 > void MainWindow::on_pbRemoveSourceXML_clicked()
1128   {
1129 <    removeTableContents( ui->twSourcesGeneral);
1129 >    removeTableContents( ui->twSourcesXML);
1130   }
1131  
1132   void MainWindow::on_pbRemoveSourceTextures_clicked()
# Line 931 | Line 1134 | void MainWindow::on_pbRemoveSourceTextur
1134      removeTableContents(ui->twSourcesTextures);
1135   }
1136  
1137 < void MainWindow::on_pbRemoveSourceModels_clicked()
1137 > void MainWindow::on_pbRemoveSourceObjects_clicked()
1138   {
1139 <    removeTableContents(ui->twSourcesModels);
1139 >    removeTableContents(ui->twSourcesObjects);
1140   }
1141  
1142 < void MainWindow::on_pbRemoveSourceAnimations_clicked()
1142 > void MainWindow::on_pbRemoveSourceCharacters_clicked()
1143   {
1144 <    removeTableContents(ui->twSourcesAnimations);
1144 >    removeTableContents(ui->twSourcesCharacters);
1145   }
1146  
1147   void MainWindow::on_pbRemoveSourceLevels_clicked()
# Line 951 | Line 1154 | void MainWindow::on_pbRemoveSourceMisc_c
1154      removeTableContents(ui->twSourcesMisc);
1155   }
1156  
1157 < void MainWindow::on_pbClearSourcesGeneral_clicked()
1157 > void MainWindow::on_pbClearSourcesXML_clicked()
1158   {
1159 <    clearTableContents(ui->twSourcesGeneral);
1159 >    clearTableContents(ui->twSourcesXML);
1160   }
1161  
1162   void MainWindow::on_pbClearSourcesTextures_clicked()
# Line 961 | Line 1164 | void MainWindow::on_pbClearSourcesTextur
1164      clearTableContents(ui->twSourcesTextures);
1165   }
1166  
1167 < void MainWindow::on_pbClearSourcesModels_clicked()
1167 > void MainWindow::on_pbClearSourcesObjects_clicked()
1168   {
1169 <    clearTableContents(ui->twSourcesModels);
1169 >    clearTableContents(ui->twSourcesObjects);
1170   }
1171  
1172 < void MainWindow::on_pbClearSourcesAnimations_clicked()
1172 > void MainWindow::on_pbClearSourcesCharacters_clicked()
1173   {
1174 <    clearTableContents(ui->twSourcesAnimations);
1174 >    clearTableContents(ui->twSourcesCharacters);
1175   }
1176  
1177   void MainWindow::on_pbClearSourcesLevels_clicked()
# Line 984 | Line 1187 | void MainWindow::on_pbClearSourcesMisc_c
1187   void MainWindow::removeTableContents(DropTableWidget *myTable){
1188      int size = myTable->selectionModel()->selectedRows().size();
1189  
1190 +    QMessageBox::StandardButton defaultButton = QMessageBox::NoButton; // default button for clear asking question, only customizable in mac os
1191 +
1192      if(size==0){
1193 <        Util::showPopUp("Select a row first.");
1193 >        Util::Dialogs::showInfo("Select a row first.");
1194          return;
1195      }
1196  
1197 <    if(Util::showQuestionPopUp(this,"Are you sure you want to delete the selected rows?")){
1197 > #ifdef Q_OS_MAC
1198 >    if(this->useYesAsDefaultWhenRemovingItems){
1199 >        defaultButton = QMessageBox::Yes;
1200 >    }
1201 >    else{
1202 >        defaultButton = QMessageBox::No;
1203 >    }
1204 > #endif
1205 >
1206 >
1207 >    if(Util::Dialogs::showQuestion(this,"Are you sure you want to delete the selected rows?",defaultButton)){
1208          for(int i=0; i<size; i++){
1209              //myTable->removeRow(myTable->selectedItems().at(size-i-1)->row());
1210              myTable->removeRow(myTable->selectionModel()->selectedRows().at(size-i-1).row());
1211          }
1212          updateItemsLoaded(myTable);
1213 +        rowsWereChangedInDropTableWidget();
1214      }
1215   }
1216  
1217   void MainWindow::clearTableContents(DropTableWidget *myTable){
1218 +
1219 +    QMessageBox::StandardButton defaultButton = QMessageBox::NoButton; // default button for clear asking question, only customizable in mac os
1220 +
1221      if(myTable->rowCount()==0){
1222 <        Util::showPopUp("Nothing to clear.");
1222 >        Util::Dialogs::showInfo("Nothing to clear.");
1223          return;
1224      }
1225  
1226 <    if(Util::showQuestionPopUp(this,"Are you sure you want to clear the content?")){
1227 <        myTable->clearContents();
1228 <        myTable->setRowCount(0);
1226 > #ifdef Q_OS_MAC
1227 >    if(this->useYesAsDefaultWhenRemovingItems){
1228 >        defaultButton = QMessageBox::Yes;
1229      }
1230 <    updateItemsLoaded(myTable);
1230 >    else{
1231 >        defaultButton = QMessageBox::No;
1232 >    }
1233 > #endif
1234 >
1235 >    if(Util::Dialogs::showQuestion(this,"Are you sure you want to clear the content?",defaultButton)){
1236 >        clearTableNoPrompt(myTable);
1237 >        updateItemsLoaded(myTable);
1238 >        rowsWereChangedInDropTableWidget();
1239 >    }
1240 >
1241   }
1242  
1243 + void MainWindow::clearTableNoPrompt(DropTableWidget *myTable){
1244 +    myTable->clearContents();
1245 +    myTable->setRowCount(0);
1246 + }
1247  
1248   void MainWindow::on_actionPreferences_triggered()
1249   {
# Line 1021 | Line 1254 | void MainWindow::on_actionPreferences_tr
1254  
1255  
1256   void MainWindow::closeEvent(QCloseEvent *event){
1257 <    if(this->vagoSettings->value("ConfirmExit").toBool()){
1258 <        if(!Util::showQuestionPopUp(this,"Exit Vago?")){
1257 >    if(this->vagoSettings->value("AskSaveProject").toBool() && this->unsavedChangesExist){
1258 >        QMessageBox::StandardButton result = askToSaveCurrentProject();
1259 >        if(result == QMessageBox::StandardButton::Cancel){
1260              event->ignore();
1261 <        }
1028 <    }
1029 < }
1030 <
1031 < void MainWindow::on_cbToGeneral_currentIndexChanged(const QString &arg1)
1032 < {
1033 <
1034 <    ui->cbDatGeneral->setEnabled(false);
1035 <    ui->cbDatGeneral->setChecked(false);
1036 <    ui->cbTRAMGeneral->setEnabled(false);
1037 <    ui->cbTRAMGeneral->setChecked(false);
1038 <
1039 <    if(QString::compare(ui->cbFromGeneral->currentText(),"ONI",Qt::CaseSensitive)==0){
1040 <        if(QString::compare(arg1,"DAT",Qt::CaseSensitive)==0){
1041 <            ui->cbDatGeneral->setEnabled(true);
1042 <        }
1043 <        else{
1044 <            ui->cbTRAMGeneral->setEnabled(true);
1261 >            return;
1262          }
1263      }
1264  
1265 +    // Exit application (this will also close all other windows which don't have parent, for instance ManualCommands)
1266 +    QApplication::quit();
1267   }
1268  
1269 < void MainWindow::on_cbToModels_currentIndexChanged(const QString &arg1)
1270 < {
1271 <    ui->cbWithAnimation->setEnabled(false);
1053 <    ui->cbWithAnimation->setChecked(false);
1269 > QMessageBox::StandardButton MainWindow::askToSaveCurrentProject(){
1270 >    QMessageBox::StandardButton result =
1271 >            Util::Dialogs::showQuestionWithCancel(this,"There are unsaved changes. Do you want to save the current project?", QMessageBox::StandardButton::Yes);
1272  
1273 <    if(arg1=="DAE"){
1274 <        ui->cbWithAnimation->setEnabled(true);
1273 >    if(result == QMessageBox::StandardButton::Yes){
1274 >        on_actionSave_triggered();
1275      }
1276 +
1277 +    return result;
1278   }
1279  
1280   void MainWindow::on_cbToLevels_currentIndexChanged(const QString &arg1)
1281   {
1282  
1063    ui->cbDatLevels->setEnabled(false);
1064    ui->cbDatLevels->setChecked(false);
1065    ui->cbBnvLevels->setEnabled(false);
1066    ui->cbBnvLevels->setChecked(false);
1067    ui->cbAdditionalSourcesLevels->setEnabled(false);
1068    ui->cbAdditionalSourcesLevels->setChecked(false);
1069    ui->cbGridsLevels->setEnabled(false);
1070    ui->cbGridsLevels->setChecked(false);
1071
1283      if(ui->cbFromLevels->currentText()=="MASTER XML" && arg1=="DAT"){
1284          ui->cbDatLevels->setEnabled(true);
1285      }
1286 <    else if(ui->cbFromLevels->currentText()=="DAE" && arg1=="ONI"){
1287 <        ui->cbBnvLevels->setEnabled(true);
1288 <        ui->cbAdditionalSourcesLevels->setEnabled(true);
1286 >    else if(ui->cbFromLevels->currentText()=="MASTER XML" && arg1=="ONI FILES"){
1287 >        ui->cbDatLevels->setEnabled(false);
1288 >        ui->cbDatLevels->setChecked(false);
1289      }
1079 }
1290  
1081 void MainWindow::on_cbDatGeneral_toggled(bool checked)
1082 {
1083    ui->leTargetDatGeneral->setEnabled(checked);
1084 }
1085
1086 void MainWindow::on_cbTRAMGeneral_toggled(bool checked)
1087 {
1088    ui->leTRAMGeneral->setEnabled(checked);
1089    if(checked){
1090        QString file=QFileDialog::getOpenFileName(this,"Choose the TRAM.oni file...","./" , "All Files (*.*)");
1091        if(!file.isEmpty()){
1092            ui->leTRAMGeneral->setText(file);
1093        }
1094    }
1291   }
1292  
1293   void MainWindow::on_cbDatLevels_toggled(bool checked)
# Line 1104 | Line 1300 | void MainWindow::on_cbBnvLevels_toggled(
1300      ui->leBnvLevels->setEnabled(checked);
1301      ui->cbGridsLevels->setEnabled(checked);
1302      ui->cbGridsLevels->setChecked(checked);
1303 <    if(checked){
1303 >    if(checked && !projectIsLoading){
1304          QString file=QFileDialog::getOpenFileName(this,"Choose the BNV.dae file...","./" , "All Files (*.*)");
1305          if(!file.isEmpty()){
1306              ui->leBnvLevels->setText(file);
# Line 1116 | Line 1312 | void MainWindow::on_cbAdditionalSourcesL
1312   {
1313      ui->leAdditSourcesLevels->setEnabled(checked);
1314  
1315 <    if(checked){
1315 >    if(checked && !projectIsLoading){
1316          QStringList filesSelected=QFileDialog::getOpenFileNames(this,"Choose the additional .dae files...","./" , "All Files (*.*)");
1317          QString filesJoined;
1318          int size=filesSelected.size();
# Line 1132 | Line 1328 | void MainWindow::on_cbAdditionalSourcesL
1328      }
1329   }
1330  
1331 + void MainWindow::on_cbWithTRBS_ONCC_toggled(bool checked)
1332 + {
1333 +    ui->leTRBS_ONCC->setEnabled(checked);
1334 + }
1335 +
1336   void MainWindow::on_actionCheck_OniSplit_version_triggered()
1337   {
1338 <    QProcess *myProcess = new QProcess();
1339 <    myProcess->setWorkingDirectory(this->AppDir);
1340 <    myProcess->start(GlobalVars::OniSplitExeName+" -version");
1341 <    myProcess->waitForFinished(-1);
1342 <    QString result=myProcess->readAllStandardOutput();
1343 <    delete myProcess;
1344 <    Util::showPopUp("This Vago version was built with base in OniSplit version "+GlobalVars::BuiltOniSplitVersion+"\n\nActual version is:\n"+result);
1338 >    QProcess myProcess;
1339 >    myProcess.setWorkingDirectory(UtilVago::getAppPath());
1340 >    myProcess.start(UtilVago::getOniSplitExecutable()+" -version");
1341 >    myProcess.waitForFinished();
1342 >
1343 >    QString result=myProcess.readAllStandardOutput();
1344 >
1345 >    Util::Dialogs::showInfo("This Vago version was built with base in OniSplit version "+GlobalVars::BuiltOniSplitVersion+"\n\nCurrent version is:\n"+result.trimmed());
1346   }
1347  
1348   void MainWindow::on_actionCheck_xmlTools_version_triggered()
1349   {
1350 <    QProcess *myProcess = new QProcess();
1351 <    myProcess->setWorkingDirectory(this->AppDir);
1352 <    myProcess->start(GlobalVars::XmlToolsExeName+" version");
1353 <    myProcess->waitForFinished(-1);
1354 <    QString result=myProcess->readLine();
1355 <    delete myProcess;
1356 <    Util::showPopUp("This Vago version was built with base in xmlTools version "+GlobalVars::BuiltXmlToolsVersion+"\n\nActual version is:\n"+result);
1350 >    QProcess myProcess;
1351 >    myProcess.setWorkingDirectory(UtilVago::getAppPath());
1352 >    myProcess.start(UtilVago::getXmlToolsExecutable()+" --version");
1353 >    myProcess.waitForFinished();
1354 >    QString result=myProcess.readLine();
1355 >
1356 >    Util::Dialogs::showInfo("This Vago version was built with base in XmlTools version "+GlobalVars::BuiltXmlToolsVersion+"\n\nCurrent version is:\n"+result.trimmed());
1357   }
1358  
1359   /**
1360    Update items loaded
1361 <  **/
1362 < void MainWindow::on_tabWidget_selected(const QString &arg1)
1361 > **/
1362 > void MainWindow::on_tabWidget_currentChanged(int)
1363   {
1364 <    if(arg1.compare("General",Qt::CaseSensitive)==0){ //case sentive is faster
1163 <        updateItemsLoaded(ui->twSourcesGeneral);
1164 <    }
1165 <    else if(arg1.compare("Textures",Qt::CaseSensitive)==0){
1166 <        updateItemsLoaded(ui->twSourcesTextures);
1167 <    }
1168 <    else if(arg1.compare("Models",Qt::CaseSensitive)==0){
1169 <        updateItemsLoaded(ui->twSourcesModels);
1170 <    }
1171 <    else if(arg1.compare("Levels",Qt::CaseSensitive)==0){
1172 <        updateItemsLoaded(ui->twSourcesLevels);
1173 <    }
1174 <    else{
1175 <        updateItemsLoaded(ui->twSourcesMisc);
1176 <    }
1364 >    updateItemsLoaded(getCurrentTableWidget());
1365   }
1366  
1367   void MainWindow::updateItemsLoaded(DropTableWidget *currentTable){
# Line 1183 | Line 1371 | void MainWindow::updateItemsLoaded(DropT
1371      this->itemsLoaded->setText(QString().setNum(numItems)+ (numItems==1?" item ":" items ") +"loaded");
1372   }
1373  
1374 + void MainWindow::rowsWereChangedInDropTableWidget(){
1375 +    // We have changed rows, we have now unsaved changes.
1376 +    if(!this->unsavedChangesExist){
1377 +        this->unsavedChangesExist = true;
1378 +        setVagoWindowTitle();
1379 +    }
1380 + }
1381 +
1382   void MainWindow::on_tbCommand_clicked()
1383   {
1384 <    //Show preferences
1385 <    ManualCommands *commandsWindow = new ManualCommands(this);
1384 >    //We pass no parent because we want to have an independent window for ManualCommands,
1385 >    //so we can minimize it or maximize indepently from the MainWindow
1386 >    ManualCommands *commandsWindow = new ManualCommands();
1387      commandsWindow->show(); //it destroys itself when finished.
1388   }
1389  
# Line 1196 | Line 1393 | void MainWindow::on_actionWorkspace_trig
1393      ui->actionOther->setChecked(false);
1394      this->outputFolder=this->workspaceLocation;
1395      ui->tbOpenFolder->setToolTip("Open Vago workspace");
1396 <    showSuccessStatusMessage("Vago is now outputting the NEW items for Vago workspace.");
1396 >    Util::StatusBar::showSuccess(ui->statusBar, "Vago is now outputting the NEW items for Vago workspace.");
1397   }
1398  
1399   void MainWindow::on_actionOther_triggered()
1400   {
1401      QString newDir=QFileDialog::getExistingDirectory(this,"Choose the folder for output NEW files directly...",this->AeLocation+"/GameDataFolder");
1402 <    newDir=Util::normalizePath(newDir);
1402 >    newDir=Util::FileSystem::normalizePath(newDir);
1403  
1404      if(newDir.isEmpty()){
1405          ui->actionOther->setChecked(false);
# Line 1219 | Line 1416 | void MainWindow::on_actionOther_triggere
1416  
1417      this->outputFolder=newDir;
1418  
1419 <    QString newDirName=Util::cutName(newDir);
1419 >    QString newDirName=Util::FileSystem::cutName(newDir);
1420      ui->tbOpenFolder->setToolTip("Open "+newDirName+" output folder");
1421 <    showSuccessStatusMessage("Vago is now outputting the NEW items for "+newDirName+".");
1421 >    Util::StatusBar::showSuccess(ui->statusBar, "Vago is now outputting the NEW items for "+newDirName+".");
1422   }
1423  
1424   void MainWindow::on_actionView_log_triggered()
1425   {
1426 <    Util::openLogFile();
1426 >    UtilVago::openLogFile();
1427 > }
1428 >
1429 > void MainWindow::on_actionOpen_AE_folder_triggered()
1430 > {
1431 >    QDesktopServices::openUrl(QUrl("file:///"+this->AeLocation));
1432 > }
1433 >
1434 > void MainWindow::on_actionSave_Project_triggered()
1435 > {
1436 >
1437 >    QString filePath = QFileDialog::getSaveFileName(this, tr("Save File"),
1438 >                                                    this->vagoSettings->value("LastProjectPath").toString(),
1439 >                                                    tr("Vago project files (*.vgp)"));
1440 >
1441 >    if(!filePath.isEmpty()){
1442 >        saveProjectState(filePath);
1443 >    }
1444 >
1445 > }
1446 >
1447 > // New Project
1448 > void MainWindow::on_actionNew_Project_triggered()
1449 > {
1450 >    if(this->vagoSettings->value("AskSaveProject").toBool() && this->unsavedChangesExist){
1451 >        QMessageBox::StandardButton result = askToSaveCurrentProject();
1452 >        if(result == QMessageBox::StandardButton::Cancel){
1453 >            return;
1454 >        }
1455 >    }
1456 >
1457 >    QList<DropTableWidget*> myTables = getAllTableWidgets();
1458 >
1459 >    for(DropTableWidget* const currTable : myTables){
1460 >        clearTableNoPrompt(currTable);
1461 >    }
1462 >
1463 >    this->lastProjectFilePath=""; // clear last project file path
1464 >    this->unsavedChangesExist = false;
1465 >
1466 >    setVagoWindowTitle(); // update vago title
1467 > }
1468 >
1469 > void MainWindow::on_actionSave_triggered()
1470 > {
1471 >    if(this->lastProjectFilePath.isEmpty()){
1472 >        on_actionSave_Project_triggered();
1473 >        return;
1474 >    }
1475 >
1476 >    saveProjectState(this->lastProjectFilePath);
1477 > }
1478 >
1479 > void MainWindow::on_actionLoad_Project_triggered()
1480 > {
1481 >
1482 >    QString filePath = QFileDialog::getOpenFileName(this, tr("Load File"),
1483 >                                                    this->vagoSettings->value("LastProjectPath").toString(),
1484 >                                                    tr("Vago project files (*.vgp)"));
1485 >    if(!filePath.isEmpty()){
1486 >        loadProjectState(filePath);
1487 >    }
1488 > }
1489 >
1490 > void MainWindow::on_actionProject1_triggered()
1491 > {
1492 >    loadProjectState(this->ui->actionProject1->text());
1493 > }
1494 >
1495 > void MainWindow::on_actionProject2_triggered()
1496 > {
1497 >    loadProjectState(this->ui->actionProject2->text());
1498 > }
1499 >
1500 > void MainWindow::on_actionProject3_triggered()
1501 > {
1502 >    loadProjectState(this->ui->actionProject3->text());
1503 > }
1504 >
1505 > void MainWindow::on_actionProject4_triggered()
1506 > {
1507 >    loadProjectState(this->ui->actionProject4->text());
1508 > }
1509 >
1510 > void MainWindow::on_actionProject5_triggered()
1511 > {
1512 >    loadProjectState(this->ui->actionProject5->text());
1513   }
1514  
1515   QString MainWindow::getTypeConversion(DropTableWidget *myTable){
1516      QString from,to;
1517  
1518 <    if(myTable==ui->twSourcesGeneral){
1519 <        from=ui->cbFromGeneral->currentText();
1520 <        to=ui->cbToGeneral->currentText();
1518 >    if(myTable==ui->twSourcesXML){
1519 >        from=ui->cbFromXML->currentText();
1520 >        to=ui->cbToXML->currentText();
1521      }
1522      else if(myTable==ui->twSourcesTextures){
1523          from=ui->cbFromTextures->currentText();
1524          to=ui->cbToTextures->currentText();
1525      }
1526 <    else if(myTable==ui->twSourcesModels){
1527 <        from=ui->cbFromModels->currentText();
1528 <        to=ui->cbToModels->currentText();
1529 <    }
1530 <    else if(myTable==ui->twSourcesAnimations){
1531 <        from=ui->cbFromAnimations->currentText();
1532 <        to=ui->cbToAnimations->currentText();
1526 >    else if(myTable==ui->twSourcesObjects){
1527 >        from=ui->cbFromObjects->currentText();
1528 >        to=ui->cbToObjects->currentText();
1529 >    }
1530 >    else if(myTable==ui->twSourcesCharacters){
1531 >        from=ui->cbFromCharacters->currentText();
1532 >        to=ui->cbToCharacters->currentText();
1533      }
1534      else if(myTable==ui->twSourcesLevels){
1535          from=ui->cbFromLevels->currentText();
# Line 1274 | Line 1557 | void MainWindow::dtContextMenu(DropTable
1557  
1558      QList<int> selectedRows = QList<int>();
1559  
1560 <    foreach(QModelIndex rowItem, myTable->selectionModel()->selectedRows()){
1560 >    for(const QModelIndex &rowItem : myTable->selectionModel()->selectedRows()){
1561          selectedRows << rowItem.row();
1562      }
1563  
1564 <    QMenu *menu = new QMenu();
1565 <    QAction *copy = new QAction("Copy",myTable);
1566 <    QAction *moveUp = new QAction("Move Up",myTable);
1567 <    QAction *moveDown = new QAction("Move Down",myTable);
1568 <    QAction *changeOptions = new QAction("Change To Current Options",myTable);
1569 <    QMenu *changeOutput = new QMenu("Change Output for:");
1570 <    QAction *outWorkspace = new QAction("Workspace",myTable);
1571 <    QAction *outCurrOutput = new QAction("Current Output Folder",myTable);
1572 <    QAction *outOther = new QAction("Other...",myTable);
1573 <    QAction *edisable = new QAction("Enable/Disable",myTable);
1564 >    std::unique_ptr<QMenu> menu = std::make_unique<QMenu>();
1565 >    std::unique_ptr<QAction> copy =  std::make_unique<QAction>("Copy",myTable);
1566 >    std::unique_ptr<QAction> moveUp = std::make_unique<QAction>("Move Up",myTable);
1567 >    std::unique_ptr<QAction> moveDown = std::make_unique<QAction>("Move Down",myTable);
1568 >    std::unique_ptr<QAction> changeOptions = std::make_unique<QAction>("Change To Current Options",myTable);
1569 >    std::unique_ptr<QMenu> changeOutput = std::make_unique<QMenu>("Change Output for:");
1570 >    std::unique_ptr<QAction> outWorkspace = std::make_unique<QAction>("Workspace",myTable);
1571 >    std::unique_ptr<QAction> outCurrOutput = std::make_unique<QAction>("Current Output Folder",myTable);
1572 >    std::unique_ptr<QAction> outOther = std::make_unique<QAction>("Other...",myTable);
1573 >    std::unique_ptr<QAction> edisable = std::make_unique<QAction>("Enable/Disable",myTable);
1574  
1575 <    menu->addAction(copy);
1575 >    menu->addAction(copy.get());
1576      menu->addSeparator();
1577 <    menu->addAction(moveUp);
1578 <    menu->addAction(moveDown);
1577 >    menu->addAction(moveUp.get());
1578 >    menu->addAction(moveDown.get());
1579      menu->addSeparator();
1580 <    menu->addAction(changeOptions);
1581 <    menu->addMenu(changeOutput);
1582 <    changeOutput->addActions(QList<QAction*>() << outWorkspace << outCurrOutput << outOther);
1583 <    menu->addAction(edisable);
1580 >    menu->addAction(changeOptions.get());
1581 >    menu->addMenu(changeOutput.get());
1582 >    changeOutput->addActions(QList<QAction*>() << outWorkspace.get() << outCurrOutput.get() << outOther.get());
1583 >    menu->addAction(edisable.get());
1584  
1585  
1586      //if it's in the first row it can't be setted up
# Line 1312 | Line 1595 | void MainWindow::dtContextMenu(DropTable
1595  
1596      //Can we change the settings? (the conversion must be the same)
1597      QString currentSettings = (getTypeConversion(myTable)); //call function at the mainWindow with a signal (different threads?)
1598 <    foreach(int row, selectedRows){
1598 >    for(const int row : selectedRows){
1599          if( myTable->item(row,1)->text() != currentSettings){ //If we find out any of the selected items can't be convert disable operation
1600              changeOptions->setEnabled(false);
1601              break;
# Line 1321 | Line 1604 | void MainWindow::dtContextMenu(DropTable
1604  
1605      QAction* selectedOption = menu->exec(event->globalPos());
1606  
1607 <    if(selectedOption==copy){
1607 >    if(selectedOption==copy.get()){
1608          //Let's copy the contents to the clipboard
1609  
1610          QString toCopy;
# Line 1342 | Line 1625 | void MainWindow::dtContextMenu(DropTable
1625          }
1626  
1627          QApplication::clipboard()->setText(toCopy);
1628 <        showSuccessStatusMessage(QString::number(size) + (size==1?" item ":" items ")+ "copied to the clipboard");
1628 >        Util::StatusBar::showSuccess(ui->statusBar, QString::number(size) + (size==1?" item ":" items ")+ "copied to the clipboard");
1629      }
1630 <    else if(selectedOption==moveUp){
1630 >    else if(selectedOption==moveUp.get()){
1631          qSort(selectedRows); //let's order the selections by the row number, so we know exactly how to swap it
1632          myTable->swapPositions(selectedRows,-1);
1633 +        rowsWereChangedInDropTableWidget();
1634      }
1635 <    else if(selectedOption==moveDown){
1635 >    else if(selectedOption==moveDown.get()){
1636          qSort(selectedRows);
1637          myTable->swapPositions(selectedRows,+1);
1638 +        rowsWereChangedInDropTableWidget();
1639      }
1640 <    else if(selectedOption==changeOptions){
1640 >    else if(selectedOption==changeOptions.get()){
1641          changeToCurrentSettings(selectedRows,myTable);
1642      }
1643 <    else if(selectedOption==outWorkspace){
1643 >    else if(selectedOption==outWorkspace.get()){
1644          changeItemsOutput(myTable,selectedRows,this->workspaceLocation);
1645      }
1646 <    else if(selectedOption==outCurrOutput){
1646 >    else if(selectedOption==outCurrOutput.get()){
1647          changeItemsOutput(myTable,selectedRows,this->outputFolder);
1648      }
1649 <    else if(selectedOption==outOther){
1649 >    else if(selectedOption==outOther.get()){
1650  
1651          QString newDir=QFileDialog::getExistingDirectory(this,"Choose the folder for the output of the files selected...",this->AeLocation+"/GameDataFolder");
1652 <        newDir=Util::normalizePath(newDir);
1652 >        newDir=Util::FileSystem::normalizePath(newDir);
1653  
1654          if(newDir.isEmpty()){
1655              return; //do nothing
# Line 1373 | Line 1658 | void MainWindow::dtContextMenu(DropTable
1658          changeItemsOutput(myTable,selectedRows,newDir);
1659  
1660      }
1661 <    else if(selectedOption==edisable){
1661 >    else if(selectedOption==edisable.get()){
1662  
1663          int enabledCount=0, disabledCount=0;
1664  
# Line 1409 | Line 1694 | void MainWindow::dtContextMenu(DropTable
1694              result+=QString::number(disabledCount) + (disabledCount==1?" item ":" items ") + "Disabled";
1695          }
1696  
1697 <        showSuccessStatusMessage(result);
1697 >        rowsWereChangedInDropTableWidget();
1698 >        Util::StatusBar::showSuccess(ui->statusBar, result);
1699      }
1414
1415    delete copy;
1416    delete moveUp;
1417    delete moveDown;
1418    delete changeOptions;
1419    delete outWorkspace;
1420    delete outCurrOutput;
1421    delete outOther;
1422    delete changeOutput;
1423    delete edisable;
1424    delete menu;
1700   }
1701  
1702   void MainWindow::changeToCurrentSettings(QList<int> rows, DropTableWidget* myTable){
# Line 1433 | Line 1708 | void MainWindow::changeToCurrentSettings
1708  
1709      QString command;
1710  
1711 <    foreach(int row, rows){
1437 <
1711 >    for(int row : rows){
1712          command=getCommand(myTable,getFileOutputFolder(fromTo,myTable->getOutputAbsolute(row)),from,to,myTable->getFileAbsolute(row));
1713  
1714          if(command.isEmpty()){ //something wrong was happening (not inputted a texture name?)
# Line 1445 | Line 1719 | void MainWindow::changeToCurrentSettings
1719          myTable->updateTableToolTips(row);
1720      }
1721  
1722 <    showSuccessStatusMessage(QString::number(rows.size()) + (rows.size()==1?" item ":" items ")+ "changed to the current settings");
1722 >    rowsWereChangedInDropTableWidget();
1723 >    Util::StatusBar::showSuccess(ui->statusBar, QString::number(rows.size()) + (rows.size()==1?" item ":" items ")+ "changed to the current settings");
1724   }
1725  
1726   void MainWindow::changeItemsOutput(DropTableWidget* myTable, QList<int> rows, QString newOutput){
1727  
1728      QString command, currentAbsoluteFile, fromTo, from, to;
1729  
1730 <    foreach(int row, rows){ //No optimization possible here, commands may be different
1730 >    for(const int row : rows){ //No optimization possible here, commands may be different
1731          fromTo=myTable->item(row,1)->text();
1732          from = QString(fromTo).remove(fromTo.indexOf(" >"),fromTo.size()-1); //parse the string to get the from
1733          to = QString(fromTo).remove(0,fromTo.lastIndexOf("> ")+2); //+2 to start after "> "
# Line 1468 | Line 1743 | void MainWindow::changeItemsOutput(DropT
1743          myTable->updateTableToolTips(row);
1744      }
1745  
1746 <    showSuccessStatusMessage(QString::number(rows.size()) + (rows.size()==1?" item ":" items ")+ "changed the output to "+(newOutput!=this->workspaceLocation?Util::cutName(newOutput):"Vago workspace"));
1746 >    rowsWereChangedInDropTableWidget();
1747 >    Util::StatusBar::showSuccess(ui->statusBar, QString::number(rows.size()) + (rows.size()==1?" item ":" items ")+ "changed the output to "+(newOutput!=this->workspaceLocation?Util::FileSystem::cutName(newOutput):"Vago workspace"));
1748   }
1749  
1750   QString MainWindow::getCommand(DropTableWidget* myTable, QString myOutputFolder, QString from, QString to , QString file){
1751 <    if(myTable==ui->twSourcesGeneral){ //So we only need to parse one command.
1752 <        return fileParsingGeneral(myOutputFolder,from,to,file);
1751 >
1752 >    QString tabTitle=ui->tabWidget->tabText(ui->tabWidget->currentIndex()).toLower(); // get current tab title
1753 >
1754 >    if(myTable==ui->twSourcesXML){ //So we only need to parse one command.
1755 >        return fileParsingXML(tabTitle, myOutputFolder,from,to,file);
1756      }
1757      else if(myTable==ui->twSourcesTextures){
1758 <        return fileParsingTextures(myOutputFolder,from,to,file);
1758 >        return fileParsingTextures(tabTitle, myOutputFolder,from,to,file);
1759      }
1760 <    else if(myTable==ui->twSourcesModels){
1761 <        return fileParsingModels(myOutputFolder,from,to,file);
1760 >    else if(myTable==ui->twSourcesObjects){
1761 >        return fileParsingObjects(tabTitle, myOutputFolder,from,to,file);
1762      }
1763 <    else if(myTable==ui->twSourcesAnimations){
1764 <        return fileParsingAnimations(myOutputFolder,from,to,file);
1763 >    else if(myTable==ui->twSourcesCharacters){
1764 >        return fileParsingCharacters(tabTitle, myOutputFolder,from,to,file);
1765      }
1766      else if(myTable==ui->twSourcesLevels){
1767 <        return fileParsingLevels(myOutputFolder,from,to,file);
1767 >        return fileParsingLevels(tabTitle, myOutputFolder,from,to,file);
1768      }
1769      else{
1770          return fileParsingMisc(myOutputFolder,from,to,file);
# Line 1493 | Line 1772 | QString MainWindow::getCommand(DropTable
1772  
1773   }
1774  
1496 /**
1497  This is OS indepented. It maintain size ratio over the Windows and Mac.
1498  **/
1499 void MainWindow::setConverterButtonsSize(){
1500    int height=ui->pbConvertGeneral->sizeHint().height()*1.3;
1501    ui->pbConvertGeneral->setMinimumHeight(height);
1502    ui->pbConvertTextures->setMinimumHeight(height);
1503    ui->pbConvertModels->setMinimumHeight(height);
1504    ui->pbConvertAnimations->setMinimumHeight(height);
1505    ui->pbConvertLevels->setMinimumHeight(height);
1506    ui->pbConvertMisc->setMinimumHeight(height);
1507 }
1508
1509 /**
1510  Gets application directory. In mac os gets the .app directory
1511  **/
1512 QString MainWindow::getOSIndependentAppPath(){
1513 #ifdef Q_WS_MAC
1514    QDir dir = QDir::current();
1515    if(dir.absolutePath().contains(".app")){ // include bundle, but we don't want it
1516        dir.cdUp();
1517        dir.cdUp();
1518        dir.cdUp();
1519    }
1520    return dir.absolutePath();
1521 #else
1522    return  QDir::currentPath();
1523 #endif
1524 }
1525
1775   void MainWindow::connectSlots(){
1776  
1777      //This signal is for thread that is working setup the progress bar (make it visible and set it's min-max)
# Line 1534 | Line 1783 | void MainWindow::connectSlots(){
1783      //This signal is for thread that is working can show the result of a conversion
1784      connect(myConverter, SIGNAL(resultConversion(QString,int)), this, SLOT(TresultConversion(QString,int)));
1785  
1786 +    //This signal is for thread that is working notify the gui thread that the conversion was aborted with sucess
1787 +    connect(myConverter, SIGNAL(conversionAborted()), this, SLOT(TconversionAborted()));
1788 +
1789 +    // This signal is to the user be able to terminate a conversion (OniSplit process in class myConverter will be terminated)
1790 +    connect(this, SIGNAL(terminateCurrProcess()), myConverter, SLOT(terminateCurrProcess()));
1791 +
1792      //Drop signal for General table
1793 <    connect(ui->twSourcesGeneral, SIGNAL(dropped(DropTableWidget*,QStringList)), this, SLOT(addFilesSource(DropTableWidget*,QStringList)));
1793 >    connect(ui->twSourcesXML, SIGNAL(dropped(DropTableWidget*,QStringList)), this, SLOT(addFilesSource(DropTableWidget*,QStringList)));
1794  
1795      //Drop signal for Textures table
1796      connect(ui->twSourcesTextures, SIGNAL(dropped(DropTableWidget*,QStringList)), this, SLOT(addFilesSource(DropTableWidget*,QStringList)));
1797  
1798 <    //Drop signal for Models table
1799 <    connect(ui->twSourcesModels, SIGNAL(dropped(DropTableWidget*,QStringList)), this, SLOT(addFilesSource(DropTableWidget*,QStringList)));
1798 >    //Drop signal for Objects table
1799 >    connect(ui->twSourcesObjects, SIGNAL(dropped(DropTableWidget*,QStringList)), this, SLOT(addFilesSource(DropTableWidget*,QStringList)));
1800  
1801 <    //Drop signal for Animations table
1802 <    connect(ui->twSourcesAnimations, SIGNAL(dropped(DropTableWidget*,QStringList)), this, SLOT(addFilesSource(DropTableWidget*,QStringList)));
1801 >    //Drop signal for Characters table
1802 >    connect(ui->twSourcesCharacters, SIGNAL(dropped(DropTableWidget*,QStringList)), this, SLOT(addFilesSource(DropTableWidget*,QStringList)));
1803  
1804      //Drop signal for Levels table
1805      connect(ui->twSourcesLevels, SIGNAL(dropped(DropTableWidget*,QStringList)), this, SLOT(addFilesSource(DropTableWidget*,QStringList)));
# Line 1553 | Line 1808 | void MainWindow::connectSlots(){
1808      connect(ui->twSourcesMisc, SIGNAL(dropped(DropTableWidget*,QStringList)), this, SLOT(addFilesSource(DropTableWidget*,QStringList)));
1809  
1810      //Context menu for General table
1811 <    connect(ui->twSourcesGeneral, SIGNAL(dtContextMenu(DropTableWidget*,QContextMenuEvent*)), this, SLOT(dtContextMenu(DropTableWidget*,QContextMenuEvent*)));
1811 >    connect(ui->twSourcesXML, SIGNAL(dtContextMenu(DropTableWidget*,QContextMenuEvent*)), this, SLOT(dtContextMenu(DropTableWidget*,QContextMenuEvent*)));
1812  
1813      //Context menu for Textures table
1814      connect(ui->twSourcesTextures, SIGNAL(dtContextMenu(DropTableWidget*,QContextMenuEvent*)), this, SLOT(dtContextMenu(DropTableWidget*,QContextMenuEvent*)));
1815  
1816 <    //Context menu for Models table
1817 <    connect(ui->twSourcesModels, SIGNAL(dtContextMenu(DropTableWidget*,QContextMenuEvent*)), this, SLOT(dtContextMenu(DropTableWidget*,QContextMenuEvent*)));
1816 >    //Context menu for Objects table
1817 >    connect(ui->twSourcesObjects, SIGNAL(dtContextMenu(DropTableWidget*,QContextMenuEvent*)), this, SLOT(dtContextMenu(DropTableWidget*,QContextMenuEvent*)));
1818  
1819 <    //Context menu for Animations table
1820 <    connect(ui->twSourcesAnimations, SIGNAL(dtContextMenu(DropTableWidget*,QContextMenuEvent*)), this, SLOT(dtContextMenu(DropTableWidget*,QContextMenuEvent*)));
1819 >    //Context menu for Characters table
1820 >    connect(ui->twSourcesCharacters, SIGNAL(dtContextMenu(DropTableWidget*,QContextMenuEvent*)), this, SLOT(dtContextMenu(DropTableWidget*,QContextMenuEvent*)));
1821  
1822      //Context menu for Levels table
1823      connect(ui->twSourcesLevels, SIGNAL(dtContextMenu(DropTableWidget*,QContextMenuEvent*)), this, SLOT(dtContextMenu(DropTableWidget*,QContextMenuEvent*)));
# Line 1571 | Line 1826 | void MainWindow::connectSlots(){
1826      connect(ui->twSourcesMisc, SIGNAL(dtContextMenu(DropTableWidget*,QContextMenuEvent*)), this, SLOT(dtContextMenu(DropTableWidget*,QContextMenuEvent*)));
1827   }
1828  
1829 + void MainWindow::saveProjectState(const QString &filePath)
1830 + {
1831 +    try{
1832 +        ProjectFileVago::saveProjectDataToFile(filePath, fetchCurrentProjectData());
1833 +
1834 +        this->vagoSettings->setValue("LastProjectPath",QFileInfo(filePath).absoluteDir().path());
1835 +
1836 +        this->lastProjectFilePath = filePath;
1837 +        this->unsavedChangesExist = false;
1838 +
1839 +        addNewRecentProject(filePath);
1840 +
1841 +        setVagoWindowTitle();
1842 +
1843 +        Util::StatusBar::showSuccess(ui->statusBar, "Project saved sucessfully.");
1844 +    }
1845 +    catch(const std::exception& e){
1846 +        QString errorMessage = "An error ocurred while trying to save the project file. Please try another path.";
1847 +        UtilVago::showAndLogErrorPopUpLogButton(errorMessage);
1848 +        Util::StatusBar::showError(ui->statusBar, "Couldn't save project file.");
1849 +    }
1850 + }
1851 +
1852 + ProjectFileVago::ProjectData MainWindow::fetchCurrentProjectData(){
1853 +
1854 +    ProjectFileVago::ProjectData currentProjectData;
1855 +
1856 +    auto fFetchTabGenericData =
1857 +            [](ProjectFileVago::ProjectTable &projectTable,
1858 +            const QComboBox * const cbFrom,
1859 +            const QComboBox * const cbTo,
1860 +            DropTableWidget const * const table) ->void{
1861 +
1862 +        projectTable.from = cbFrom->currentText();
1863 +        projectTable.to = cbTo->currentText();
1864 +
1865 +        for(int i=0; i<table->rowCount(); i++){
1866 +
1867 +            ProjectFileVago::ProjectTableRow currentRow;
1868 +
1869 +            currentRow.fileFolder = table->item(i,0)->text();
1870 +            currentRow.fromTo = table->item(i,1)->text();
1871 +            currentRow.command= table->item(i,2)->text();
1872 +
1873 +            if(table->item(i,2)->background()==table->disabledBackStyle){
1874 +                currentRow.isDisabled = true;
1875 +            }
1876 +
1877 +            projectTable.rows.append(currentRow);
1878 +        }
1879 +    };
1880 +
1881 +    // XML tab
1882 +    fFetchTabGenericData(currentProjectData.xmlTable, ui->cbFromXML, ui->cbToXML, ui->twSourcesXML);
1883 +
1884 +    // Textures tab
1885 +    fFetchTabGenericData(currentProjectData.texturesTable, ui->cbFromTextures, ui->cbToTextures, ui->twSourcesTextures);
1886 +    currentProjectData.texturesTable.rbTexturesType = getTextureRBCheckedTypeTexture()->text();
1887 +    currentProjectData.texturesTable.cbGenMipMaps = ui->cbMipMapsTextures->isChecked();
1888 +    currentProjectData.texturesTable.cbNoUwrap = ui->cbNoUwrap->isChecked();
1889 +    currentProjectData.texturesTable.cbNoVwrap = ui->cbNoVwrap->isChecked();
1890 +    currentProjectData.texturesTable.cbLarge = ui->cbLarge->isChecked();
1891 +    currentProjectData.texturesTable.cbEnvMap = ui->cbEnvMap->isChecked();
1892 +    currentProjectData.texturesTable.leEnvMapTexture = ui->leEnvMapTexture->text();
1893 +
1894 +    // Characters tab
1895 +    fFetchTabGenericData(currentProjectData.charactersTable, ui->cbFromCharacters, ui->cbToCharacters, ui->twSourcesCharacters);
1896 +    currentProjectData.charactersTable.cbCellShading = ui->cbCellShading->isChecked();
1897 +    currentProjectData.charactersTable.cbNormals = ui->cbNormals->isChecked();
1898 +    currentProjectData.charactersTable.cbStandingPose = ui->cbStandingPose->isChecked();
1899 +    currentProjectData.charactersTable.cbWithTRBS_ONCC = ui->cbWithTRBS_ONCC->isChecked();
1900 +    currentProjectData.charactersTable.leTRBS_ONCC = ui->leTRBS_ONCC->text();
1901 +
1902 +    // Objects tab
1903 +    fFetchTabGenericData(currentProjectData.objectsTable, ui->cbFromObjects, ui->cbToObjects, ui->twSourcesObjects);
1904 +    currentProjectData.objectsTable.cbTexture = ui->cbTexture->isChecked();
1905 +    currentProjectData.objectsTable.leTextureName = ui->leTextureName->text();
1906 +    currentProjectData.objectsTable.cbWithAnimation = ui->cbWithAnimation->isChecked();
1907 +    currentProjectData.objectsTable.leAnimationName = ui->leAnimationName->text();
1908 +
1909 +    // Levels tab
1910 +    fFetchTabGenericData(currentProjectData.levelsTable, ui->cbFromLevels, ui->cbToLevels, ui->twSourcesLevels);
1911 +    currentProjectData.levelsTable.cbSpecificFilesLevels = ui->cbSpecificFilesLevels->isChecked();
1912 +    currentProjectData.levelsTable.leSpecificFilesLevels = ui->leSpecificFilesLevels->text();
1913 +    currentProjectData.levelsTable.cbDatLevels = ui->cbDatLevels->isChecked();
1914 +    currentProjectData.levelsTable.leTargetDatLevels = ui->leTargetDatLevels->text();
1915 +    currentProjectData.levelsTable.cbBnvLevels = ui->cbBnvLevels->isChecked();
1916 +    currentProjectData.levelsTable.leBnvLevels = ui->leBnvLevels->text();
1917 +    currentProjectData.levelsTable.cbGridsLevels = ui->cbGridsLevels->isChecked();
1918 +    currentProjectData.levelsTable.cbAdditionalSourcesLevels = ui->cbAdditionalSourcesLevels->isChecked();
1919 +    currentProjectData.levelsTable.leAdditSourcesLevels = ui->leAdditSourcesLevels->text();
1920 +
1921 +    // Misc tab
1922 +    fFetchTabGenericData(currentProjectData.miscTable, ui->cbFromMisc, ui->cbToMisc, ui->twSourcesMisc);
1923 +
1924 +    return currentProjectData;
1925 + }
1926 +
1927 + QRadioButton* MainWindow::getTextureRBCheckedTypeTexture()
1928 + {
1929 +    if(ui->rbBGR32->isChecked()){
1930 +        return ui->rbBGR32;
1931 +    }
1932 +    else if(ui->rbBGRA32->isChecked()){
1933 +        return ui->rbBGRA32;
1934 +    }
1935 +    else if(ui->rbBGR555->isChecked()){
1936 +        return ui->rbBGR555;
1937 +    }
1938 +    else if(ui->rbBGRA5551->isChecked()){
1939 +        return ui->rbBGRA5551;
1940 +    }
1941 +    else if(ui->rbBGRA444->isChecked()){
1942 +        return ui->rbBGRA444;
1943 +    }
1944 +    else{ //dxt1 checked
1945 +        return ui->rbDxt1;
1946 +    }
1947 + }
1948  
1949 + QRadioButton* MainWindow::getTextureRBTypeTextureByName(const QString &texType)
1950 + {
1951 +    if(QString::compare(texType,ui->rbBGR32->text(),Qt::CaseSensitive)==0){
1952 +        return ui->rbBGR32;
1953 +    }
1954 +    else if(QString::compare(texType,ui->rbBGRA32->text(),Qt::CaseSensitive)==0){
1955 +        return ui->rbBGRA32;
1956 +    }
1957 +    else if(QString::compare(texType, ui->rbBGR555->text(),Qt::CaseSensitive)==0){
1958 +        return ui->rbBGR555;
1959 +    }
1960 +    else if(QString::compare(texType,ui->rbBGRA5551->text(),Qt::CaseSensitive)==0){
1961 +        return ui->rbBGRA5551;
1962 +    }
1963 +    else if(QString::compare(texType,ui->rbBGRA444->text(),Qt::CaseSensitive)==0){
1964 +        return ui->rbBGRA444;
1965 +    }
1966 +    else{ //dxt1
1967 +        return ui->rbDxt1;
1968 +    }
1969 +
1970 + }
1971 +
1972 + void MainWindow::setVagoWindowTitle(){
1973 +
1974 +    QString vagoTitle = "Vago v"+GlobalVars::AppVersion + " - ";
1975 +
1976 +    if(this->lastProjectFilePath.isEmpty()){
1977 +        vagoTitle += "Untitled";
1978 +    }
1979 +    else{
1980 +        vagoTitle += Util::FileSystem::cutNameWithoutBackSlash(this->lastProjectFilePath);
1981 +    }
1982 +
1983 +    if(this->unsavedChangesExist){
1984 +        vagoTitle += "*";
1985 +    }
1986 +
1987 +    setWindowTitle(vagoTitle);
1988 + }
1989 +
1990 + DropTableWidget* MainWindow::getCurrentTableWidget(){
1991 +
1992 +    return getTableWidgetByTabName(ui->tabWidget->tabText(ui->tabWidget->currentIndex()));
1993 +
1994 + }
1995 +
1996 + DropTableWidget* MainWindow::getTableWidgetByTabName(const QString &tabName){
1997 +
1998 +    if(tabName.compare("XML",Qt::CaseSensitive)==0){ //case sentive is faster
1999 +        return ui->twSourcesXML;
2000 +    }
2001 +    else if(tabName.compare("Textures",Qt::CaseSensitive)==0){
2002 +        return ui->twSourcesTextures;
2003 +    }
2004 +    else if(tabName.compare("Characters",Qt::CaseSensitive)==0){
2005 +        return ui->twSourcesCharacters;
2006 +    }
2007 +    else if(tabName.compare("Objects",Qt::CaseSensitive)==0){
2008 +        return ui->twSourcesObjects;
2009 +    }
2010 +    else if(tabName.compare("Levels",Qt::CaseSensitive)==0){
2011 +        return ui->twSourcesLevels;
2012 +    }
2013 +    else{
2014 +        return ui->twSourcesMisc;
2015 +    }
2016 +
2017 + }
2018 +
2019 + QString MainWindow::getCurrentTabName(){
2020 +    return ui->tabWidget->tabText(ui->tabWidget->currentIndex());
2021 + }
2022 +
2023 + QString MainWindow::getTabNameByTableWidget(DropTableWidget* table){
2024 +
2025 +    if(table == ui->twSourcesXML){
2026 +        return ui->tabWidget->tabText(XMLTabIndex);
2027 +    }
2028 +    else if(table == ui->twSourcesTextures){
2029 +        return ui->tabWidget->tabText(TexturesTabIndex);
2030 +    }
2031 +    else if(table == ui->twSourcesCharacters){
2032 +        return ui->tabWidget->tabText(CharactersTabIndex);
2033 +    }
2034 +    else if(table == ui->twSourcesObjects){
2035 +        return ui->tabWidget->tabText(ObjectsTabIndex);
2036 +    }
2037 +    else if(table == ui->twSourcesLevels){
2038 +        return ui->tabWidget->tabText(LevelsTabIndex);
2039 +    }
2040 +    else{
2041 +        return ui->tabWidget->tabText(MiscTabIndex);
2042 +    }
2043 +
2044 + }
2045 +
2046 + QList<DropTableWidget*> MainWindow::getAllTableWidgets()
2047 + {
2048 +    QList<DropTableWidget*> tableWidgets;
2049 +
2050 +    tableWidgets << ui->twSourcesXML << ui->twSourcesTextures << ui->twSourcesCharacters
2051 +                 << ui->twSourcesObjects << ui->twSourcesLevels << ui->twSourcesMisc;
2052 +
2053 +    return tableWidgets;
2054 + }
2055 +
2056 + void MainWindow::loadProjectState(const QString &filePath)
2057 + {
2058 +
2059 +    auto fLoadTabGenericData =
2060 +            [this]( // we are capturing this only to call the addRowTable function...
2061 +                const ProjectFileVago::ProjectTable &tableData,
2062 +                DropTableWidget * const table,
2063 +                QComboBox * const cbFrom,
2064 +                QComboBox * const cbTo) -> void{
2065 +
2066 +        cbFrom->setCurrentText(tableData.from);
2067 +        cbTo->setCurrentText(tableData.to);
2068 +
2069 +        // Add rows
2070 +        for(const ProjectFileVago::ProjectTableRow &currentRow : tableData.rows){
2071 +            addRowTable(table,currentRow.fileFolder,currentRow.fromTo,currentRow.command, currentRow.isDisabled);
2072 +        }
2073 +
2074 +    };
2075 +
2076 +    this->projectIsLoading = true;
2077 +
2078 +    if(this->vagoSettings->value("AskSaveProject").toBool() && this->unsavedChangesExist){
2079 +        QMessageBox::StandardButton result = askToSaveCurrentProject();
2080 +        if(result == QMessageBox::StandardButton::Cancel){
2081 +            this->projectIsLoading = false;
2082 +            return;
2083 +        }
2084 +    }
2085 +
2086 +    try{
2087 +        ProjectFileVago::ProjectData projectData = ProjectFileVago::readProjectDataFromFile(filePath);
2088 +
2089 +        // XML tab
2090 +        fLoadTabGenericData(projectData.xmlTable, ui->twSourcesXML, ui->cbFromXML, ui->cbToXML);
2091 +
2092 +        // Textures tab
2093 +        fLoadTabGenericData(projectData.texturesTable, ui->twSourcesTextures, ui->cbFromTextures, ui->cbToTextures);
2094 +        getTextureRBTypeTextureByName(projectData.texturesTable.rbTexturesType)->setChecked(true);
2095 +        ui->cbMipMapsTextures->setChecked(projectData.texturesTable.cbGenMipMaps);
2096 +        ui->cbNoUwrap->setChecked(projectData.texturesTable.cbNoUwrap);
2097 +        ui->cbNoVwrap->setChecked(projectData.texturesTable.cbNoVwrap);
2098 +        ui->cbLarge->setChecked(projectData.texturesTable.cbLarge);
2099 +        ui->cbEnvMap->setChecked(projectData.texturesTable.cbEnvMap);
2100 +        ui->leEnvMapTexture->setText(projectData.texturesTable.leEnvMapTexture);
2101 +
2102 +        // Characters tab
2103 +        fLoadTabGenericData(projectData.charactersTable, ui->twSourcesCharacters, ui->cbFromCharacters, ui->cbToCharacters);
2104 +
2105 +        ui->cbCellShading->setChecked(projectData.charactersTable.cbCellShading);
2106 +        ui->cbNormals->setChecked(projectData.charactersTable.cbNormals);
2107 +        ui->cbStandingPose->setChecked(projectData.charactersTable.cbStandingPose);
2108 +        ui->cbWithTRBS_ONCC->setChecked(projectData.charactersTable.cbWithTRBS_ONCC);
2109 +        ui->leTRBS_ONCC->setText(projectData.charactersTable.leTRBS_ONCC);
2110 +
2111 +        // Objects tab
2112 +        fLoadTabGenericData(projectData.objectsTable, ui->twSourcesObjects, ui->cbFromObjects, ui->cbToObjects);
2113 +
2114 +        ui->cbTexture->setChecked(projectData.objectsTable.cbTexture);
2115 +        ui->leTextureName->setText(projectData.objectsTable.leTextureName);
2116 +        ui->cbWithAnimation->setChecked(projectData.objectsTable.cbWithAnimation);
2117 +        ui->leAnimationName->setText(projectData.objectsTable.leAnimationName);
2118 +
2119 +        // Levels tab
2120 +        fLoadTabGenericData(projectData.levelsTable, ui->twSourcesLevels, ui->cbFromLevels, ui->cbToLevels);
2121 +
2122 +        ui->cbSpecificFilesLevels->setChecked(projectData.levelsTable.cbSpecificFilesLevels);
2123 +        ui->leSpecificFilesLevels->setText(projectData.levelsTable.leSpecificFilesLevels);
2124 +        ui->cbDatLevels->setChecked(projectData.levelsTable.cbDatLevels);
2125 +        ui->leTargetDatLevels->setText(projectData.levelsTable.leTargetDatLevels);
2126 +        ui->cbBnvLevels->setChecked(projectData.levelsTable.cbBnvLevels);
2127 +        ui->leBnvLevels->setText(projectData.levelsTable.leBnvLevels);
2128 +        ui->cbGridsLevels->setChecked(projectData.levelsTable.cbGridsLevels);
2129 +        ui->cbAdditionalSourcesLevels->setChecked(projectData.levelsTable.cbAdditionalSourcesLevels);
2130 +        ui->leAdditSourcesLevels->setText(projectData.levelsTable.leAdditSourcesLevels);
2131 +
2132 +        // Misc tab
2133 +        fLoadTabGenericData(projectData.miscTable, ui->twSourcesMisc, ui->cbFromMisc, ui->cbToMisc);
2134 +
2135 +        this->vagoSettings->setValue("LastProjectPath",QFileInfo(filePath).absoluteDir().path());
2136 +
2137 +        this->lastProjectFilePath = filePath;
2138 +        this->unsavedChangesExist = false;
2139 +
2140 +        addNewRecentProject(filePath);
2141 +
2142 +        setVagoWindowTitle();
2143 +
2144 +        this->projectIsLoading = false;
2145 +
2146 +        Util::StatusBar::showSuccess(ui->statusBar, "Project loaded sucessfully.");
2147 +    }
2148 +    catch(const std::exception& e){
2149 +        this->projectIsLoading = false;
2150 +        QString errorMessage = "Couldn't load the Vago project. Error: " + QString(e.what());
2151 +        LOG_ERROR << errorMessage;
2152 +        Util::Dialogs::showError(errorMessage);
2153 +        Util::StatusBar::showError(ui->statusBar, "Couldn't load project.");
2154 +    }
2155 +
2156 + }
2157 +
2158 + void MainWindow::saveRecentProjects(){
2159 +    for(int i=0; i<this->recentProjectsList.size(); i++){
2160 +        this->vagoSettings->setValue("RecentProject" + QString::number(i+1), recentProjectsList[i]);
2161 +    }
2162 + }
2163 +
2164 + void MainWindow::loadRecentProjects(){
2165 +    for(int i=0; i<this->recentProjectsMaxSize; i++){
2166 +
2167 +        QString currProj = this->vagoSettings->value("RecentProject" + QString::number(i+1)).toString();
2168 +
2169 +        if(!currProj.isEmpty()){
2170 +            recentProjectsList.append(currProj);
2171 +        }
2172 +        else{
2173 +            break;
2174 +        }
2175 +    }
2176 +
2177 +    reloadRecentProjectsMenu();
2178 +
2179 + }
2180 +
2181 + void MainWindow::addNewRecentProject(const QString &filePath){
2182 +
2183 +    // If the new project is equal to the last one simply ignore
2184 +    if(filePath == this->vagoSettings->value("RecentProject1").toString()){
2185 +        return;
2186 +    }
2187 +
2188 +    // If the item already exists in our list remove it, so it can go to the top again
2189 +    for(auto it = this->recentProjectsList.begin(); it != this->recentProjectsList.end();){
2190 +        if(*it == filePath){
2191 +            it = this->recentProjectsList.erase(it);
2192 +        }
2193 +        else{
2194 +            it++;
2195 +        }
2196 +    }
2197 +
2198 +    // if we gonna overflow our list, remove the older item to reserve space to the new one
2199 +    if(this->recentProjectsList.size()==this->recentProjectsMaxSize){
2200 +        this->recentProjectsList.removeLast();
2201 +    }
2202 +
2203 +    this->vagoSettings->setValue("LastProjectPath",QFileInfo(filePath).absoluteDir().path());
2204 +
2205 +    // add new recent file
2206 +    this->recentProjectsList.prepend(filePath);
2207 +
2208 +    reloadRecentProjectsMenu();
2209 +
2210 +    saveRecentProjects();
2211 + }
2212 +
2213 + void MainWindow::reloadRecentProjectsMenu(){
2214 +
2215 +    ui->menuRecent_Projects->setEnabled(false);
2216 +    ui->actionProject1->setVisible(false);
2217 +    ui->actionProject2->setVisible(false);
2218 +    ui->actionProject3->setVisible(false);
2219 +    ui->actionProject4->setVisible(false);
2220 +    ui->actionProject5->setVisible(false);
2221 +
2222 +    {
2223 +        QList<QString>::const_iterator it;
2224 +        int i;
2225 +        for(it = recentProjectsList.cbegin(), i=0; it != recentProjectsList.cend(); it++, i++){
2226 +
2227 +            QAction* currAction = nullptr;
2228 +
2229 +            switch (i){
2230 +            case 0:
2231 +                currAction = ui->actionProject1;
2232 +                break;
2233 +            case 1:
2234 +                currAction = ui->actionProject2;
2235 +                break;
2236 +            case 2:
2237 +                currAction = ui->actionProject3;
2238 +                break;
2239 +            case 3:
2240 +                currAction = ui->actionProject4;
2241 +                break;
2242 +            case 4:
2243 +                currAction = ui->actionProject5;
2244 +                break;
2245 +            }
2246 +
2247 +            if(currAction){
2248 +                ui->menuRecent_Projects->setEnabled(true);
2249 +                currAction->setText(*it);
2250 +                currAction->setVisible(true);
2251 +            }
2252 +        }
2253 +    }
2254 +
2255 + }

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)