Commit 2c37320f authored by sumpfralle's avatar sumpfralle

external program locations (inkscape/pstoedit) are now configurable via the GUI


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@584 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 833dd869
......@@ -30,6 +30,7 @@ import pycam.Toolpath.Generator
import pycam.Toolpath
import pycam.Importers
import pycam.Utils.log
import pycam.Utils
from pycam.Geometry.utils import sqrt
from pycam.Gui.OpenGLTools import ModelViewWindowGL
from pycam.Toolpath import Bounds
......@@ -87,6 +88,8 @@ PREFERENCES_DEFAULTS = {
"view_polygon": True,
"simulation_details_level": 3,
"drill_progress_max_fps": 2,
"external_program_inkscape": "",
"external_program_pstoedit": "",
}
""" the listed items will be loaded/saved via the preferences file in the
user's home directory on startup/shutdown"""
......@@ -266,6 +269,8 @@ class ProjectGui:
# Calculate the "minx, ..." settings based on a (potentially) selected
# bounds setting.
def get_absolute_limit(key):
if self.model is None:
return None
bounds = self.settings.get("current_bounds")
if bounds is None:
return getattr(self.model, key)
......@@ -581,6 +586,21 @@ class ProjectGui:
obj = self.gui.get_object(objname)
self._task_property_signals.append((obj,
obj.connect("changed", self._handle_task_setting_change)))
# configure locations of external programs
for auto_control_name, location_control_name, browse_button, key in (
("ExternalProgramInkscapeAuto",
"ExternalProgramInkscapeControl",
"ExternalProgramInkscapeBrowse", "inkscape"),
("ExternalProgramPstoeditAuto",
"ExternalProgramPstoeditControl",
"ExternalProgramPstoeditBrowse", "pstoedit")):
self.gui.get_object(auto_control_name).connect("clicked",
self._locate_external_program, key)
location_control = self.gui.get_object(location_control_name)
self.settings.add_item("external_program_%s" % key,
location_control.get_text, location_control.set_text)
self.gui.get_object(browse_button).connect("clicked",
self._browse_external_program_location, key)
# menu bar
uimanager = gtk.UIManager()
self._accel_group = uimanager.get_accel_group()
......@@ -821,6 +841,23 @@ class ProjectGui:
else:
self.grid_adjustment_selector.set_active(-1)
def _browse_external_program_location(self, widget=None, key=None):
location = self.get_filename_via_dialog(title="Select the executable " \
+ "for '%s'" % key, mode_load=True)
if not location is None:
self.settings.set("external_program_%s" % key, location)
def _locate_external_program(self, widget=None, key=None):
# the button was just activated
location = pycam.Utils.get_external_program_location(key)
if location is None:
log.error("Failed to locate the external program '%s'. " % key \
+ "Please install the program and try again.\nOr maybe" \
+ "you need to specify the location manually.")
else:
# store the new setting
self.settings.set("external_program_%s" % key, location)
@gui_activity_guard
def adjust_bounds(self, widget, axis, change):
......@@ -1169,6 +1206,11 @@ class ProjectGui:
def add_log_message(self, title, message, record=None):
timestamp = datetime.datetime.fromtimestamp(record.created).strftime("%H:%M")
try:
message = message.encode("utf-8")
except UnicodeDecodeError:
# remove all non-ascii characters
message = "".join([char for char in message if ord(char) < 128])
self.log_model.append((timestamp, title, message))
@gui_activity_guard
......@@ -1612,9 +1654,10 @@ class ProjectGui:
continue
value_raw = config.get("DEFAULT", item)
old_value = self.settings.get(item)
if isinstance(old_value, basestring):
value_type = type(PREFERENCES_DEFAULTS[item])
if isinstance(value_type(), basestring):
# keep strings as they are
value = value_raw
value = str(value_raw)
else:
# parse tuples, integers, bools, ...
value = eval(value_raw)
......@@ -1777,10 +1820,16 @@ class ProjectGui:
filename = self.get_filename_via_dialog("Loading model ...",
mode_load=True, type_filter=FILTER_MODEL)
if filename:
# import all external program locations into a dict
program_locations = {}
prefix = "external_program_"
for key in self.settings.get_keys():
if key.startswith(prefix) and self.settings.get(key):
program_locations[key[len(prefix):]] = self.settings.get(key)
file_type, importer = pycam.Importers.detect_file_type(filename)
if file_type and callable(importer):
# TODO: get the "program_locations"
self.load_model(importer(filename, program_locations=None))
self.load_model(importer(filename,
program_locations=program_locations))
self.set_model_filename(filename)
else:
log.error("Failed to detect filetype!")
......
......@@ -113,6 +113,9 @@ class Settings:
result[key] = self.get(key)
return str(result)
def get_keys(self):
return self.items.keys()
class ProcessSettings:
......
......@@ -4712,6 +4712,18 @@ upon interesting bugs and weird results.</property>
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkImage" id="logo">
<property name="visible">True</property>
<property name="ypad">2</property>
<property name="pixbuf">logo_gui.png</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkNotebook" id="notebook1">
<property name="visible">True</property>
......@@ -5384,7 +5396,7 @@ It is significantly faster, but the current release of ODE contains a nasty bug
<object class="GtkTable" id="table11">
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">3</property>
<property name="n_columns">4</property>
<property name="column_spacing">3</property>
<child>
<object class="GtkLinkButton" id="ExternalProgramInkscapeLink">
......@@ -5403,23 +5415,59 @@ It is significantly faster, but the current release of ODE contains a nasty bug
</packing>
</child>
<child>
<object class="GtkFileChooserButton" id="ExternalProgramInkscapeChooser">
<object class="GtkLinkButton" id="ExternalProgramPstoeditLink">
<property name="label" translatable="yes">pstoedit</property>
<property name="visible">True</property>
<property name="title" translatable="yes">Choose location of Inkscape</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">pstoedit is a postscript conversion tool. It can be used to convert 2D SVG files into DXF contour models.</property>
<property name="relief">none</property>
<property name="xalign">0</property>
<property name="uri">http://sourceforge.net/apps/mediawiki/pycam/index.php?title=Requirements#Inkscape</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="ExternalProgramInkscapeAuto">
<property name="label" translatable="yes">auto</property>
<object class="GtkButton" id="ExternalProgramInkscapeAuto">
<property name="label">Detect</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ExternalProgramPstoeditAuto">
<property name="label">Detect</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ExternalProgramInkscapeBrowse">
<property name="label" translatable="yes">Browse</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="left_attach">2</property>
......@@ -5429,17 +5477,15 @@ It is significantly faster, but the current release of ODE contains a nasty bug
</packing>
</child>
<child>
<object class="GtkLinkButton" id="ExternalProgramPstoeditLink">
<property name="label" translatable="yes">pstoedit</property>
<object class="GtkButton" id="ExternalProgramPstoeditBrowse">
<property name="label" translatable="yes">Browse</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">pstoedit is a postscript conversion tool. It can be used to convert 2D SVG files into DXF contour models.</property>
<property name="relief">none</property>
<property name="xalign">0</property>
<property name="uri">http://sourceforge.net/apps/mediawiki/pycam/index.php?title=Requirements#Inkscape</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
......@@ -5447,32 +5493,28 @@ It is significantly faster, but the current release of ODE contains a nasty bug
</packing>
</child>
<child>
<object class="GtkFileChooserButton" id="ExternalProgramPstoeditChooser">
<object class="GtkEntry" id="ExternalProgramInkscapeControl">
<property name="visible">True</property>
<property name="title" translatable="yes">Choose location of pstoedit</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="ExternalProgramPstoeditAuto">
<property name="label" translatable="yes">auto</property>
<object class="GtkEntry" id="ExternalProgramPstoeditControl">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="invisible_char">&#x25CF;</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
......@@ -5504,7 +5546,7 @@ It is significantly faster, but the current release of ODE contains a nasty bug
</child>
</object>
<packing>
<property name="position">1</property>
<property name="position">3</property>
</packing>
</child>
<child internal-child="action_area">
......
......@@ -22,6 +22,40 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
__all__ = [ "iterators", "polynomials", "ProgressCounter"]
import os
# this is imported below on demand
#import win32.com
def get_external_program_location(key):
extensions = ["", ".exe"]
potential_names = ["%s%s" % (key, ext) for ext in extensions]
windows_program_directories = {'inkscape': ['Inkscape'],
'pstoedit': ['pstoedit']}
# go through the PATH environment variable
if "PATH" in os.environ:
path_env = os.environ["PATH"]
for one_dir in path_env.split(os.pathsep):
for basename in potential_names:
location = os.path.join(one_dir, basename)
if os.path.isfile(location):
return location
# do a manual scan in the programs directory (only for windows)
try:
from win32com.shell import shellcon, shell
program_dir = shell.SHGetFolderPath(0, shellcon.CSIDL_PROGRAM_FILES, 0, 0)
except ImportError:
# no other options for non-windows systems
return None
# scan the program directory
for subdir in windows_program_directories[key]:
for basename in potential_names:
location = os.path.join(program_dir, sub_dir, basename)
if os.path.isfile(location):
return location
# nothing found
return None
class ProgressCounter:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment