Initial implementation of console.
This commit is contained in:
239
FlatCAMApp.py
239
FlatCAMApp.py
@@ -8,6 +8,7 @@ import simplejson as json
|
||||
import re
|
||||
import webbrowser
|
||||
import os
|
||||
import Tkinter
|
||||
|
||||
from PyQt4 import QtCore
|
||||
|
||||
@@ -22,6 +23,8 @@ from FlatCAMGUI import *
|
||||
from FlatCAMCommon import LoudDict
|
||||
from FlatCAMTool import *
|
||||
|
||||
from FlatCAMShell import FCShell
|
||||
|
||||
|
||||
########################################
|
||||
## App ##
|
||||
@@ -251,7 +254,7 @@ class App(QtCore.QObject):
|
||||
|
||||
#### Check for updates ####
|
||||
# Separate thread (Not worker)
|
||||
self.version = 6
|
||||
self.version = 7
|
||||
App.log.info("Checking for updates in backgroud (this is version %s)." % str(self.version))
|
||||
|
||||
self.worker2 = Worker(self, name="worker2")
|
||||
@@ -293,6 +296,7 @@ class App(QtCore.QObject):
|
||||
self.ui.menuviewdisableall.triggered.connect(self.disable_plots)
|
||||
self.ui.menuviewdisableother.triggered.connect(lambda: self.disable_plots(except_current=True))
|
||||
self.ui.menuviewenable.triggered.connect(self.enable_all_plots)
|
||||
self.ui.menutoolshell.triggered.connect(lambda: self.shell.show())
|
||||
self.ui.menuhelp_about.triggered.connect(self.on_about)
|
||||
self.ui.menuhelp_manual.triggered.connect(lambda: webbrowser.open(self.app_url))
|
||||
# Toolbar
|
||||
@@ -302,6 +306,7 @@ class App(QtCore.QObject):
|
||||
self.ui.clear_plot_btn.triggered.connect(self.plotcanvas.clear)
|
||||
self.ui.replot_btn.triggered.connect(self.on_toolbar_replot)
|
||||
self.ui.delete_btn.triggered.connect(self.on_delete)
|
||||
self.ui.shell_btn.triggered.connect(lambda: self.shell.show())
|
||||
# Object list
|
||||
self.collection.view.activated.connect(self.on_row_activated)
|
||||
# Options
|
||||
@@ -324,6 +329,20 @@ class App(QtCore.QObject):
|
||||
self.measeurement_tool = Measurement(self)
|
||||
self.measeurement_tool.install()
|
||||
|
||||
#############
|
||||
### Shell ###
|
||||
#############
|
||||
# TODO: Move this to its own class
|
||||
self.shell = FCShell(self)
|
||||
self.shell.setWindowIcon(self.ui.app_icon)
|
||||
self.shell.setWindowTitle("FlatCAM Shell")
|
||||
self.shell.show()
|
||||
self.shell.resize(550, 300)
|
||||
self.shell.append_output("FlatCAM Alpha 7\n(c) 2014 Juan Pablo Caram\n\n")
|
||||
self.shell.append_output("Type help to get started.\n\n")
|
||||
self.tcl = Tkinter.Tcl()
|
||||
self.setup_shell()
|
||||
|
||||
App.log.debug("END of constructor. Releasing control.")
|
||||
|
||||
def defaults_read_form(self):
|
||||
@@ -368,6 +387,110 @@ class App(QtCore.QObject):
|
||||
# Send to worker
|
||||
self.worker_task.emit({'fcn': worker_task, 'params': [self]})
|
||||
|
||||
def execCommand(self, text):
|
||||
"""
|
||||
Hadles input from the shell.
|
||||
|
||||
:param text: Input command
|
||||
:return: None
|
||||
"""
|
||||
text = str(text)
|
||||
|
||||
try:
|
||||
result = self.tcl.eval(str(text))
|
||||
self.shell.append_output(result + '\n')
|
||||
except Tkinter.TclError, e:
|
||||
self.shell.append_error('ERROR: ' + str(e) + '\n')
|
||||
raise
|
||||
return
|
||||
|
||||
def shhelp(p=None):
|
||||
if not p:
|
||||
return "Available commands:\n" + '\n'.join([' ' + cmd for cmd in commands])
|
||||
|
||||
if p not in commands:
|
||||
return "Unknown command: %s" % p
|
||||
|
||||
return commands[p]["help"]
|
||||
|
||||
|
||||
commands = {
|
||||
"open_gerber": {
|
||||
"fcn": self.open_gerber,
|
||||
"params": 1,
|
||||
"converters": [lambda x: x],
|
||||
"retfcn": lambda x: None,
|
||||
"help": "Opens a Gerber file.\n> open_gerber <filename>\n filename: Path to file to open."
|
||||
},
|
||||
"open_excellon": {
|
||||
"fcn": self.open_excellon,
|
||||
"params": 1,
|
||||
"converters": [lambda x: x],
|
||||
"retfcn": lambda x: None,
|
||||
"help": "Opens an Excellon file.\n> open_excellon <filename>\n filename: Path to file to open."
|
||||
},
|
||||
"open_gcode": {
|
||||
"fcn": self.open_gcode,
|
||||
"params": 1,
|
||||
"converters": [lambda x: x],
|
||||
"retfcn": lambda x: None,
|
||||
"help": "Opens an G-Code file.\n> open_gcode <filename>\n filename: Path to file to open."
|
||||
},
|
||||
"open_project": {
|
||||
"fcn": self.open_project,
|
||||
"params": 1,
|
||||
"converters": [lambda x: x],
|
||||
"retfcn": lambda x: None,
|
||||
"help": "Opens a FlatCAM project.\n> open_project <filename>\n filename: Path to file to open."
|
||||
},
|
||||
"save_project": {
|
||||
"fcn": self.save_project,
|
||||
"params": 1,
|
||||
"converters": [lambda x: x],
|
||||
"retfcn": lambda x: None,
|
||||
"help": "Saves the FlatCAM project to file.\n> save_project <filename>\n filename: Path to file to save."
|
||||
},
|
||||
"help": {
|
||||
"fcn": shhelp,
|
||||
"params": [0, 1],
|
||||
"converters": [lambda x: x],
|
||||
"retfcn": lambda x: x,
|
||||
"help": "Shows list of commands."
|
||||
}
|
||||
}
|
||||
|
||||
parts = re.findall(r'([\w\\:\.]+|".*?")+', text)
|
||||
parts = [p.replace('\n', '').replace('"', '') for p in parts]
|
||||
self.log.debug(parts)
|
||||
try:
|
||||
if parts[0] not in commands:
|
||||
self.shell.append_error("Unknown command\n")
|
||||
return
|
||||
|
||||
#import inspect
|
||||
#inspect.getargspec(someMethod)
|
||||
if (type(commands[parts[0]]["params"]) is not list and len(parts)-1 != commands[parts[0]]["params"]) or \
|
||||
(type(commands[parts[0]]["params"]) is list and len(parts)-1 not in commands[parts[0]]["params"]):
|
||||
self.shell.append_error(
|
||||
"Command %s takes %d arguments. %d given.\n" %
|
||||
(parts[0], commands[parts[0]]["params"], len(parts)-1)
|
||||
)
|
||||
return
|
||||
|
||||
cmdfcn = commands[parts[0]]["fcn"]
|
||||
cmdconv = commands[parts[0]]["converters"]
|
||||
if len(parts)-1 > 0:
|
||||
retval = cmdfcn(*[cmdconv[i](parts[i+1]) for i in range(len(parts)-1)])
|
||||
else:
|
||||
retval = cmdfcn()
|
||||
retfcn = commands[parts[0]]["retfcn"]
|
||||
if retval and retfcn(retval):
|
||||
self.shell.append_output(retfcn(retval) + "\n")
|
||||
|
||||
except:
|
||||
self.shell.append_error(''.join(traceback.format_exc()))
|
||||
#self.shell.append_error("?\n")
|
||||
|
||||
def info(self, text):
|
||||
self.ui.info_label.setText(QtCore.QString(text))
|
||||
|
||||
@@ -540,7 +663,7 @@ class App(QtCore.QObject):
|
||||
|
||||
title = QtGui.QLabel(
|
||||
"<font size=8><B>FlatCAM</B></font><BR>"
|
||||
"Version Alpha 6 (2014/09)<BR>"
|
||||
"Version Alpha 7 (2014/10)<BR>"
|
||||
"<BR>"
|
||||
"2D Post-processing for Manufacturing specialized in<BR>"
|
||||
"Printed Circuit Boards<BR>"
|
||||
@@ -1379,6 +1502,114 @@ class App(QtCore.QObject):
|
||||
def set_progress_bar(self, percentage, text=""):
|
||||
self.ui.progress_bar.setValue(int(percentage))
|
||||
|
||||
def setup_shell(self):
|
||||
self.log.debug("setup_shell()")
|
||||
|
||||
def shelp(p=None):
|
||||
if not p:
|
||||
return "Available commands:\n" + '\n'.join([' ' + cmd for cmd in commands]) + \
|
||||
"\n\nType help <command_name> for usage.\n Example: help open_gerber"
|
||||
|
||||
if p not in commands:
|
||||
return "Unknown command: %s" % p
|
||||
|
||||
return commands[p]["help"]
|
||||
|
||||
def options(name):
|
||||
ops = self.collection.get_by_name(str(name)).options
|
||||
return '\n'.join(["%s: %s" % (o, ops[o]) for o in ops])
|
||||
|
||||
def isolate(name, dia=None, passes=None, overlap=None):
|
||||
dia = float(dia) if dia is not None else None
|
||||
passes = int(passes) if passes is not None else None
|
||||
overlap = float(overlap) if overlap is not None else None
|
||||
self.collection.get_by_name(str(name)).isolate(dia, passes, overlap)
|
||||
|
||||
commands = {
|
||||
'help': {
|
||||
'fcn': shelp,
|
||||
'help': "Shows list of commands."
|
||||
},
|
||||
'open_gerber': {
|
||||
'fcn': self.open_gerber,
|
||||
'help': "Opens a Gerber file.\n> open_gerber <filename>\n filename: Path to file to open."
|
||||
},
|
||||
'open_excellon': {
|
||||
'fcn': self.open_excellon,
|
||||
'help': "Opens an Excellon file.\n> open_excellon <filename>\n filename: Path to file to open."
|
||||
},
|
||||
'open_gcode': {
|
||||
'fcn': self.open_gcode,
|
||||
'help': "Opens an G-Code file.\n> open_gcode <filename>\n filename: Path to file to open."
|
||||
},
|
||||
'open_project': {
|
||||
'fcn': self.open_project,
|
||||
"help": "Opens a FlatCAM project.\n> open_project <filename>\n filename: Path to file to open."
|
||||
},
|
||||
'save_project': {
|
||||
'fcn': self.save_project,
|
||||
'help': "Saves the FlatCAM project to file.\n> save_project <filename>\n filename: Path to file to save."
|
||||
},
|
||||
'set_active': {
|
||||
'fcn': self.collection.set_active,
|
||||
'help': "Sets a FlatCAM object as active.\n > set_active <name>\n name: Name of the object."
|
||||
},
|
||||
'get_names': {
|
||||
'fcn': lambda: '\n'.join(self.collection.get_names()),
|
||||
'help': "Lists the names of objects in the project.\n > get_names"
|
||||
},
|
||||
'new': {
|
||||
'fcn': self.on_file_new,
|
||||
'help': "Starts a new project. Clears objects from memory.\n > new"
|
||||
},
|
||||
'options': {
|
||||
'fcn': options,
|
||||
'help': "Shows the settings for an object.\n > options <name>\n name: Object name."
|
||||
},
|
||||
'isolate': {
|
||||
'fcn': isolate,
|
||||
'help': "Creates isolation routing geometry for the given Gerber.\n" +
|
||||
"> isolate <name> [dia [passes [overlap]]]\n" +
|
||||
" name: Name if the object\n"
|
||||
" dia: Tool diameter\n passes: # of tool width\n" +
|
||||
" overlap: Fraction of tool diameter to overlap passes"
|
||||
},
|
||||
'scale': {
|
||||
'fcn': lambda name, factor: self.collection.get_by_name(str(name)).scale(float(factor)),
|
||||
'help': "Resizes the object by a factor.\n" +
|
||||
"> scale <name> <factor>\n" +
|
||||
" name: Name of the object\n factor: Fraction by which to scale"
|
||||
},
|
||||
'offset': {
|
||||
'fcn': lambda name, x, y: self.collection.get_by_name(str(name)).offset([float(x), float(y)]),
|
||||
'help': "Changes the position of the object.\n" +
|
||||
"> offset <name> <x> <y>\n" +
|
||||
" name: Name of the object\n" +
|
||||
" x: X-axis distance\n" +
|
||||
" y: Y-axis distance"
|
||||
},
|
||||
'plot': {
|
||||
'fcn': self.plot_all,
|
||||
'help': 'Updates the plot on the user interface'
|
||||
}
|
||||
}
|
||||
|
||||
for cmd in commands:
|
||||
self.tcl.createcommand(cmd, commands[cmd]['fcn'])
|
||||
|
||||
self.tcl.eval('''
|
||||
rename puts original_puts
|
||||
proc puts {args} {
|
||||
if {[llength $args] == 1} {
|
||||
return "[lindex $args 0]"
|
||||
} else {
|
||||
eval original_puts $args
|
||||
}
|
||||
}
|
||||
''')
|
||||
|
||||
|
||||
|
||||
def setup_recent_items(self):
|
||||
self.log.debug("setup_recent_items()")
|
||||
|
||||
@@ -1473,8 +1704,8 @@ class App(QtCore.QObject):
|
||||
try:
|
||||
data = json.load(f)
|
||||
except:
|
||||
App.log.error("Could nor parse information about latest version.")
|
||||
self.inform.emit("Could nor parse information about latest version.")
|
||||
App.log.error("Could not parse information about latest version.")
|
||||
self.inform.emit("Could not parse information about latest version.")
|
||||
f.close()
|
||||
return
|
||||
|
||||
|
||||
Reference in New Issue
Block a user