1 /*
2 Copyright (C) 2010 Andres Cabrera
3 mantaraya36@gmail.com
4
5 This file is part of CsoundQt.
6
7 CsoundQt is free software; you can redistribute it
8 and/or modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 CsoundQt is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with Csound; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA
21 */
22
23 #include <QCheckBox>
24 #include <QGroupBox>
25 #include <QLabel>
26 #include <QLineEdit>
27 #include <QRadioButton>
28 #include <QVBoxLayout>
29 #include <QGridLayout>
30 #include <QListWidget>
31 #include <QDir>
32 #include <QFile>
33 #include <QMessageBox>
34 #include <QDebug>
35 #include <QProcess>
36
37
38 #include "appwizard.h"
39 #include "appdetailspage.h"
40 #include "additionalfilespage.h"
41 #include "pluginspage.h"
42
43
AppWizard(QWidget * parent,QString opcodeDir,QString csd,QString sdkDir)44 AppWizard::AppWizard(QWidget *parent,QString opcodeDir,
45 QString csd, QString sdkDir) :
46 QWizard(parent), m_csd(csd), m_sdkDir(sdkDir)
47 {
48 int appPage = addPage(new AppDetailsPage(this));
49
50 setField("opcodeDir", opcodeDir);
51 #ifndef Q_OS_MAC
52 // No plugins page for Mac for now
53 m_pluginsPage = addPage(new PluginsPage(this, field("opcodeDir").toString()));
54 // static_cast<PluginsPage *>(this->page(m_pluginsPage))->
55 connect(static_cast<AppDetailsPage *>(this->page(appPage)), SIGNAL(opcodeDirChangedSignal()),
56 static_cast<PluginsPage *>(this->page(m_pluginsPage)), SLOT(updateOpcodeDir()));
57 connect(static_cast<AppDetailsPage *>(this->page(appPage)), SIGNAL(libDirChangedSignal()),
58 static_cast<PluginsPage *>(this->page(m_pluginsPage)), SLOT(updateOpcodeDir()));
59 #endif
60 m_additionalsPage = addPage(new AdditionalFilesPage(this));
61
62 m_dataFiles = processDataFiles();
63 static_cast<AdditionalFilesPage *>(this->page(m_additionalsPage))->setFiles(m_dataFiles);
64 //
65 // setPixmap(QWizard::BannerPixmap, QPixmap(":/images/banner.png"));
66 // setPixmap(QWizard::BackgroundPixmap, QPixmap(":/images/background.png"));
67 setWindowTitle(tr("Standalone Application Generator"));
68 }
69
makeApp()70 void AppWizard::makeApp()
71 {
72 QString appName = field("appName").toString();
73 QString targetDir = field("targetDir").toString();
74 bool useSdk = field("useSdk").toInt() == 1;
75
76 // bool autorun = field("autorun").toBool();
77 // int runMode = field("runMode").toInt();
78 // bool saveState = field("saveState").toBool();
79 // bool newParser = field("newParser").toBool();
80
81 QString author = field("author").toString();
82 QString version = field("version").toString();
83 QString email = field("email").toString();
84 QString website = field("website").toString();
85 QString instructions = field("instructions").toString();
86
87 bool customPaths = field("customPaths").toBool();
88 QString libDir, opcodeDir, qtLibsDir;
89 if (customPaths) {
90 libDir = field("libDir").toString();
91 opcodeDir = field("opcodeDir").toString();
92 qtLibsDir = field("qtLibsDir").toString();
93 } else {
94 libDir = "";
95 opcodeDir = "";
96 qtLibsDir = "";
97 }
98
99 #ifdef Q_OS_MAC
100 QStringList plugins;
101 #else
102 QStringList plugins = this->page(m_pluginsPage)->property("plugins").toStringList();
103 #endif
104 QStringList dataFiles = this->page(m_additionalsPage)->property("dataFiles").toStringList();
105
106 if (!QFile::exists(targetDir)) {
107 QMessageBox::critical(this, tr("CsoundQt App Creator"),
108 tr("The destination directory does not exist!\n"
109 "Aborting."));
110 return;
111 }
112
113 qDebug() << targetDir;
114 if (useSdk) {
115 createLinuxApp(appName, targetDir, dataFiles, plugins, m_sdkDir,
116 "", "", "");
117 // TODO create two Mac Apps (one for 32 bit plaforms to support PPC)
118 createMacApp(appName, targetDir, dataFiles, plugins, m_sdkDir,
119 "", "", "");
120 createWinApp(appName, targetDir, dataFiles, plugins, m_sdkDir,
121 "", "", "");
122 } else {
123 #ifdef USE_DOUBLE
124 #ifdef Q_OS_LINUX
125 createLinuxApp(appName, targetDir, dataFiles, plugins, "",
126 libDir, opcodeDir, qtLibsDir);
127 #endif
128 #ifdef Q_OS_MAC
129 createMacApp(appName, targetDir, dataFiles, plugins, "",
130 libDir, opcodeDir, qtLibsDir);
131 #endif
132 #ifdef Q_OS_WIN32
133 createWinApp(appName, targetDir, dataFiles, plugins, "",
134 libDir, opcodeDir, qtLibsDir);
135 #endif
136 #else // If not doubles version, can't build for local platform
137 QMessageBox::critical(this, tr("Can't build"),
138 tr("Can't build for local platform for single presicion. Aborted."));
139 return;
140 #endif
141 }
142 QMessageBox::information(this, tr("Done"), tr("App Creation finished!"));
143 }
144
processDataFiles()145 QStringList AppWizard::processDataFiles()
146 {
147 QFile csdFile(m_csd);
148 if (!csdFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
149 return QStringList();
150 }
151 QStringList list;
152 QTextStream in(&csdFile);
153 while (!in.atEnd()) {
154 QString line = in.readLine();
155 if (line.count("\"") == 2 && !line.contains("invalue") && !line.contains("outvalue")
156 && !line.contains("chnget") && !line.contains("chnset") ) {
157 int startIndex = line.indexOf("\"");
158 if ((line.contains(";") && (line.indexOf(";") > startIndex)) ||
159 !line.contains(";")) { // Quotes are not part of a comment
160 if (!line.contains("outvalue") && !line.contains("invalue") &&
161 !line.contains("if") && !line.contains("=") &&
162 !line.contains("elseif") && !line.contains("=") ) { // exclude opcodes which use strings which are not filenames
163 int endIndex = line.lastIndexOf("\"");
164 QString dataName = line.mid(startIndex + 1, endIndex-startIndex - 1);
165 QString newDataName = dataName;
166 #ifdef Q_OS_WIN32
167 if (newDataName.indexOf(QRegExp("\\w\\:")) == 0) { // Absolute path
168 #else
169 if (newDataName.startsWith("/")) { // Absolute path
170 #endif
171 newDataName = "data/" + newDataName.right(newDataName.lastIndexOf("/") + 1);
172 }
173 else {
174 newDataName += "data/";
175 }
176 if (QFile::exists(m_csd.left(m_csd.lastIndexOf(QDir::separator()) + 1) + dataName)
177 || QFile::exists(m_csd)) {
178 list << dataName;
179 line.replace(dataName,newDataName);
180 }
181 }
182 }
183 }
184 m_fullText += line + "\n";
185 if (line.trimmed().startsWith("</CsoundSynthesizer>")) {
186 break;
187 }
188 }
189 return list;
190 }
191
192 void AppWizard::copyFolder(QString sourceFolder, QString destFolder)
193 {
194 QDir sourceDir(sourceFolder);
195 if(!sourceDir.exists()) {
196 qDebug() << "source dir does not exist";
197 return;
198 }
199 QDir destDir(destFolder);
200 if(!destDir.exists()) {
201 destDir.mkdir(destFolder);
202 }
203 QStringList files = sourceDir.entryList();
204 for(int i = 0; i< files.count(); i++) {
205 QString srcName = sourceFolder + QDir::separator() + files[i];
206 QString destName = destFolder + QDir::separator() + files[i];
207 QString symLinkTarget = QFile::symLinkTarget(srcName);
208 if (symLinkTarget.isEmpty()) {
209 QFile::copy(srcName, destName);
210 } else {
211 QFile::link(symLinkTarget, destName);
212 }
213 }
214 files.clear();
215 files = sourceDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
216 for(int i = 0; i< files.count(); i++) {
217 QString srcName = sourceFolder + QDir::separator() + files[i];
218 QString destName = destFolder + QDir::separator() + files[i];
219 QString symLinkTarget = QFile::symLinkTarget(srcName);
220 if (symLinkTarget.isEmpty()) {
221 copyFolder(srcName, destName);
222 } else {
223 QFile::link(symLinkTarget, destName);
224 }
225 }
226 }
227
228
229 void AppWizard::createWinApp(QString appName, QString appDir, QStringList dataFiles,
230 QStringList plugins, QString sdkDir, QString libDir,
231 QString opcodeDir, QString qtLibsDir)
232 {
233 (void) appName;
234 (void) appDir;
235 (void) dataFiles;
236 (void) plugins;
237 (void) sdkDir;
238 (void) libDir;
239 (void) opcodeDir;
240 (void) qtLibsDir;
241 // QDir dir(appDir);
242 // if (dir.mkdir(appName)) {
243 // dir.cd(appName);
244 // dir.mkdir("lib");
245 // dir.mkdir("data");
246 // dir.cd("data");
247 // QMessageBox::critical(this, tr("CsoundQt App Creator"),
248 // tr("Plugins:") + dataFiles.join("\n"));
249 // foreach(QString file, dataFiles) {
250 // QString destName = dir.absolutePath() + QDir::separator() + file.mid(file.lastIndexOf(QDir::separator()) + 1);
251 // QFile::copy(file, destName);
252 // qDebug() << destName;
253 // }
254 // dir.cd("../lib");
255 // foreach(QString file, plugins) {
256 // QString destName = dir.absolutePath() + QDir::separator() + file.mid(file.lastIndexOf(QDir::separator()) + 1);
257 // QFile::copy(file, destName);
258 // qDebug() << destName;
259 // }
260 // }
261 // else {
262 // QMessageBox::critical(this, tr("CsoundQt App Creator"),
263 // tr("Error creating app directory."));
264 // }
265 // }
266 }
267
268 void AppWizard::createMacApp(QString appName, QString appDir, QStringList dataFiles,
269 QStringList plugins, QString sdkDir, QString libDir,
270 QString opcodeDir, QString qtLibsDir)
271 {
272 (void) appName;
273 (void) appDir;
274 (void) dataFiles;
275 (void) plugins;
276 (void) sdkDir;
277 (void) libDir;
278 (void) opcodeDir;
279 (void) qtLibsDir;
280 qDebug() ;
281 QDir dir(appDir);
282 QList<QPair<QString, QString> > copyList;
283 if (dir.exists(appName + QDir::separator() + "osx")) {
284 int ret = QProcess::execute("rm -fR " + dir.absolutePath() + QDir::separator() + appName + QDir::separator() + "osx");
285 qDebug() << "deleted directory";
286 if (ret != 0) {
287 QMessageBox::critical(this, tr("Error"), tr("Could not delete old application directory! Aborted."));
288 }
289 }
290 if (dir.mkpath(appName + QDir::separator() + "osx")) {
291 dir.cd(appName + QDir::separator() + "osx");
292 // Copy csd and binaries
293 if (sdkDir.isEmpty()) {
294 copyList << QPair<QString, QString>(QCoreApplication::applicationDirPath() + QDir::separator() + "../Resources/QuteApp_d.app",
295 dir.absolutePath() + QDir::separator() + appName + ".app");
296 } else {
297 copyList << QPair<QString, QString>(sdkDir + QDir::separator() + "osx/QuteApp_d.app",
298 dir.absolutePath() + QDir::separator() + appName + ".app");
299 }
300 // Data files
301 copyList << QPair<QString, QString>
302 (m_csd,
303 dir.absolutePath() + QDir::separator() + appName + ".app" + QDir::separator() + "Contents/Resources" + QDir::separator() + "quteapp.csd");
304
305 foreach(QString file, dataFiles) {
306 QString destName = dir.absolutePath() + QDir::separator() + appName + ".app" + QDir::separator() + "Contents/Resources" + QDir::separator() + file.mid(file.lastIndexOf(QDir::separator()) + 1);
307 if (file.startsWith("/")) { // Absolute path
308 copyList << QPair<QString, QString>(file, destName);
309 }
310 else { // Relative path
311 copyList << QPair<QString, QString>(m_csd.left(m_csd.lastIndexOf("/")), destName);
312 }
313 }
314 // No need to copy Qt libraries as they should already be deployed in the QuteApp
315 // Copy lib files and plugins only if libDir is not given
316 if (!libDir.isEmpty()) {
317 QStringList libFiles;
318 libFiles << "LibCsound64.framework";
319 libFiles << "libportaudio.so" << "libportmidi.so";
320 QStringList defaultLibDirs;
321 defaultLibDirs << "/Library/Frameworks" << "/usr/lib" << "/usr/local/lib";
322 QStringList libSearchDirs;
323 libSearchDirs << libDir << defaultLibDirs;
324 //FIXME this is not really working yet... You need to use the frameworks and libs inside the QuteApp template bundle.
325 qDebug() << "Error! libDir not implemented!";
326 dir.cd("../Frameworks");
327 foreach(QString file, libFiles) {
328 QString destName = dir.absolutePath() + QDir::separator() + file.mid(file.lastIndexOf(QDir::separator()) + 1);
329 for (int i = 0 ; i < libSearchDirs.size(); i++) {
330 QString libName = libSearchDirs[i] + QDir::separator() + file;
331 if (QFile::exists(libName)) {
332 copyList << QPair<QString, QString>(libName,destName);
333 break;
334 }
335 }
336 }
337 }
338 if (!opcodeDir.isEmpty()) {
339 foreach(QString file, plugins) {
340 QString destName = dir.absolutePath() + QDir::separator() + file.mid(file.lastIndexOf(QDir::separator()) + 1);
341 copyList << QPair<QString, QString>(opcodeDir + QDir::separator() + file, destName);
342 }
343 }
344 QList<QPair<QString,QString> >::const_iterator i;
345 for (i = copyList.constBegin(); i != copyList.constEnd(); ++i) {
346 QFileInfo finfo((*i).first);
347 if (finfo.isDir()) {
348 copyFolder((*i).first, (*i).second);
349 qDebug() << "dir copied:" << (*i).first;
350 } else {
351 if (QFile::copy((*i).first, (*i).second)) {
352 qDebug() << "copied:" << (*i).first;
353 } else {
354 qDebug() << "error copying: " << (*i).first << (*i).second;
355 }
356 }
357 }
358
359 dir.cdUp();
360 QFile f3(dir.absolutePath() + QDir::separator() + "quteapp.csd");
361 f3.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner
362 | QFile::ReadUser | QFile::WriteUser | QFile::ExeUser
363 | QFile::ReadOther | QFile::WriteOther | QFile::ExeOther);
364 }
365 else {
366 QMessageBox::critical(this, tr("CsoundQt App Creator"),
367 tr("Error creating app directory."));
368 }
369 }
370
371 void AppWizard::createLinuxApp(QString appName, QString appDir, QStringList dataFiles,
372 QStringList plugins, QString sdkDir, QString libDir,
373 QString opcodeDir, QString qtLibsDir)
374 {
375 qDebug() ;
376 QDir dir(appDir);
377 QList<QPair<QString, QString> > copyList;
378 if (dir.exists(appName + QDir::separator() + "linux")) {
379 int ret = QProcess::execute("rm -fR " + dir.absolutePath() + QDir::separator() + appName + QDir::separator() + "linux");
380 qDebug() << "Deleted directory";
381 if (ret != 0) {
382 QMessageBox::critical(this, tr("Error"), tr("Could not delete old application directory! Aborted."));
383 }
384 }
385 if (dir.mkpath(appName + QDir::separator() + "linux")) {
386 dir.cd(appName + QDir::separator() + "linux");
387 // Create directories
388 dir.mkdir("lib");
389 dir.mkdir("data");
390 // Copy csd and binaries
391 if (sdkDir.isEmpty()) {
392 copyList << QPair<QString, QString>(":/res/linux/QuteApp_d",
393 dir.absolutePath() + QDir::separator() +"lib/QuteApp");
394 copyList << QPair<QString, QString>(":/res/linux/launch.sh",
395 dir.absolutePath() + QDir::separator() + appName + ".sh");
396 } else {
397 copyList << QPair<QString, QString>(sdkDir + QDir::separator() + "linux/lib/QuteApp_d",
398 dir.absolutePath() + QDir::separator() +"lib/QuteApp");
399 copyList << QPair<QString, QString>(sdkDir + QDir::separator() + "linux/lib/launch.sh",
400 dir.absolutePath() + QDir::separator() + appName + ".sh");
401 }
402 // Data files
403 dir.cd("data");
404 copyList << QPair<QString, QString>(m_csd,
405 dir.absolutePath() + QDir::separator() + "quteapp.csd");
406
407 foreach(QString file, dataFiles) {
408 QString destName = dir.absolutePath() + QDir::separator() + file.mid(file.lastIndexOf(QDir::separator()) + 1);
409 if (file.startsWith("/")) { // Absolute path
410 copyList << QPair<QString, QString>(file, destName);
411 }
412 else { // Relative path
413 copyList << QPair<QString, QString>(m_csd.left(m_csd.lastIndexOf("/")), destName);
414 }
415 }
416 // Copy lib files and plugins
417 QStringList libFiles;
418 libFiles << "libcsound64.so" << "libcsound64.so.5.2";
419 libFiles << "libportaudio.so" << "libportmidi.so";
420 QStringList defaultLibDirs;
421 defaultLibDirs << "/usr/lib" << "/usr/local/lib";
422 QStringList libSearchDirs;
423 if (sdkDir.isEmpty()) { // If sdk dir is not given, it means that local installation is used
424 libSearchDirs << defaultLibDirs;
425 } else {
426 libSearchDirs << libDir;
427 }
428
429 dir.cd("../lib");
430 foreach(QString file, libFiles) {
431 QString destName = dir.absolutePath() + QDir::separator() + file.mid(file.lastIndexOf(QDir::separator()) + 1);
432 for (int i = 0 ; i < libSearchDirs.size(); i++) {
433 QString libName = libSearchDirs[i] + QDir::separator() + file;
434 if (QFile::exists(libName)) {
435 copyList << QPair<QString, QString>(libName,destName);
436 break;
437 }
438 }
439 }
440 // Qt Libs
441 QStringList qtLibFiles;
442 qtLibFiles << "libQtCore.4.so" << "libQtGui.4.so" << "libQtXml.4.so";
443 QStringList defaultQtLibDirs;
444 defaultQtLibDirs<< "/usr/lib" << "/usr/local/lib";
445 QStringList qtLibSearchDirs;
446 if (qtLibsDir.isEmpty()) {
447 qtLibSearchDirs << defaultQtLibDirs;
448 } else {
449 qtLibSearchDirs << qtLibsDir;
450 }
451 foreach(QString file, qtLibFiles) {
452 QString destName = dir.absolutePath() + QDir::separator() + file.mid(file.lastIndexOf(QDir::separator()) + 1);
453 for (int i = 0 ; i < qtLibSearchDirs.size(); i++) {
454 QString libName = qtLibSearchDirs[i] + QDir::separator() + file;
455 if (QFile::exists(libName)) {
456 copyList << QPair<QString, QString>(libName,destName);
457 break;
458 }
459 }
460 }
461 foreach(QString file, plugins) {
462 QString destName = dir.absolutePath() + QDir::separator() + file.mid(file.lastIndexOf(QDir::separator()) + 1);
463 copyList << QPair<QString, QString>(opcodeDir + QDir::separator() + file, destName);
464 }
465 QList<QPair<QString,QString> >::const_iterator i;
466 for (i = copyList.constBegin(); i != copyList.constEnd(); ++i) {
467 if (QFile::copy((*i).first, (*i).second)) {
468 qDebug() << "copied:" << (*i).first;
469 } else {
470 qDebug() << "error copying: " << (*i).first << (*i).second;
471 }
472 }
473 dir.cdUp();
474 QFile f(dir.absolutePath() + QDir::separator() +"lib/QuteApp");
475 f.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner
476 | QFile::ReadUser | QFile::WriteUser | QFile::ExeUser
477 | QFile::ReadOther | QFile::WriteOther | QFile::ExeOther);
478 QFile f2(dir.absolutePath() + QDir::separator() + appName + ".sh");
479 f2.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner
480 | QFile::ReadUser | QFile::WriteUser | QFile::ExeUser
481 | QFile::ReadOther | QFile::WriteOther | QFile::ExeOther);
482 QFile f3(dir.absolutePath() + QDir::separator() + "quteapp.csd");
483 f3.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner
484 | QFile::ReadUser | QFile::WriteUser | QFile::ExeUser
485 | QFile::ReadOther | QFile::WriteOther | QFile::ExeOther);
486 }
487 else {
488 QMessageBox::critical(this, tr("CsoundQt App Creator"),
489 tr("Error creating app directory."));
490 }
491 }
492
493 void AppWizard::getLinuxLibDeps(QString libname)
494 {
495 (void) libname;
496 QProcess ldd;
497 // ldd.start("ldd", QStringList() << "-c");
498 // if (!ldd.waitForStarted())
499 // return false;
500 // ldd.write("Qt rocks!");
501 // ldd.closeWriteChannel();
502 // if (!ldd.waitForFinished())
503 // return false;
504 // QByteArray result = ldd.readAll();
505 }
506