summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/AboutDialog.html16
-rw-r--r--src/MainWindow.h1
-rw-r--r--src/ModuleCache.cc25
-rw-r--r--src/ProgressWidget.cc2
-rw-r--r--src/ProgressWidget.ui3
-rw-r--r--src/expr.cc2
-rw-r--r--src/mainwin.cc82
-rw-r--r--src/module.cc66
-rw-r--r--src/module.h19
-rw-r--r--src/parsersettings.cc13
10 files changed, 133 insertions, 96 deletions
diff --git a/src/AboutDialog.html b/src/AboutDialog.html
index 005f61f..b5a5d7c 100644
--- a/src/AboutDialog.html
+++ b/src/AboutDialog.html
@@ -7,7 +7,8 @@
make to do your testing. -->
<head>
- <meta name="qrichtext" content="1" />
+ <meta charset="UTF-8"/>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
</head>
@@ -74,18 +75,23 @@ Please visit this link for a copy of the license: <a href="http://www.gnu.org/li
<b>OpenSCAD Github Project members (public)</b>
</p>
-<lu>
+<ul>
<li><a href="https://github.com/kintel">Marius Kintel </a>
<li><a href="http://clifford.at">Clifford Wolf</a>
<li><a href="http://www.github.com/GilesBathgate">Giles Bathgate</a>
<li><a href="https://github.com/brad">Brad Pitcher</a>
<li><a href="https://github.com/donbright">Don Bright</a>
-</lu>
+</ul>
<p>
-<b><a href="http://www.debian.org">Debian</a> maintainer:</b>
- <a href="http://christian.amsuess.com/">chrysn</a>
+<b>Package Maintainers</b>
</p>
+<ul>
+<li><a href="http://www.debian.org">Debian</a> maintainer:</b>
+ <a href="http://christian.amsuess.com/">chrysn</a></lu>
+<li><a href="http://fedoraproject.org/">Fedora</a> maintainer:</b>
+ <a href="http://hroncok.cz/">Miro HronĨok</a></lu>
+</ul>
<p>
<b>Patches</b>
diff --git a/src/MainWindow.h b/src/MainWindow.h
index bd32bdd..1dcffeb 100644
--- a/src/MainWindow.h
+++ b/src/MainWindow.h
@@ -76,7 +76,6 @@ private:
void refreshDocument();
void updateTemporalVariables();
bool fileChangedOnDisk();
- bool includesChanged();
bool compileTopLevelDocument(bool reload);
bool compile(bool reload, bool procevents);
void compileCSG(bool procevents);
diff --git a/src/ModuleCache.cc b/src/ModuleCache.cc
index 505015e..83f7b7d 100644
--- a/src/ModuleCache.cc
+++ b/src/ModuleCache.cc
@@ -30,34 +30,37 @@ ModuleCache *ModuleCache::inst = NULL;
*/
FileModule *ModuleCache::evaluate(const std::string &filename)
{
+ bool shouldCompile = true;
FileModule *lib_mod = NULL;
// Create cache ID
struct stat st;
memset(&st, 0, sizeof(struct stat));
- stat(filename.c_str(), &st);
+ bool valid = (stat(filename.c_str(), &st) == 0);
+ // If file isn't there, just return and let the cache retain the old module
+ if (!valid) return NULL;
+
std::string cache_id = str(boost::format("%x.%x") % st.st_mtime % st.st_size);
// Lookup in cache
- if (this->entries.find(filename) != this->entries.end() &&
- this->entries[filename].cache_id == cache_id) {
-#ifdef DEBUG
-// Causes too much debug output
-// PRINTB("Using cached library: %s (%s)", filename % cache_id);
-#endif
+ if (this->entries.find(filename) != this->entries.end()) {
lib_mod = &(*this->entries[filename].module);
+ if (this->entries[filename].cache_id == cache_id) {
+ shouldCompile = false;
- BOOST_FOREACH(const FileModule::IncludeContainer::value_type &include, lib_mod->includes) {
- if (lib_mod->include_modified(include.second)) {
+ if (lib_mod->includesChanged()) {
lib_mod = NULL;
- break;
+ shouldCompile = true;
}
}
}
+ else {
+ shouldCompile = valid;
+ }
// If cache lookup failed (non-existing or old timestamp), compile module
- if (!lib_mod) {
+ if (shouldCompile) {
#ifdef DEBUG
if (this->entries.find(filename) != this->entries.end()) {
PRINTB("Recompiling cached library: %s (%s)", filename % cache_id);
diff --git a/src/ProgressWidget.cc b/src/ProgressWidget.cc
index ce66405..7aa6a4a 100644
--- a/src/ProgressWidget.cc
+++ b/src/ProgressWidget.cc
@@ -5,7 +5,7 @@ ProgressWidget::ProgressWidget(QWidget *parent)
:QWidget(parent)
{
setupUi(this);
- setRange(0, 100);
+ setRange(0, 1000);
setValue(0);
this->wascanceled = false;
this->starttime.start();
diff --git a/src/ProgressWidget.ui b/src/ProgressWidget.ui
index 895586c..24aefdb 100644
--- a/src/ProgressWidget.ui
+++ b/src/ProgressWidget.ui
@@ -22,6 +22,9 @@
</property>
<item>
<widget class="QProgressBar" name="progressBar">
+ <property name="maximum">
+ <number>1000</number>
+ </property>
<property name="value">
<number>24</number>
</property>
diff --git a/src/expr.cc b/src/expr.cc
index 46d606f..2e069f0 100644
--- a/src/expr.cc
+++ b/src/expr.cc
@@ -69,7 +69,7 @@ public:
expr.recursioncount++;
}
~FuncRecursionGuard() { expr.recursioncount--; }
- bool recursion_detected() const { return (expr.recursioncount > 100); }
+ bool recursion_detected() const { return (expr.recursioncount > 1000); }
private:
const Expression &expr;
};
diff --git a/src/mainwin.cc b/src/mainwin.cc
index ac75269..946bc2a 100644
--- a/src/mainwin.cc
+++ b/src/mainwin.cc
@@ -122,7 +122,7 @@ static char helptitle[] =
#endif
"\nhttp://www.openscad.org\n\n";
static char copyrighttext[] =
- "Copyright (C) 2009-2013 Marius Kintel <marius@kintel.net> and Clifford Wolf <clifford@clifford.at>\n"
+ "Copyright (C) 2009-2013 The OpenSCAD Developers\n"
"\n"
"This program is free software; you can redistribute it and/or modify "
"it under the terms of the GNU General Public License as published by "
@@ -462,12 +462,11 @@ void MainWindow::showProgress()
void MainWindow::report_func(const class AbstractNode*, void *vp, int mark)
{
MainWindow *thisp = static_cast<MainWindow*>(vp);
- int v = (int)((mark*100.0) / progress_report_count);
- int percent = v < 100 ? v : 99;
-
- if (percent > thisp->progresswidget->value()) {
+ int v = (int)((mark*1000.0) / progress_report_count);
+ int permille = v < 1000 ? v : 999;
+ if (permille > thisp->progresswidget->value()) {
QMetaObject::invokeMethod(thisp->progresswidget, "setValue", Qt::QueuedConnection,
- Q_ARG(int, percent));
+ Q_ARG(int, permille));
QApplication::processEvents();
}
@@ -493,12 +492,12 @@ void
MainWindow::openFile(const QString &new_filename)
{
QString actual_filename = new_filename;
+ QFileInfo fi(new_filename);
+ if (fi.suffix().toLower().contains(QRegExp("^(stl|off|dxf)$"))) {
+ actual_filename = QString();
+ }
#ifdef ENABLE_MDI
if (!editor->toPlainText().isEmpty()) {
- QFileInfo fi(new_filename);
- if (fi.suffix().toLower().contains(QRegExp("^(stl|off|dxf)$"))) {
- actual_filename = QString();
- }
new MainWindow(actual_filename);
clearCurrentOutput();
return;
@@ -506,6 +505,7 @@ MainWindow::openFile(const QString &new_filename)
#endif
setFileName(actual_filename);
+ fileChangedOnDisk(); // force cached autoReloadId to update
refreshDocument();
updateRecentFiles();
if (actual_filename.isEmpty()) {
@@ -691,8 +691,7 @@ void MainWindow::compileCSG(bool procevents)
{
assert(this->root_node);
PRINT("Compiling design (CSG Products generation)...");
- if (procevents)
- QApplication::processEvents();
+ if (procevents) QApplication::processEvents();
// Main CSG evaluation
QTime t;
@@ -710,16 +709,16 @@ void MainWindow::compileCSG(bool procevents)
PolySetEvaluator psevaluator(this->tree);
#endif
CSGTermEvaluator csgrenderer(this->tree, &psevaluator);
+ if (procevents) QApplication::processEvents();
this->root_raw_term = csgrenderer.evaluateCSGTerm(*root_node, highlight_terms, background_terms);
if (!root_raw_term) {
PRINT("ERROR: CSG generation failed! (no top level object found)");
- if (procevents)
- QApplication::processEvents();
}
PolySetCache::instance()->print();
#ifdef ENABLE_CGAL
CGALCache::instance()->print();
#endif
+ if (procevents) QApplication::processEvents();
}
catch (const ProgressCancelException &e) {
PRINT("CSG generation cancelled.");
@@ -731,8 +730,7 @@ void MainWindow::compileCSG(bool procevents)
if (root_raw_term) {
PRINT("Compiling design (CSG Products normalization)...");
- if (procevents)
- QApplication::processEvents();
+ if (procevents) QApplication::processEvents();
size_t normalizelimit = 2 * Preferences::inst()->getValue("advanced/openCSGLimit").toUInt();
CSGTermNormalizer normalizer(normalizelimit);
@@ -744,15 +742,13 @@ void MainWindow::compileCSG(bool procevents)
else {
this->root_chain = NULL;
PRINT("WARNING: CSG normalization resulted in an empty tree");
- if (procevents)
- QApplication::processEvents();
+ if (procevents) QApplication::processEvents();
}
if (highlight_terms.size() > 0)
{
PRINTB("Compiling highlights (%d CSG Trees)...", highlight_terms.size());
- if (procevents)
- QApplication::processEvents();
+ if (procevents) QApplication::processEvents();
highlights_chain = new CSGChain();
for (unsigned int i = 0; i < highlight_terms.size(); i++) {
@@ -764,8 +760,7 @@ void MainWindow::compileCSG(bool procevents)
if (background_terms.size() > 0)
{
PRINTB("Compiling background (%d CSG Trees)...", background_terms.size());
- if (procevents)
- QApplication::processEvents();
+ if (procevents) QApplication::processEvents();
background_chain = new CSGChain();
for (unsigned int i = 0; i < background_terms.size(); i++) {
@@ -794,8 +789,7 @@ void MainWindow::compileCSG(bool procevents)
PRINT("CSG generation finished.");
int s = t.elapsed() / 1000;
PRINTB("Total rendering time: %d hours, %d minutes, %d seconds", (s / (60*60)) % ((s / 60) % 60) % (s % 60));
- if (procevents)
- QApplication::processEvents();
+ if (procevents) QApplication::processEvents();
}
}
@@ -973,7 +967,10 @@ void MainWindow::actionShowLibraryFolder()
void MainWindow::actionReload()
{
- if (checkEditorModified()) refreshDocument();
+ if (checkEditorModified()) {
+ fileChangedOnDisk(); // force cached autoReloadId to update
+ refreshDocument();
+ }
}
void MainWindow::hideEditor()
@@ -1027,7 +1024,10 @@ bool MainWindow::fileChangedOnDisk()
if (!this->fileName.isEmpty()) {
struct stat st;
memset(&st, 0, sizeof(struct stat));
- stat(this->fileName.toLocal8Bit(), &st);
+ bool valid = (stat(this->fileName.toLocal8Bit(), &st) == 0);
+ // If file isn't there, just return and use current editor text
+ if (!valid) return false;
+
std::string newid = str(boost::format("%x.%x") % st.st_mtime % st.st_size);
if (newid != this->autoReloadId) {
@@ -1038,16 +1038,6 @@ bool MainWindow::fileChangedOnDisk()
return false;
}
-bool MainWindow::includesChanged()
-{
- if (this->root_module) {
- BOOST_FOREACH(const FileModule::IncludeContainer::value_type &item, this->root_module->includes) {
- if (this->root_module->include_modified(item.second)) return true;
- }
- }
- return false;
-}
-
/*!
If reload is true, does a timestamp check on the document and tries to reload it.
Otherwise, just reparses the current document and any dependencies, updates the
@@ -1059,11 +1049,22 @@ bool MainWindow::compileTopLevelDocument(bool reload)
{
bool shouldcompiletoplevel = !reload;
- if (includesChanged()) shouldcompiletoplevel = true;
-
- if (reload && fileChangedOnDisk() && checkEditorModified()) {
+ if (this->root_module && this->root_module->includesChanged()) {
shouldcompiletoplevel = true;
- refreshDocument();
+ }
+
+ if (reload) {
+ // Refresh file if it has changed on disk
+ if (fileChangedOnDisk() && checkEditorModified()) {
+ shouldcompiletoplevel = true;
+ refreshDocument();
+ }
+ // If the file hasn't changed, we might still need to compile it
+ // if we haven't yet compiled the current text.
+ else if (!editor->isContentModified()) {
+ QString current_doc = editor->toPlainText();
+ if (current_doc != last_compiled_doc) shouldcompiletoplevel = true;
+ }
}
if (shouldcompiletoplevel) {
@@ -1116,7 +1117,6 @@ void MainWindow::autoReloadSet(bool on)
QSettings settings;
settings.setValue("design/autoReload",designActionAutoReload->isChecked());
if (on) {
- autoReloadId = "";
autoReloadTimer->start(200);
} else {
autoReloadTimer->stop();
diff --git a/src/module.cc b/src/module.cc
index cc0f99c..046d0c4 100644
--- a/src/module.cc
+++ b/src/module.cc
@@ -166,7 +166,7 @@ public:
~ModRecursionGuard() {
inst.recursioncount--;
}
- bool recursion_detected() const { return (inst.recursioncount > 100); }
+ bool recursion_detected() const { return (inst.recursioncount > 1000); }
private:
const ModuleInstantiation &inst;
};
@@ -226,6 +226,28 @@ void FileModule::registerInclude(const std::string &localpath,
this->includes[localpath] = inc;
}
+bool FileModule::includesChanged() const
+{
+ BOOST_FOREACH(const FileModule::IncludeContainer::value_type &item, this->includes) {
+ if (include_modified(item.second)) return true;
+ }
+ return false;
+}
+
+bool FileModule::include_modified(const IncludeFile &inc) const
+{
+ struct stat st;
+ memset(&st, 0, sizeof(struct stat));
+
+ fs::path fullpath = find_valid_path(this->path, inc.filename);
+ bool valid = !fullpath.empty() ? (stat(boosty::stringy(fullpath).c_str(), &st) == 0) : false;
+
+ if (valid && !inc.valid) return true; // Detect appearance of file but not removal
+ if (valid && st.st_mtime > inc.mtime) return true;
+
+ return false;
+}
+
/*!
Check if any dependencies have been modified and recompile them.
Returns true if anything was recompiled.
@@ -236,35 +258,49 @@ bool FileModule::handleDependencies()
this->is_handling_dependencies = true;
bool changed = false;
- // Iterating manually since we want to modify the container while iterating
-
// If a lib in usedlibs was previously missing, we need to relocate it
// by searching the applicable paths. We can identify a previously missing module
// as it will have a relative path.
+
+ // Iterating manually since we want to modify the container while iterating
+ std::vector<std::pair<std::string, FileModule*> > modified_modules;
FileModule::ModuleContainer::iterator iter = this->usedlibs.begin();
while (iter != this->usedlibs.end()) {
FileModule::ModuleContainer::iterator curr = iter++;
FileModule *oldmodule = curr->second;
+ bool wasmissing = false;
// Get an absolute filename for the module
std::string filename = curr->first;
if (!boosty::is_absolute(filename)) {
+ wasmissing = true;
fs::path fullpath = find_valid_path(this->path, filename);
if (!fullpath.empty()) filename = boosty::stringy(fullpath);
}
- curr->second = ModuleCache::instance()->evaluate(filename);
- if (curr->second != oldmodule) {
+ FileModule *newmodule = ModuleCache::instance()->evaluate(filename);
+ // Detect appearance but not removal of files
+ if (newmodule && oldmodule != newmodule) {
changed = true;
#ifdef DEBUG
- PRINTB_NOCACHE(" %s: %p", filename % curr->second);
+ PRINTB_NOCACHE(" %s: %p", filename % newmodule);
#endif
}
- if (!curr->second) {
- PRINTB_NOCACHE("WARNING: Failed to compile library '%s'.", filename);
+ if (newmodule) {
+ modified_modules.push_back(std::make_pair(filename, newmodule));
+ this->usedlibs.erase(curr);
+ }
+ else {
+ // Only print warning if we're not part of an automatic reload
+ if (!oldmodule && !wasmissing) {
+ PRINTB_NOCACHE("WARNING: Failed to compile library '%s'.", filename);
+ }
}
}
+ BOOST_FOREACH(const FileModule::ModuleContainer::value_type &mod, modified_modules) {
+ this->usedlibs[mod.first] = mod.second;
+ }
this->is_handling_dependencies = false;
return changed;
@@ -286,17 +322,3 @@ AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiat
return node;
}
-
-bool FileModule::include_modified(IncludeFile inc)
-{
- struct stat st;
- memset(&st, 0, sizeof(struct stat));
-
- fs::path fullpath = find_valid_path(this->path, inc.filename);
- bool valid = !fullpath.empty() ? (stat(boosty::stringy(fullpath).c_str(), &st) == 0) : false;
-
- if (valid != inc.valid) return true;
- if (valid && st.st_mtime > inc.mtime) return true;
-
- return false;
-}
diff --git a/src/module.h b/src/module.h
index 96e5649..e28677a 100644
--- a/src/module.h
+++ b/src/module.h
@@ -78,12 +78,6 @@ public:
LocalScope scope;
};
-struct IncludeFile {
- std::string filename;
- bool valid;
- time_t mtime;
-};
-
// FIXME: A FileModule doesn't have definition arguments, so we shouldn't really
// inherit from a Module
class FileModule : public Module
@@ -95,15 +89,24 @@ public:
void setModulePath(const std::string &path) { this->path = path; }
const std::string &modulePath() const { return this->path; }
void registerInclude(const std::string &localpath, const std::string &fullpath);
+ bool includesChanged() const;
bool handleDependencies();
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx = NULL) const;
+ bool hasIncludes() const { return !this->includes.empty(); }
+ bool usesLibraries() const { return !this->usedlibs.empty(); }
typedef boost::unordered_map<std::string, class FileModule*> ModuleContainer;
ModuleContainer usedlibs;
+private:
+ struct IncludeFile {
+ std::string filename;
+ bool valid;
+ time_t mtime;
+ };
+
+ bool include_modified(const IncludeFile &inc) const;
typedef boost::unordered_map<std::string, struct IncludeFile> IncludeContainer;
IncludeContainer includes;
- bool include_modified(struct IncludeFile inc);
-private:
bool is_handling_dependencies;
std::string path;
};
diff --git a/src/parsersettings.cc b/src/parsersettings.cc
index 8db33a8..ab93b78 100644
--- a/src/parsersettings.cc
+++ b/src/parsersettings.cc
@@ -30,23 +30,24 @@ fs::path search_libs(const fs::path &localpath)
}
// files must be 'ordinary' - they must exist and be non-directories
+// FIXME: We cannot print any output here since these function is called periodically
+// from "Automatic reload and compile"
static bool check_valid(const fs::path &p, const std::vector<std::string> *openfilenames)
{
if (p.empty()) {
- PRINTB("WARNING: File path is blank: %s",p);
+// PRINTB("WARNING: File path is blank: %s",p);
return false;
}
if (!p.has_parent_path()) {
- PRINTB("WARNING: No parent path: %s",p);
+// PRINTB("WARNING: No parent path: %s",p);
return false;
}
if (!fs::exists(p)) {
- PRINTB("WARNING: File not found: %s",p);
- // searched ===
+// PRINTB("WARNING: File not found: %s",p);
return false;
}
if (fs::is_directory(p)) {
- PRINTB("WARNING: %s invalid - points to a directory",p);
+// PRINTB("WARNING: %s invalid - points to a directory",p);
return false;
}
std::string fullname = boosty::stringy(p);
@@ -54,7 +55,7 @@ static bool check_valid(const fs::path &p, const std::vector<std::string> *openf
if (openfilenames) {
BOOST_FOREACH(const std::string &s, *openfilenames) {
if (s == fullname) {
- PRINTB("WARNING: circular include file %s", fullname);
+// PRINTB("WARNING: circular include file %s", fullname);
return false;
}
}
contact: Jan Huwald // Impressum