import rev 27 from https://bazaar.launchpad.net/~j/calcool
This commit is contained in:
commit
2a9f5822e5
28 changed files with 4155 additions and 0 deletions
273
bin/calcool
Executable file
273
bin/calcool
Executable file
|
|
@ -0,0 +1,273 @@
|
|||
#!/usr/bin/python
|
||||
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||
### BEGIN LICENSE
|
||||
# Copyright (C) 2010 jan gerber <j@mailb.org>
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 3, as published
|
||||
# by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranties of
|
||||
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
|
||||
# PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
### END LICENSE
|
||||
from __future__ import division
|
||||
import sys
|
||||
import os
|
||||
import gtk
|
||||
|
||||
from gtksourceview2 import View as GtkSourceView
|
||||
|
||||
from math import *
|
||||
safe_list = ['math','acos', 'asin', 'atan', 'atan2', 'ceil', 'cos',
|
||||
'cosh', 'degrees', 'e', 'exp', 'fabs', 'floor', 'fmod',
|
||||
'frexp', 'hypot', 'ldexp', 'log', 'log10', 'modf', 'pi',
|
||||
'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh']
|
||||
|
||||
#use the list to filter the local namespace
|
||||
safe_dict = dict([ (k, locals().get(k, None)) for k in safe_list ])
|
||||
#add any needed builtins back in.
|
||||
safe_dict['abs'] = abs
|
||||
|
||||
import re
|
||||
|
||||
# Check if we are working in the source tree or from the installed
|
||||
# package and mangle the python path accordingly
|
||||
if os.path.dirname(sys.argv[0]) != ".":
|
||||
if sys.argv[0][0] == "/":
|
||||
fullPath = os.path.dirname(sys.argv[0])
|
||||
else:
|
||||
fullPath = os.getcwd() + "/" + os.path.dirname(sys.argv[0])
|
||||
else:
|
||||
fullPath = os.getcwd()
|
||||
sys.path.insert(0, os.path.dirname(fullPath))
|
||||
|
||||
from calcool import AboutCalcoolDialog
|
||||
from calcool.calcoolconfig import getdatapath
|
||||
|
||||
class CalcoolWindow(gtk.Window):
|
||||
__gtype_name__ = "CalcoolWindow"
|
||||
|
||||
record_type = "http://wiki.ubuntu.com/Quickly/CalcoolDocument"
|
||||
database_name = "calcool"
|
||||
filename = ''
|
||||
|
||||
def __init__(self):
|
||||
"""__init__ - This function is typically not called directly.
|
||||
Creation a CalcoolWindow requires redeading the associated ui
|
||||
file and parsing the ui definition extrenally,
|
||||
and then calling CalcoolWindow.finish_initializing().
|
||||
|
||||
Use the convenience function NewCalcoolWindow to create
|
||||
CalcoolWindow object.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def finish_initializing(self, builder):
|
||||
"""finish_initalizing should be called after parsing the ui definition
|
||||
and creating a CalcoolWindow object with it in order to finish
|
||||
initializing the start of the new CalcoolWindow instance.
|
||||
|
||||
"""
|
||||
#get a reference to the builder and set up the signals
|
||||
self.builder = builder
|
||||
self.builder.connect_signals(self)
|
||||
|
||||
def about(self, widget, data=None):
|
||||
"""about - display the about box for calcool """
|
||||
about = AboutCalcoolDialog.NewAboutCalcoolDialog()
|
||||
response = about.run()
|
||||
about.destroy()
|
||||
|
||||
def quit(self, widget, data=None):
|
||||
"""quit - signal handler for closing the CalcoolWindow"""
|
||||
self.destroy()
|
||||
|
||||
def on_destroy(self, widget, data=None):
|
||||
"""on_destroy - called when the CalcoolWindow is close. """
|
||||
#clean up code for saving application state should be added here
|
||||
|
||||
gtk.main_quit()
|
||||
|
||||
def update_output(self):
|
||||
self.builder.get_object('status').set_text('Calculating...')
|
||||
txt = self.builder.get_object('input').get_buffer()
|
||||
text = txt.get_text(txt.get_start_iter(), txt.get_end_iter())
|
||||
rows = text.split('\n')
|
||||
otxt = []
|
||||
computed_values = []
|
||||
def expand_lines(line):
|
||||
return re.sub('line(\d+)', lambda m: 'line%010d'%int(m.groups(0)[0]), line)
|
||||
def resolve_row(r, line):
|
||||
#if r not in self._results:
|
||||
try:
|
||||
r_ = r
|
||||
r_ = expand_lines(r_)
|
||||
|
||||
match = re.compile('line(\d+)').findall(r)
|
||||
match = filter(lambda l: int(l) <= len(rows), match)
|
||||
if match:
|
||||
for l in match:
|
||||
l = int(l)
|
||||
assert(l!=line)
|
||||
value = '(%s)' % expand_lines(rows[l-1])
|
||||
r_ = r_.replace('line%010d' % l, value)
|
||||
r_ = resolve_row(r_, line)
|
||||
#print r, r_
|
||||
result = str(eval(r_, {"__builtins__":None}, safe_dict))
|
||||
|
||||
#highlight computed values
|
||||
if result != r:
|
||||
offset = len('\n'.join(otxt))
|
||||
computed_values.append((offset, offset+len(result)+1))
|
||||
except:
|
||||
result = r
|
||||
return result
|
||||
|
||||
for i, r in enumerate(rows):
|
||||
otxt.append(resolve_row(r, i+1))
|
||||
output = self.builder.get_object('output').get_buffer()
|
||||
output.set_text('\n'.join(otxt))
|
||||
|
||||
tagTable = output.get_tag_table()
|
||||
computed = tagTable.lookup('computed')
|
||||
if not computed:
|
||||
computed = gtk.TextTag('computed')
|
||||
computed.set_property('weight', 700) # pango.WEIGHT_BOLD = 700
|
||||
tagTable.add(computed)
|
||||
|
||||
for start, end in computed_values:
|
||||
currentIter = output.get_iter_at_offset(start)
|
||||
currentEndIter = output.get_iter_at_offset(end)
|
||||
output.apply_tag(computed, currentIter, currentEndIter)
|
||||
|
||||
self.builder.get_object('status').set_text('')
|
||||
|
||||
def keypressed(self, widget, data=None):
|
||||
self.update_output()
|
||||
|
||||
def new_file(self, widget, data=None):
|
||||
self.filename = ''
|
||||
buff = self.builder.get_object("input").get_buffer()
|
||||
buff.set_text("")
|
||||
self.update_output()
|
||||
|
||||
def load_file(self, filename):
|
||||
with open(filename) as f:
|
||||
text = f.read().decode('utf-8')
|
||||
#set the UI to display the string
|
||||
buff = self.builder.get_object("input").get_buffer()
|
||||
buff.set_text(text)
|
||||
self.update_output()
|
||||
self.filename = filename
|
||||
|
||||
def open_file(self, widget, data=None):
|
||||
dialog = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_OPEN,
|
||||
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
|
||||
|
||||
dialog.set_default_response(gtk.RESPONSE_OK)
|
||||
|
||||
filter = gtk.FileFilter()
|
||||
filter.set_name("Calcool Documents")
|
||||
filter.add_mime_type("text/x-calcool")
|
||||
filter.add_pattern("*.calc")
|
||||
dialog.add_filter(filter)
|
||||
|
||||
filter = gtk.FileFilter()
|
||||
filter.set_name("All files")
|
||||
filter.add_pattern("*")
|
||||
dialog.add_filter(filter)
|
||||
|
||||
response = dialog.run()
|
||||
if response == gtk.RESPONSE_OK:
|
||||
filename = dialog.get_filename()
|
||||
dialog.destroy()
|
||||
self.load_file(filename)
|
||||
else:
|
||||
dialog.destroy()
|
||||
|
||||
def save_file(self, widget, data=None):
|
||||
|
||||
if not self.filename:
|
||||
return self.save_as_file(widget)
|
||||
|
||||
title = self.filename
|
||||
|
||||
buff = self.builder.get_object("input").get_buffer()
|
||||
start_iter = buff.get_start_iter()
|
||||
end_iter = buff.get_end_iter()
|
||||
|
||||
text = buff.get_text(start_iter,end_iter)
|
||||
with open(self.filename, "w") as f:
|
||||
f.write(text.encode('utf-8'))
|
||||
|
||||
def save_as_file(self, widget, data=None):
|
||||
dialog = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_SAVE,
|
||||
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
|
||||
filter = gtk.FileFilter()
|
||||
filter.set_name("Calcool Documents")
|
||||
filter.add_mime_type("text/x-calcool")
|
||||
filter.add_pattern("*.calc")
|
||||
dialog.add_filter(filter)
|
||||
|
||||
filter = gtk.FileFilter()
|
||||
filter.set_name("All files")
|
||||
filter.add_pattern("*")
|
||||
dialog.add_filter(filter)
|
||||
|
||||
response = dialog.run()
|
||||
if response == gtk.RESPONSE_OK:
|
||||
self.filename = dialog.get_filename()
|
||||
self.save_file(widget)
|
||||
dialog.destroy()
|
||||
|
||||
def cut(self, widget, data=None):
|
||||
pass
|
||||
def copy(self, widget, data=None):
|
||||
pass
|
||||
def paste(self, widget, data=None):
|
||||
pass
|
||||
def delete(self, widget, data=None):
|
||||
pass
|
||||
|
||||
def NewCalcoolWindow():
|
||||
"""NewCalcoolWindow - returns a fully instantiated
|
||||
CalcoolWindow object. Use this function rather than
|
||||
creating a CalcoolWindow directly.
|
||||
"""
|
||||
|
||||
#look for the ui file that describes the ui
|
||||
ui_filename = os.path.join(getdatapath(), 'ui', 'CalcoolWindow.ui')
|
||||
if not os.path.exists(ui_filename):
|
||||
ui_filename = None
|
||||
|
||||
builder = gtk.Builder()
|
||||
builder.add_from_file(ui_filename)
|
||||
window = builder.get_object("calcool_window")
|
||||
window.finish_initializing(builder)
|
||||
return window
|
||||
|
||||
if __name__ == "__main__":
|
||||
#support for command line options
|
||||
import logging, optparse
|
||||
parser = optparse.OptionParser(version="%prog %ver")
|
||||
parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="Show debug messages")
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
#set the logging level to show debug messages
|
||||
if options.verbose:
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logging.debug('logging enabled')
|
||||
|
||||
#run the application
|
||||
window = NewCalcoolWindow()
|
||||
window.show()
|
||||
if args:
|
||||
window.load_file(args[0])
|
||||
gtk.main()
|
||||
def save_file(self, widget, data=None):
|
||||
print "save"
|
||||
Loading…
Add table
Add a link
Reference in a new issue