~strainanalyser/strainanalyser/trunk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#!/usr/bin/python
#
# Strain Analyser
# Copyright (C) 2009-2010 Malcolm Scott <Malcolm.Scott@cl.cam.ac.uk>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 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 warranty of
# MERCHANTABILITY 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, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.


import gtk

from strainanalyser.util import *
from strainanalyser.datahandling import *
from strainanalyser.graphing import *


class StrainAnalyserDatasetUI(AbstractUI):

	def __init__(self, compensated_dataset=None, toplevel=False, save_cb=lambda cb_arg,dataset: True, cb_arg=None):
		super(StrainAnalyserDatasetUI, self).__init__("dataset.xml", "datasetwindow")

		self.save_cb = save_cb
		self.cb_arg = cb_arg

		self.last_strain_path = None
		self.last_loss_path = None

		self.toplevel = toplevel
		self.get_window().set_modal(not toplevel)

		if compensated_dataset:
			# unravel the spaghetti the caller threw at us
			self.compensated_dataset = compensated_dataset
			self.avg_strain_dataset = compensated_dataset.strain_dataset
			self.avg_temperature_dataset = compensated_dataset.temperature_dataset
			self.strain_dataset = self.avg_strain_dataset.dataset
			self.temperature_dataset = self.avg_temperature_dataset.dataset
		else:
			# cook the spaghetti ready to throw at the caller
			self.strain_dataset = StrainAnalyserDataset()
			self.temperature_dataset = StrainAnalyserDataset()
			self.avg_strain_dataset = StrainAnalyserAveragedDataset(self.strain_dataset)
			self.avg_temperature_dataset = StrainAnalyserAveragedDataset(self.temperature_dataset)
			self.compensated_dataset = StrainAnalyserTemperatureCompensatedDataset(
					strain_dataset=self.avg_strain_dataset,
					temperature_dataset=self.avg_temperature_dataset,
				)

		self.datagraph = StrainAnalyserDataGraph(
				widget_add_cb=self.get_object("graphcontainer").add,
				set_temperature_offset_cb=self.set_temperature_offset,
				set_range_cb=self.set_range,
				avg_dataset_strain=self.avg_strain_dataset,
				avg_dataset_temperature=self.avg_temperature_dataset
			)

		# initialise dataset list model-view-controller stuff
		# (insert "GTK, you're doing this wrong" soundbite)
		for widgetname, dataset in [("strainlist", self.strain_dataset), ("temperaturelist", self.temperature_dataset)]:
			widget = self.get_object(widgetname)
			# TODO: final boolean is a temporary hack to hide loss until that's implemented
			cols = [
					("Strain data file", 0, True),
					("Loss data file", 1, False),
				]
			for (title, columnId, visible) in cols:
				column = gtk.TreeViewColumn(title, gtk.CellRendererText(), text=columnId)
				column.set_resizable(True)
				column.set_sort_column_id(columnId)
				column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
				column.set_expand(True)
				column.set_visible(visible)
				widget.append_column(column)
			widget.set_model(dataset)

		toggle_renderer = gtk.CellRendererToggle()
		toggle_renderer.set_property('activatable', True)
		toggle_renderer.connect("toggled", self.on_strainlist_include_toggled)
		column = gtk.TreeViewColumn("", toggle_renderer, active=3)
		self.get_object("strainlist").append_column(column)

		toggle_renderer = gtk.CellRendererToggle()
		toggle_renderer.set_property('activatable', True)
		toggle_renderer.connect("toggled", self.on_temperaturelist_include_toggled)
		column = gtk.TreeViewColumn("", toggle_renderer, active=3)
		self.get_object("temperaturelist").append_column(column)

		self.get_object("alpha_a").set_value(self.compensated_dataset.alpha_a)
		self.get_object("alpha_n_temp").set_value(self.compensated_dataset.alpha_n_temp)
		self.get_object("alpha_n_strain").set_value(self.compensated_dataset.alpha_n_strain)

		self.get_object("dataset_name").set_text(self.compensated_dataset.name)

		# Not self.set_temperature_offset, or the graph doesn't pick up the change
		self.datagraph.set_temperature_shift(self.compensated_dataset.temperature_offset)
		self.datagraph.set_range(self.compensated_dataset.range_start, self.compensated_dataset.range_end)

		self.update_controls()

	def show(self):
		self.on_dataset_name_changed(self.get_object("dataset_name"))
		super(StrainAnalyserDatasetUI, self).show()

	def set_range(self, x1, x2):
		if x1 is not None and x2 is not None:
			self.compensated_dataset.range_start = x1
			self.compensated_dataset.range_end = x2
			self.get_object("range_start_label").set_text("%.1f m" % x1)
			self.get_object("range_end_label").set_text("%.1f m" % x2)

	def set_temperature_offset(self, offset):
		self.compensated_dataset.temperature_offset = offset
		self.get_object("thermal_offset_label").set_text("%.1f m" % offset)

	def choosedata(self, add_cb):
		chooserbuilder = gtk.Builder()
		chooserbuilder.add_from_file(relfile("straindatachooser.xml"))
		dialog = chooserbuilder.get_object("straindatachooser")
		strainfile = chooserbuilder.get_object("strainfile")
		lossfile = chooserbuilder.get_object("lossfile")
		try:
			if self.last_strain_path != None:
				strainfile.set_current_folder(self.last_strain_path)
			if self.last_loss_path != None:
				lossfile.set_current_folder(self.last_loss_path)
		except Exception:
			pass
		retry = True
		while retry:
			retry = False
			response = dialog.run()
			if response == 0:
				try:
					data = StrainAnalyserDatafile(strainfile.get_filename(), lossfile.get_filename())
				except Exception, e:
					self.errorbox("Error loading data", str(e))
					retry = True
				else:
					self.last_strain_path = strainfile.get_current_folder()
					self.last_loss_path = lossfile.get_current_folder()
					dialog.destroy()
					if ((len(self.strain_dataset) > 0 or len(self.temperature_dataset) > 0)
							and self.compensated_dataset.recorded_resolution != data.resolution):
						self.errorbox("Error loading data",
								"Resolution of added data (%s m) does not match that of existing data (%s m)." %
								(data.resolution, self.compensated_dataset.recorded_resolution)
							)
						retry = True
					elif ((len(self.strain_dataset) > 0 or len(self.temperature_dataset) > 0)
							and self.compensated_dataset.recorded_refractiveindex != data.refractiveindex):
						self.errorbox("Error loading data",
								"Recorded refractive index of added data (%s) does not match that of existing data (%s)." %
								(data.refractiveindex, self.compensated_dataset.recorded_refractiveindex)
							)
						retry = True
					else:
						#data.resolution = self.resolution  # just in case we've overridden the recorded refractive index
						add_cb(data)
						self.update_controls()
			else:
				dialog.destroy()

	def update_controls(self):
		if len(self.strain_dataset) > 0 or len(self.temperature_dataset) > 0:
			self.compensated_dataset.update_resolution()
			self.get_object("recorded_refractive_index").set_text(str(self.compensated_dataset.recorded_refractiveindex))
			self.get_object("recorded_resolution").set_text("%.3f m" % self.compensated_dataset.recorded_resolution)
			self.get_object("refractive_index").set_value(self.compensated_dataset.refractiveindex)
			self.get_object("resolution").set_text("%.3f m" % self.compensated_dataset.resolution)


	# Signal handlers

	def on_datasetwindow_destroy(self, widget):
		if self.toplevel:
			gtk.main_quit()

	def on_add_strain_file_clicked(self, widget):
		self.choosedata(add_cb=self.strain_dataset.add_file)
		self.datagraph.redraw()

	def on_remove_strain_file_clicked(self, widget):
		strainlist = self.get_object("strainlist")
		cursor = strainlist.get_cursor()[0]
		if cursor:
			index = cursor[0]
			self.strain_dataset.remove_file(index)
			self.datagraph.redraw()

	def on_add_temperature_file_clicked(self, widget):
		self.choosedata(add_cb=self.temperature_dataset.add_file)
		self.datagraph.redraw()

	def on_remove_temperature_file_clicked(self, widget):
		temperaturelist = self.get_object("temperaturelist")
		cursor = temperaturelist.get_cursor()[0]
		if cursor:
			index = cursor[0]
			self.temperature_dataset.remove_file(index)
			self.datagraph.redraw()

	def on_strainlist_include_toggled(self, widget, path):
		self.strain_dataset[path][3] = not self.strain_dataset[path][3]
		self.datagraph.redraw()

	def on_temperaturelist_include_toggled(self, widget, path):
		self.temperature_dataset[path][3] = not self.temperature_dataset[path][3]
		self.datagraph.redraw()

	def on_refractive_index_value_changed(self, widget):
		self.compensated_dataset.refractiveindex = widget.get_value()
		self.update_controls()
		# Hack to make the scale on this preliminary graph right, despite the real refractive index
		# compensation being done by a later stage
		self.avg_strain_dataset.resolution_factor = self.compensated_dataset.resolution / self.compensated_dataset.recorded_resolution
		self.avg_temperature_dataset.resolution_factor = self.avg_strain_dataset.resolution_factor
		self.datagraph.redraw()

	def on_alpha_a_value_changed(self, widget):
		self.compensated_dataset.alpha_a = widget.get_value()
		self.datagraph.redraw()

	def on_alpha_n_strain_value_changed(self, widget):
		self.compensated_dataset.alpha_n_strain = widget.get_value()
		self.datagraph.redraw()

	def on_alpha_n_temp_value_changed(self, widget):
		self.compensated_dataset.alpha_n_temp = widget.get_value()
		self.datagraph.redraw()

	def on_dataset_name_changed(self, widget):
		name = (widget.get_text() or "Untitled")
		self.compensated_dataset.name = name
		self.get_window().set_title("%s - Edit Dataset - Strain Analyser" % name)

	def on_editmode_align_toggled(self, widget):
		if widget.get_active():
			self.datagraph.set_align_mode()

	def on_editmode_range_toggled(self, widget):
		if widget.get_active():
			self.datagraph.set_range_mode()

	def on_cancel_clicked(self, widget):
		self.destroy()

	def on_go_clicked(self, widget):
		if len(self.strain_dataset) == 0:
			self.errorbox("Cannot save",
					"Please add some strain data before attempting to save."
				)
			return
		if self.compensated_dataset.range_start is None or self.compensated_dataset.range_end is None:
			self.get_object("editmode_range").activate()
			self.errorbox("Cannot save",
					"Please set a range of interest before saving."
				)
			return
		self.compensated_dataset.refresh()
		if self.save_cb(self.cb_arg, self.compensated_dataset) != False:
			self.destroy()


if __name__ == "__main__":
	ui = StrainAnalyserDatasetUI(toplevel=True, save_cb=lambda cb_arg,dataset: simple_graph_viewer(dataset))
	ui.show()
	gtk.main()