summaryrefslogtreecommitdiffstats
path: root/awlsim/gui/projectwidget.py
blob: aadb8d9e64f3146bcd0abda984d1d8222740c205 (plain)
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
# -*- coding: utf-8 -*-
#
# AWL simulator - GUI project widget
#
# Copyright 2014 Michael Buesch <m@bues.ch>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 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.
#

from __future__ import division, absolute_import, print_function, unicode_literals
from awlsim.common.compat import *

from awlsim.common.templates import *

from awlsim.gui.util import *
from awlsim.gui.sourcetabs import *


class TemplateDialog(QDialog):
	def __init__(self, blockName, verboseBlockName=None, extra=None, parent=None):
		QDialog.__init__(self, parent)
		self.setLayout(QGridLayout())

		if not verboseBlockName:
			verboseBlockName = blockName

		self.setWindowTitle("Insert %s template" % verboseBlockName)

		label = QLabel("Insert %s template." % verboseBlockName, self)
		self.layout().addWidget(label, 0, 0, 1, 2)

		label = QLabel("%s number:" % verboseBlockName, self)
		self.layout().addWidget(label, 1, 0)
		self.blockNr = QSpinBox(self)
		self.blockNr.setMinimum(1)
		self.blockNr.setMaximum(0xFFFF)
		self.blockNr.setValue(1)
		self.blockNr.setPrefix(blockName + " ")
		self.layout().addWidget(self.blockNr, 1, 1)

		if extra:
			label = QLabel("%s number:" % extra, self)
			self.layout().addWidget(label, 2, 0)
			self.extraNr = QSpinBox(self)
			self.extraNr.setMinimum(1)
			self.extraNr.setMaximum(0xFFFF)
			self.extraNr.setValue(1)
			self.extraNr.setPrefix(extra + " ")
			self.layout().addWidget(self.extraNr, 2, 1)

		self.verbose = QCheckBox("Generate verbose code", self)
		self.verbose.setCheckState(Qt.Checked)
		self.layout().addWidget(self.verbose, 3, 0, 1, 2)

		self.okButton = QPushButton("&Paste code", self)
		self.layout().addWidget(self.okButton, 4, 0, 1, 2)

		self.okButton.released.connect(self.accept)

	def getBlockNumber(self):
		return self.blockNr.value()

	def getExtraNumber(self):
		return self.extraNr.value()

	def getVerbose(self):
		return self.verbose.checkState() == Qt.Checked

