diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/AboutDialog.html | 16 | ||||
| -rw-r--r-- | src/MainWindow.h | 1 | ||||
| -rw-r--r-- | src/ModuleCache.cc | 25 | ||||
| -rw-r--r-- | src/ProgressWidget.cc | 2 | ||||
| -rw-r--r-- | src/ProgressWidget.ui | 3 | ||||
| -rw-r--r-- | src/expr.cc | 2 | ||||
| -rw-r--r-- | src/mainwin.cc | 82 | ||||
| -rw-r--r-- | src/module.cc | 66 | ||||
| -rw-r--r-- | src/module.h | 19 | ||||
| -rw-r--r-- | src/parsersettings.cc | 13 | 
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;  			}  		} | 
