# -*- coding: utf-8 -*- # CoordConvert # # Created by Erik Fløisbonn # Email: erif@0x6.org # # Latest version can be found at: # http://www.0x6.org/CoordConvert/ # name = "CoordConvert" version = "1.4.7b" modified = "13/04/09" author = u"Erik Fløisbonn" contact = "erif@0x6.org" url = "http://www.0x6.org/CoordConvert/" releasenotes = '''What's new? ----------- - Changed .kof format to correctly handle blank values of pointcode and themecode. - Filename guessing with drag-and-drop. - Create graph with Gnuplot (bundled), requires the newest CoordConvert. x_rot, y_rot and other options are not currently implemented. - Speed improvements.''' ''' TODO: 1. (Done) Alter .kof format to correctly handle blank values of pointcode and themecode 2. Add entity TYPE, so that one can transfer different types of data between formats - lines between kof/dxf 3. (Done) Filename guessing. 4. (Begun) Create graph - Must add gnuplot to bundle - Delete temporary files after they are used 5. Check for illegal file in gnuplot 6. Fix changing gnuplotfile. ''' import sys from PyQt4 import QtGui, QtCore import urllib2 import os # Globals set by Update.py '''if not "folder" in globals(): global folder folder = "./" if not "filename" in globals(): global filename filename = "CoordConvert"''' # Set color of window # This palette uses the colors of skanska. global skin skin = "normal" def useSkin(name): global skin skin = name def setStyle(window): if skin == "Skanska": window.setStyleSheet('''QMainWindow, QDialog { background: #E0E0E0; } QLineEdit { border: 1px solid #293e6b; color: #293e6b; background: #F4F4F4; selection-background-color: #293e6b; selection-color: #F0F0F0; } QTextEdit { border: 1px solid #293e6b; color: #293e6b; background: #F4F4F4; selection-background-color: #293e6b; selection-color: #F0F0F0; } QCheckBox::indicator { border: 0; } QCheckBox::indicator:unchecked { background-color: transparent; border: 1px solid #293e6b; } QCheckBox::indicator:checked { background-color: #293e6b; border: 0; } QPushButton { border: 1px solid #293e6b; background-color: #c8c8c8; color: #293e6b; padding-left: 10px; padding-right: 10px; } QPushButton:hover { color: #F0F0F0; border-style: inset; } QPushButton:pressed { background-color: #F0F0F0; color: #c8c8c8; } QMenu { background-color: #F0F0F0; color: #293e6b; border: 1px solid #293e6b; } QMenu::item { background-color: transparent; } QMenu::item:selected { background-color: #293e6b; color: #F0F0F0; } QMenuBar { background-color: #F4F4F4; color: #293e6b; border: 1px solid #293e6b; border-right: 0; border-top: 0; border-left: 1px solid transparent; /* bugfix */ } QMenuBar::item { spacing: 4px; /* spacing between menu bar items */ padding: 1px 4px; background: transparent; } QMenuBar::item:selected { /* when selected using mouse or keyboard */ background: #293e6b; color: #F0F0F0; } QMenuBar::item:pressed { background: #293e6b; color: #F0F0F0; } QTreeView { color: #293e6b; } QLabel { color: #293e6b; } /* Taken from Qt documentation */ QGroupBox { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E0E0E0, stop: 1 #FFFFFF); border: 1px solid #293e6b; margin-top: 1ex; /* leave space at the top for the title */ } QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top center; /* position at the top center */ padding: 0 3px; color: #293e6b; } QTreeView { background-color: #F4F4F4; border: 1px solid #293e6b; } QHeaderView::section { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #E0E0E0, stop: 1 #F4F4F4); color: #293e6b; padding-left: 4px; border-bottom: 1px solid #293e6b; border-left: 1px solid #293e6b; border-right: 1px solid #293e6b; border-top: None; } /* style the sort indicator */ QHeaderView::down-arrow { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #293e6b, stop: 1 #F4F4F4); } QHeaderView::up-arrow { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #F4F4F4, stop: 1 #293e6b); }''') elif skin == "LSK": window.setStyleSheet('''QMainWindow, QDialog { background: #EEEE10; } QLineEdit { border: 1px solid #000000; color: #000000; background: #FFFF00; selection-background-color: #000000; selection-color: #FFFF00; } QTextEdit { border: 1px solid #000000; color: #000000; background: #FFFF00; selection-background-color: #000000; selection-color: #FFFF00; } QCheckBox::indicator { border: 0; } QCheckBox::indicator:unchecked { background-color: transparent; border: 1px solid #000000; } QCheckBox::indicator:checked { background-color: #000000; border: 0; } QPushButton { border: 1px solid #000000; background-color: #EEEE10; color: #000000; padding-left: 10px; padding-right: 10px; } QPushButton:hover { color: #EEEE10; border-style: inset; background-color: #000000; } QPushButton:pressed { background-color: #FFFF10; color: #c8c8c8; } QMenu { background-color: #FFFF10; color: #000000; border: 1px solid #000000; } QMenu::item { background-color: transparent; } QMenu::item:selected { background-color: #000000; color: #FFFF10; } QMenuBar { background-color: #FFFF00; color: #000000; border: 1px solid #000000; border-right: 0; border-top: 0; border-left: 1px solid transparent; /* bugfix */ } QMenuBar::item { spacing: 4px; /* spacing between menu bar items */ padding: 1px 4px; background: transparent; } QMenuBar::item:selected { /* when selected using mouse or keyboard */ background: #000000; color: #FFFF10; } QMenuBar::item:pressed { background: #000000; color: #FFFF10; } QTreeView { color: #000000; } QLabel { color: #000000; } /* Taken from Qt documentation */ QGroupBox { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #EEEE10, stop: 1 #AAAA00); border: 1px solid #000000; margin-top: 1ex; /* leave space at the top for the title */ } QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top center; /* position at the top center */ padding: 0 3px; color: #000000; } QTreeView { background-color: #FFFF00; border: 1px solid #000000; } QHeaderView::section { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #EEEE10, stop: 1 #FFFF00); color: #000000; padding-left: 4px; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; border-top: None; } /* style the sort indicator */ QHeaderView::down-arrow { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #000000, stop: 1 #FFFF00); } QHeaderView::up-arrow { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFFF00, stop: 1 #000000); }"''') elif skin == "Forest": window.setStyleSheet(''' QMainWindow, QDialog { background: #AA0000; } QLineEdit { border: 1px solid #FFFFFF; color: #FFFFFF; background: #AA1010; selection-background-color: #FFFFFF; selection-color: #AA1010; } QTextEdit { border: 1px solid #FFFFFF; color: #FFFFFF; background: #AA1010; selection-background-color: #FFFFFF; selection-color: #AA1010; } QCheckBox { color: #FFFFFF; } QCheckBox::indicator { border: 0; } QCheckBox::indicator:unchecked { background-color: transparent; border: 1px solid #FFFFFF; } QCheckBox::indicator:checked { background-color: #FFFFFF; border: 0; } QPushButton { border: 1px solid #FFFFFF; background-color: #EE1010; color: #FFFFFF; padding-left: 10px; padding-right: 10px; } QPushButton:hover { color: #EE1010; border-style: inset; background-color: #FFFFFF; } QPushButton:pressed { background-color: #EE1010; color: #AA1010; } QMenu { background-color: #AA1010; color: #FFFFFF; border: 1px solid #FFFFFF; } QMenu::item { background-color: transparent; } QMenu::item:selected { background-color: #FFFFFF; color: #AA1010; } QMenuBar { background-color: #AA1010; color: #FFFFFF; border: 1px solid #FFFFFF; border-right: 0; border-top: 0; border-left: 1px solid transparent; /* bugfix */ } QMenuBar::item { spacing: 4px; /* spacing between menu bar items */ padding: 1px 4px; background: transparent; } QMenuBar::item:selected { /* when selected using mouse or keyboard */ background-color: #AA1010; color: #FFFFFF; } QMenuBar::item:pressed { background: #FFFFFF; color: #AA1010; } QTreeView { color: #FFFFFF; } QLabel { color: #FFFFFF; } /* Taken from Qt documentation */ QGroupBox { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #EE1010, stop: 1 #AA0000); border: 1px solid #FFFFFF; margin-top: 1ex; /*leave space at the top for the title */ } QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top center; /* position at the top center */ padding: 0 3px; color: #FFFFFF; border: 1px solid #FFFFFF; background-color: #EE1010; } QTreeView { background-color: #AA1010; border: 1px solid #FFFFFF; } QHeaderView::section { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #EE1010, stop: 1 #AA1010); color: #FFFFFF; padding-left: 4px; border-bottom: 1px solid #FFFFFF; border-left: 1px solid #FFFFFF; border-right: 1px solid #FFFFFF; border-top: None; } /* style the sort indicator */ QHeaderView::down-arrow { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFFFFF, stop: 1 #AA1010); } QHeaderView::up-arrow { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #AA1010, stop: 1 #FFFFFF); } "''') elif skin == "Lillestrom": window.setStyleSheet(''' QMainWindow, QDialog { background: #fad603; } QLineEdit { border: 1px solid #000000; color: #000000; /*background: #fad603;*/ selection-background-color: #000000; selection-color: #fad603; background: qlineargradient(x1:0,y1:0,x2:0,y2:1, stop:0 #000000, stop:0.1 #fad603, stop:0.8 #fad603, stop:1 #fad603); } QTextEdit { border: 1px solid #000000; color: #000000; background: #fad603; selection-background-color: #000000; selection-color: #fad603; } QCheckBox { color: #000000; } QCheckBox { color: #000000; } QCheckBox::indicator { border: 0; } QCheckBox::indicator:unchecked { background-color: transparent; border: 1px solid #000000; } QCheckBox::indicator:checked { background-color: #000000; border: 0; } QPushButton { border: 1px solid #000000; background-color: #fad603; color: #000000; padding-left: 10px; padding-right: 10px; background-color: qlineargradient(x1:0,y1:0,x2:0,y2:1, stop:0 white, stop:0.2 #fad603, stop:0.8 #fad603, stop:1 #000000) } QPushButton:hover { color: #fad603; border-style: inset; background-color: #000000; background-color: qlineargradient(x1:0,y1:0,x2:0,y2:1, stop:0 white, stop:0.2 #000000, stop:0.8 #000000, stop:1 #000000) } QPushButton:pressed { background-color: #000000; color: #fad603; } QMenu { background-color: #fad603; color: #000000; border: 1px solid #000000; } QMenu::item { background-color: transparent; } QMenu::item:selected { background-color: #000000; color: #fad603; } QMenuBar { background-color: #fad603; color: #000000; border: 1px solid #000000; border-right: 0; border-top: 0; border-left: 1px solid transparent; /* bugfix */ } QMenuBar::item { spacing: 4px; /* spacing between menu bar items */ padding: 1px 4px; background: transparent; } QMenuBar::item:selected { /* when selected using mouse or keyboard */ background-color: #fad603; color: #000000; } QMenuBar::item:pressed { background: #000000; color: #fad603; } QTreeView { color: #000000; } QLabel { color: #000000; } /* Taken from Qt documentation */ QGroupBox { background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 white, stop: 0.5 #fad603, stop: 1 #000000); border: 1px solid #000000; margin-top: 1ex; /*leave space at the top for the title */ /*border-radius: 3px;*/ } QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top center; /* position at the top center */ /*padding: 0 3px;*/ color: #000000; border: 1px solid #000000; background-color: #fad603; /*background: qlineargradient(x1:0,y1:0,x2:0,y2:1, stop:0 #000000, stop:0.1 #fad603, stop:0.8 #fad603, stop:1 #fad603);*/ } QTreeView { background-color: #fad603; border: 1px solid #000000; } QHeaderView::section { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #fad603, stop: 1 #fad603); color: #000000; padding-left: 4px; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; border-top: None; } /* style the sort indicator */ QHeaderView::down-arrow { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #000000, stop: 1 #fad603); } QHeaderView::up-arrow { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #fad603, stop: 1 #000000); } "''') else: window.setStyleSheet("") def setPalette(window): return if skin == "Skanska": palette = QtGui.QPalette(QtGui.QColor(41,62,107)) palette.setColor(QtGui.QPalette.Window, QtGui.QColor(240,240,240)) palette.setColor(QtGui.QPalette.Background, QtGui.QColor(240,240,240)) palette.setColor(QtGui.QPalette.WindowText, QtGui.QColor(41,62,107)) palette.setColor(QtGui.QPalette.Foreground, QtGui.QColor(41,62,107)) palette.setColor(QtGui.QPalette.Base, QtGui.QColor(244,244,244)) palette.setColor(QtGui.QPalette.AlternateBase, QtGui.QColor(244,244,244)) palette.setColor(QtGui.QPalette.Text, QtGui.QColor(41,62,107)) palette.setColor(QtGui.QPalette.Button, QtGui.QColor(200,200,200)) palette.setColor(QtGui.QPalette.ButtonText, QtGui.QColor(41,62,107)) palette.setColor(QtGui.QPalette.BrightText, QtGui.QColor(41,62,107)) # 3D palette.setColor(QtGui.QPalette.Light, QtGui.QColor(41,62,107)) palette.setColor(QtGui.QPalette.Midlight, QtGui.QColor(41,62,107)) palette.setColor(QtGui.QPalette.Dark, QtGui.QColor(41,62,107)) palette.setColor(QtGui.QPalette.Mid, QtGui.QColor(41,62,107)) palette.setColor(QtGui.QPalette.Shadow, QtGui.QColor(41,62,107)) palette.setColor(QtGui.QPalette.ToolTipBase, QtGui.QColor(41,62,107)) palette.setColor(QtGui.QPalette.ToolTipText, QtGui.QColor(244,244,244)) # Selected items palette.setColor(QtGui.QPalette.Highlight, QtGui.QColor(41,62,107)) palette.setColor(QtGui.QPalette.HighlightedText, QtGui.QColor(240,240,240)) # Hyperlinks palette.setColor(QtGui.QPalette.Link, QtGui.QColor(41,62,107)) palette.setColor(QtGui.QPalette.LinkVisited, QtGui.QColor(41,62,107)) window.setPalette(palette) else: window.setPalette(QtGui.QPalette()) # reSmall, subset of reStructuredtext # A veeeery simple reStructured text interpreter # This only supports headers h1->h5, unnumbered lists and paragraphs. def reSmall(text): out = [] tmp = [] headers = ["-", "+", "/", "*", "%"] # h1->h5 bullets = ["*", "+", "-"] lines = (text + "\n\n").splitlines().__iter__() for line in lines: if (len(line) > 1 and line[0] == "\t" and line[1] in bullets) or (len(line) > 4 and line[0:4] == " "*4 and line[4] in bullets): # Remove the bullet line = line[0:5].strip("".join(bullets)) + line[5:] if "
%s
" % ("".join(tmp)));tmp=[] tmp.append("%s
" % ("".join(tmp[:-1]))) out.append("%s
" % ("".join(tmp)));tmp=[] else: tmp.append(line) return "\n".join(out) # Classes defining readers and writers class Widget(): ''' Widget class that represents the widgets string, cstring, check ''' def __init__(self, name, type, value, label=None, checked=None, description=None, priority=99): self.type = type self.name = name self.label = label self.priority = priority if type == "string": self.widget = QtGui.QLineEdit(value) if label: self.label = QtGui.QLabel(self.label) else: self.label = QtGui.QLabel(self.name) if type == "cstring": self.widget = QtGui.QLineEdit(value) if label: self.check = QtGui.QCheckBox(self.label) else: self.check = QtFGui.QCheckBox(self.name) if type == "check": if label: self.check = QtGui.QCheckBox(self.label) else: self.check = QtGui.QCheckBox(self.name) # Description if description: self.button = QtGui.QPushButton('?') self.description = description # Checked if checked != None and hasattr(self, "check"): if (checked == "True" or checked == True): checked = True elif (checked == "False" or checked == False): checked = False else: return # Change widgets self.check.setChecked(checked) self.check_action(checked) # Widget actions def check_action(self, value): if hasattr(self, "widget"): if value: self.widget.setEnabled(True) else: self.widget.setEnabled(False) def button_action(self): if hasattr(self, "description"): # QtGui.QMessageBox.information(None, self.name, self.description) textedit(title=self.name, text=self.description) class Variables(): ''' Variables class, one level above the widgets. Has the responsibility of getting stored values of the widgets, storing the values, showing the widgets and deleting them. It is also the interface towards the user when accessing variables, like get_var and is_checked. ''' def __init__(self, config): self.config = config self.var = {} variables = [] # Add all the variables defined in 'in_variables()' if self.job == "reader" and hasattr(self, "reader_variables") and self.reader_variables(): if type(self.reader_variables()) == list: variables.extend(self.reader_variables()) # Add all the variables defined in 'out_variables()' if self.job == "writer" and hasattr(self, "writer_variables") and self.writer_variables(): if type(self.writer_variables()) == list: variables.extend(self.writer_variables()) # Add widgets for var in variables: if type(var) != dict: continue # name, type, value, label, description # m, m, m, o, o description = None label = None priority = 99 if "name" in var.keys(): name = var["name"] else: QtGui.QMessageBox.warning(None, 'Format error', "One of " + str(self.__class__.__name__) + "'s " + self.job + " variables does not have a name.") if "type" in var.keys(): typei = var["type"] else: QtGui.QMessageBox.warning(None, 'Format error', str(self.__class__.__name__) + "'s " + self.job + " variable " + name + " does not have a type.") if "value" in var.keys(): value = var["value"] else: QtGui.QMessageBox.warning(None, 'Format error', str(self.__class__.__name__) + "'s " + self.job + " variable " + name + " does not have a default value.") if "label" in var.keys(): label = var["label"] if "description" in var.keys(): description = var["description"] if "priority" in var.keys(): priority = var["priority"] # Add variable self.add_var(name, typei, value, label=label, description=description, priority=priority) def add_var(self, name, type, default, label=None, description=None, priority=99): # Check to see if the value is in the config # if so, add it instead of the default # Look in config if not self.config: return None # Get widget value value = self.config.get(self.__class__.__name__, name + ".widget") if not value: value = default # Get check value, default is None checked = self.config.get(self.__class__.__name__, name + ".check") if not checked: checked = default # Add variable self.var[name] = Widget(name, type, value, label=label, checked=checked, description=description, priority=priority) def get_var(self, name): if name not in self.var.keys(): return None if self.var[name].type == "check": # Get the value return self.var[name].check.isChecked() else: return self.var[name].widget.text() def is_checked(self, name): widget = self.var[name] if hasattr(widget, "check"): return widget.check.isChecked() return None def addWidgets(self, box, window=None): # Sort by variable name # keys = self.var.keys() #keys.sort() # Sort the variables based on their priority keys = self.var.keys() keys.sort(lambda x,y:cmp(self.var[x].priority,self.var[y].priority)) x, y = 0, 0 for name in keys: widget = self.var[name] y = 0 if widget.type == "cstring": box.addWidget(self.var[name].check, x, y) y+=1 box.addWidget(self.var[name].widget, x, y) y+=1 # Add check action box.parentWidget().connect(self.var[name].check, QtCore.SIGNAL('stateChanged(int)'), self.var[name].check_action) if widget.type == "string": box.addWidget(self.var[name].label, x, y) x+=1; box.addWidget(self.var[name].widget, x, y) y+=1 if widget.type == "check": box.addWidget(self.var[name].check, x, y) y+=1 if hasattr(self.var[name], "button"): # Resize button if window: # Same size as in_file button = window.out_file_button size = button.width() self.var[name].button.setMaximumWidth(size) box.addWidget(self.var[name].button, x, 2) box.parentWidget().connect(self.var[name].button, QtCore.SIGNAL('pressed()'), self.var[name].button_action) x +=1 def deleteWidgets(self, box): x, y = 0, 0 for name in self.var: widget = self.var[name] # Add value to config if hasattr(widget, "widget"): self.config.set(self.__class__.__name__, name + ".widget", self.get_var(name)) if hasattr(widget, "check"): self.config.set(self.__class__.__name__, name + ".check", str(self.is_checked(name))) if widget.type == "cstring": box.removeWidget(self.var[name].check) box.removeWidget(self.var[name].widget) self.var[name].check.setParent(None) self.var[name].widget.setParent(None) if widget.type == "string": box.removeWidget(self.var[name].label) self.var[name].label.setParent(None) box.removeWidget(self.var[name].widget) self.var[name].widget.setParent(None) if widget.type == "check": box.removeWidget(self.var[name].check) self.var[name].check.setParent(None) if hasattr(self.var[name], "button"): box.removeWidget(self.var[name].button) self.var[name].button.setParent(None) x +=1 self.var = {} class io(Variables): ''' For each userformat this holds the file, and statistics about io ''' def __init__(self, file, options=None, config=None, job=None): self.file = file self.options = options self.job = job self.points = 0 self.lines = 0 Variables.__init__(self, config=config) # Methods called before and after a conversion # self.job holds the job, either reader or writer def before(self): pass def after(self): pass # Stop the conversion def stop(self, message): raise Exception(message) # Give a warning. Best to do in after() or before() # as if used in next() or read() you will get spammed. def warning(self, message): QtGui.QMessageBox.warning(None, "Warning!", message) class writer(io): ''' Writer class, holds the functions that can be overloaded by usercreated formats To create a custom writer, overload write(self, dict) and use self.write_point() to write to the output.''' def write(self, dict): return None # Write point to the file def write_point(self, string): if hasattr(self, "points"): self.points+=1 self.file.write(string) def writer_variables(self): return None def writer_report(self): return "" class reader(io): ''' Reader class, holds the functions that can be overloaded by usercreated formats To create a custom reader, overload next(self) and use self.return_point(self, dict) to return point, and read from input wuth self.file.next().''' def __iter__(self): return self def next(self): self.file.next() return None # Return point to the writer def return_point(self, dict): if hasattr(self, "points"): self.points+=1 return dict def reader_variables(self): return None def reader_report(self): return "" # Classes implementing formats class Parser: ''' Parse a string with $(variables) and $functions(arg1,arg2,...). dict holds the variable values. ''' def __init__(self, dict): # Variables, add whitespace self.var = dict.copy() self.var['space'] = " " self.var['tab'] = "\t" self.var['newline'] = "\n" self.var['comma'] = "," # Functions self.functions = ["+", "-", "*", "/"] def parse(self, format): # format variables for key, item in self.var.iteritems(): if key and item: format = format.replace("$(" + key + ")", str(item)) # Functions functions = self.functions pos = format.find("$") # While there are dollars left while pos != -1: fparan = format.find("(", pos) nextDollar = format.find("$", pos+1) if nextDollar == -1: nextDollar = fparan+1 # Found a right paranthesis. Does it belong to this dollar? if fparan != -1 and fparan < nextDollar: # Get name fname = format[pos+1:fparan] if fname in functions: # Get end end = format.find(")", fparan) if end != -1: # Get arguments arg_string = format[fparan+1:end].split(",") res = "" if len(arg_string[0]) > 0: try: res = eval(fname.join(arg_string), {}, {}) except Exception, e: raise Exception("Interpretation of " + fname.join(arg_string) + ":\n\n" + str(e)) # Replace the function call with the result format = format.replace(format[pos:end+1], str(res)) # Go to next dollar pos = format.find("$", pos+1) return format class txt(reader, writer): ''' .txt reader/writer. Reads line by line from a file, and tries to match the line to a given format with variables. Writers lines on the usergiven format ''' def before(self): self.ignored = 0 def reader_report(self): return "Ignored " + str(self.ignored) + " line(s)
" def writer_variables(self): return [{ "name": "out_format", "type": "string", "value": "$(x),$(y),$(z)", "label": "Use format:", "description": reSmall('''txt writer ---------- The program supports several file formats which in all cases define x, y and z coordinates of each point. Since some formats also include other information like pointcode, certain formats also define format specific variables. This is a list of the variables and functions one can use with the .txt writer class, which enables the user to specify a custom writer format. Variables +++++++++ - $(pointcode) = pointcode from a .kof file. - $(x), $(y), $(z) = x, y, z coordinates for each point - $(tab), $(space), $(newline), $(comma) = Tab, space, newline, comma - Functions: $+, $/, $-, $* on the form $+(arg1,arg2,...) => arg1 + arg2 + ... Note: Valid arguments to functions are numbers and variables, as they are evaluated the first pass. Calls to functions are invalid arguments. Example +++++++ - To write "x,y,z" for all points, use the format "$(x), $(y), $(z)". - To write "x/2, y-1, z+1" for all points, use the format "$/($(x),2),$-($(y),1),$+($(z),1)"''')}] def reader_variables(self): return [{ "name": "in_format", "type": "string", "value": "$(x),$(y),$(z)", "label": "Uses format:", "description": reSmall('''txt reader ---------- This reader enables the user to read files with a custom userdefined format. The reader tries to match the format to each line of the infile, by matching and setting the variable values as it goes from left to right. The reader learns as it moves along, so if you are looking for and matching $(x), the next $(x) will only match it's allready set value. Unknown delimiter +++++++++++++++++ If you do not know the delimiter, or if it varies from line to line, you can match each delimiter to it's own variable. The reader then looks for numbers, and uses anything inbetween as delimiter. For example: - If you have a file with "x,y,z" and "x-y_z", you can use the format "$(x)$(s1)$(y)$(s2)$(z)". This will match both lines and it will set s1,s2 accordingly. If you had used $(s) instead of s1,s2, the second line would not match as "-" does not equal "_". Example ++++++++ - If you have a file with points on the format "x,y;z", you can extract the values by using the format "$(x),$(y);$(z)".''')}, { "name": "stop_mismatch", "type": "check", "value": True, "label": "Stop on mismatch", "description": reSmall('''txt reader stop on mismatch ----------------------------- If you check "stop on mismatch" the program will stop when it encounters a line that does not match the format given. If it is not checked, the program will ignore all lines that do not match.''')}] def write(self, dict): format = str(self.get_var("out_format")) parser = Parser(dict) self.write_point(parser.parse(format) + "\n") def get_next(self): if len(self.match) > 0: if self.match[0:2] == "$(": end = self.match[0:].find(")") # Could not find an end, it's just text if end == -1: tmp = self.match[0] self.match = self.match[1:] return tmp tmp = self.match[0:end+1] self.match = self.match[end+1:] # Match the variable with constants # and variables found so far if len(tmp) >=3: var = tmp[2:len(tmp)-1] if var in self.vars.keys(): return self.vars[var] return tmp else: tmp = self.match[0] self.match = self.match[1:] return tmp return "" def next(self): # Match format line = self.file.next().strip("\n") self.match = str(self.get_var("in_format")) self.vars = {} self.vars['space'] = " " self.vars['tab'] = "\t" self.vars['comma'] = "," while len(self.match) > 0: pattern = self.get_next() ahead = self.get_next() if pattern[0] != "$": if pattern[0] == line[0]: line = line[1:] self.match = ahead + self.match continue else: if self.is_checked("stop_mismatch"): self.stop("Can not map:\n\n" + pattern + ahead + " to " + line + "\n\nThe character '" + pattern[0] + "' does not match '" + line[0] + "'.") self.ignored +=1 return self.return_point(None) # Variable pattern else: # Two variables of unknow size not possible if not looking # for something specific if len(ahead) > 0 and ahead[0] == "$": # Find number innumber = ["1","2","3","4","5","6","7","8","9","0",".", "-"] number = [] while len(line) > 0 and line[0] in innumber: number.append(line[0]) line = line[1:] # Did not find a number if number == []: # The left is not a number # Go forward until you encounter a number. nonumber = [] while len(line) > 0 and line[0] not in innumber: nonumber.append(line[0]) line = line[1:] # Assign the value of the variable to the number. # Is only set on the first encounter of an variable, # as the rest is evaluated to the value. if len(nonumber) > 0: self.vars[pattern[2:len(pattern)-1]] = "".join(nonumber) self.match = ahead + self.match continue else: # Found a number # Assign the value to the variable. self.vars[pattern[2:len(pattern)-1]] = "".join(number) self.match = ahead + self.match continue # Find the ahead if ahead == "": self.vars[pattern[2:len(pattern)-1]] = line line = "" else: pos = line.find(ahead) if pos != -1: self.vars[pattern[2:len(pattern)-1]] = line[:pos] line = line[pos+1:] else: if self.is_checked("stop_mismatch"): self.stop("Can not map:\n\n" + pattern + ahead + " to '" + line + "'\n\nas the character '" + ahead + "' is not in the string '" + line + "'.") self.ignored +=1 return self.return_point(None) return self.return_point(self.vars) class pxy(reader): ''' Reader class for .pxy files ''' def __iter__(self): return self def next(self): line = self.file.next() tokens = line.split(" ") tokens = [token for token in tokens if token != ""] # Get token 1, 2, 3 dict = {'pre': "", "coord": "", "post":""} # Only interrested in lines on the format: #| " + text + " |
Read " + str(k.reader.file.tell()) + " byte(s) from " + k.reader.file.name + "
", str(k.reader.reader_report()), "Wrote " + str(k.writer.file.tell()) + " byte(s) to " + k.writer.file.name + "
", str(k.writer.writer_report()), "