class ProjectWidget(QTabWidget):
	# Signal: Some source changed
	codeChanged = Signal()
	# Signal: Some symbol table changed
	symTabChanged = Signal()
	# Signal: The visible AWL line range changed
	#         Parameters are: source, visibleFromLine, visibleToLine
	visibleLinesChanged = Signal(AwlSource, int, int)

	def __init__(self, parent=None):
		QTabWidget.__init__(self, parent)

		self.awlTabs = AwlSourceTabWidget(self)
		self.symTabs = SymSourceTabWidget(self)

		self.addTab(self.awlTabs, "Sources")
		self.addTab(self.symTabs, "Symbol tables")
		self.setTabToolTip(0, "Enter your AWL/STL program here")
		self.setTabToolTip(1, "Enter your symbol table here")

		self.reset()

		self.awlTabs.sourceChanged.connect(self.codeChanged)
		self.symTabs.sourceChanged.connect(self.symTabChanged)
		self.awlTabs.visibleLinesChanged.connect(self.visibleLinesChanged)

	def handleOnlineDiagChange(self, enabled):
		self.awlTabs.handleOnlineDiagChange(enabled)

	def handleInsnDump(self, insnDumpMsg):
		self.awlTabs.handleInsnDump(insnDumpMsg)

	def updateRunState(self, newRunState):
		self.awlTabs.updateRunState(newRunState)
		self.symTabs.updateRunState(newRunState)

	def getProject(self):
		"""Returns the project description object (class Project).
		Do _not_ use awlSources and symTabs from this project!"""
		return self.__project

	def getAwlSources(self):
		"Returns a list of AwlSource()s"
		return self.awlTabs.getSources()

	def getSymTabSources(self):
		"Returns a list of SymTabSource()s"
		return self.symTabs.getSources()

	def reset(self):
		self.__project = Project(None) # Empty project
		self.__isAdHocProject = False
		self.__warnedFileBacked = False
		self.awlTabs.reset()
		self.symTabs.reset()

	def __loadProject(self, project):
		self.__project = project
		self.awlTabs.setSources(self.__project.getAwlSources())
		self.symTabs.setSources(self.__project.getSymTabSources())
		self.__warnedFileBacked = False

	def __loadPlainAwlSource(self, filename):
		project = Project(None) # Create an ad-hoc project
		srcs = [ AwlSource.fromFile(identNr = AwlSource.newIdentNr(),
					    name = filename,
					    filepath = filename), ]
		project.setAwlSources(srcs)
		self.__loadProject(project)
		self.__isAdHocProject = True
		QMessageBox.information(self,
			"Opened plain AWL/STL file",
			"The plain AWL/STL source file \n'%s'\n has sucessfully "
			"been opened.\n\n"
			"If you click on 'save', you will be asked to create "
			"a project file for this source." % filename)

	def loadProjectFile(self, filename):
		if Project.fileIsProject(filename):
			self.__loadProject(Project.fromFile(filename))
		else:
			# This might be a plain AWL-file.
			# Try to load it.
			self.__loadPlainAwlSource(filename)
		return 1

	def saveProjectFile(self, filename):
		if self.__isAdHocProject:
			srcs = self.__project.getAwlSources()
			assert(len(srcs) == 1)
			if filename == srcs[0].filepath:
				# This is an ad-hoc project, that was created from
				# a plain AWL file. Do not overwrite the AWL file.
				# Ask the user to create an .awlpro file.
				res = QMessageBox.question(self,
					"Create Awlsim project file?",
					"The current project was created ad-hoc from a "
					"plain AWL/STL file.\n"
					"Can not save without creating a project file.\n\n"
					"Do you want to create a project file?",
					QMessageBox.Yes, QMessageBox.No)
				if res != QMessageBox.Yes:
					return 0
				# The user has to choose a new project file name.
				# Signal this to our caller.
				return -1
		awlSrcs = self.getAwlSources()
		symTabSrcs = self.getSymTabSources()
		if not all(awlSrcs) or not all(symTabSrcs):
			# Failed to generate some sources
			return 0
		if (any(src.isFileBacked() for src in awlSrcs) or\
		    any(src.isFileBacked() for src in symTabSrcs)) and\
		    not self.__warnedFileBacked:
			QMessageBox.information(self,
				"Project contains external sources",
				"The project contains external sources.\n"
				"It is strongly recommended to integrate "
				"external sources into the project.\n"
				"Click on 'integrate source into project' "
				"in the source menu.")
			self.__warnedFileBacked = True
		self.__project.setAwlSources(awlSrcs)
		self.__project.setSymTabSources(symTabSrcs)
		self.__project.setProjectFile(filename)
		self.__project.toFile()
		if self.__isAdHocProject:
			# We got converted to a real project. Update the tabs.
			self.awlTabs.setSources(self.__project.getAwlSources())
			self.symTabs.setSources(self.__project.getSymTabSources())
			self.__isAdHocProject = False
		return 1

	def __pasteAwlText(self, text):
		if self.currentWidget() == self.awlTabs:
			self.awlTabs.pasteText(text)
		else:
			QMessageBox.information(self,
				"Please select AWL/STL source",
				"Can not paste template.\n\n"
				"Please move the text cursor to the place "
				"in the AWL/STL code where you want to paste "
				"the template to.")

	def insertOB(self):
		dlg = TemplateDialog("OB", parent=self)
		if dlg.exec_() == QDialog.Accepted:
			self.__pasteAwlText(Templates.getOB(dlg.getBlockNumber(),
							    dlg.getVerbose()))

	def insertFC(self):
		dlg = TemplateDialog("FC", parent=self)
		if dlg.exec_() == QDialog.Accepted:
			self.__pasteAwlText(Templates.getFC(dlg.getBlockNumber(),
							    dlg.getVerbose()))

	def insertFB(self):
		dlg = TemplateDialog("FB", parent=self)
		if dlg.exec_() == QDialog.Accepted:
			self.__pasteAwlText(Templates.getFB(dlg.getBlockNumber(),
							    dlg.getVerbose()))

	def insertInstanceDB(self):
		dlg = TemplateDialog("DB", "Instance-DB", extra="FB", parent=self)
		if dlg.exec_() == QDialog.Accepted:
			self.__pasteAwlText(Templates.getInstanceDB(dlg.getBlockNumber(),
								    dlg.getExtraNumber(),
								    dlg.getVerbose()))

	def insertGlobalDB(self):
		dlg = TemplateDialog("DB", parent=self)
		if dlg.exec_() == QDialog.Accepted:
			self.__pasteAwlText(Templates.getGlobalDB(dlg.getBlockNumber(),
								  dlg.getVerbose()))

	def insertFCcall(self):
		dlg = TemplateDialog("FC", "FC call", parent=self)
		if dlg.exec_() == QDialog.Accepted:
			self.__pasteAwlText(Templates.getFCcall(dlg.getBlockNumber(),
								dlg.getVerbose()))

	def insertFBcall(self):
		dlg = TemplateDialog("FB", "FB call", extra="DB", parent=self)
		if dlg.exec_() == QDialog.Accepted:
			self.__pasteAwlText(Templates.getFBcall(dlg.getBlockNumber(),
								dlg.getExtraNumber(),
								dlg.getVerbose()))
bues.ch cgit interface