24105c196d50391811ff6570d6929417cd7c9476
[bertos.git] / wizard / BToolchainPage.py
1 #!/usr/bin/env python
2 # encoding: utf-8
3 #
4 # This file is part of BeRTOS.
5 #
6 # Bertos is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 #
20 # As a special exception, you may use this file as part of a free software
21 # library without restriction.  Specifically, if other files instantiate
22 # templates or use macros or inline functions from this file, or you compile
23 # this file and link it with other files to produce an executable, this
24 # file does not by itself cause the resulting executable to be covered by
25 # the GNU General Public License.  This exception does not however
26 # invalidate any other reasons why the executable file might be covered by
27 # the GNU General Public License.
28 #
29 # Copyright 2008 Develer S.r.l. (http://www.develer.com/)
30 #
31 # $Id$
32 #
33 # Author: Lorenzo Berni <duplo@develer.com>
34 #
35
36 import os
37 import collections
38
39 from BWizardPage import *
40 import BToolchainSearch
41 import bertos_utils
42 import qvariant_converter
43
44 from const import *
45
46 class BToolchainPage(BWizardPage):
47     """
48     Page of the wizard that permits to choose the toolchain to use for the
49     project.
50     """
51
52     def __init__(self):
53         BWizardPage.__init__(self, UI_LOCATION + "/toolchain_select.ui")
54         self.setTitle(self.tr("Select toolchain"))
55         self._validation_process = None
56         self._valid_items = []
57
58     ## Overloaded QWizardPage methods. ##
59
60     def isComplete(self):
61         """
62         Overload of the QWizard isComplete method.
63         """
64         if self.pageContent.toolchainList.currentRow() != -1:
65             self.setProjectInfo("TOOLCHAIN",
66                 qvariant_converter.getStringDict(self.pageContent.toolchainList.currentItem().data(Qt.UserRole)))
67             return True
68         else:
69             return False
70
71     ####
72
73     ## Overloaded BWizardPage methods. ##
74
75     def setupUi(self):
76         """
77         Sets up the user interface.
78         """
79         self.pageContent.infoLabel.setVisible(False)
80
81     def connectSignals(self):
82         """
83         Connects the signals with the related slots.
84         """
85         self.connect(self.pageContent.toolchainList, SIGNAL("itemSelectionChanged()"), self.selectionChanged)
86         self.connect(self.pageContent.addButton, SIGNAL("clicked()"), self.addToolchain)
87         self.connect(self.pageContent.removeButton, SIGNAL("clicked()"), self.removeToolchain)
88         self.connect(self.pageContent.searchButton, SIGNAL("clicked()"), self.searchToolchain)
89         self.connect(self.pageContent.checkButton, SIGNAL("clicked()"), self.validateAllToolchains)
90
91     def reloadData(self):
92         """
93         Overload of the BWizard reloadData method.
94         """
95         self._clearList()
96         self.setupUi()
97         self._populateToolchainList()
98         if len(self._valid_items) == 1:
99             self.pageContent.toolchainList.setCurrentItem(self._valid_items[0])
100
101     ####
102
103     ## Slots ##
104
105     def selectionChanged(self):
106         """
107         Slot called when the user click on an entry of the toolchain list.
108         """
109         if self.pageContent.toolchainList.currentRow() != -1:
110             infos = collections.defaultdict(lambda: unicode("not defined"))
111             infos.update(qvariant_converter.getStringDict(self.pageContent.toolchainList.currentItem().data(Qt.UserRole)))
112             self.pageContent.infoLabel.setText("GCC " + infos["version"] + " (" + infos["build"] + ")\nTarget: " + infos["target"] + "\nPath: " + os.path.normpath(infos["path"]))
113             self.pageContent.infoLabel.setVisible(True)
114             if self.isDefaultToolchain(infos):
115                 self.disableRemoveButton()
116             else:
117                 self.enableRemoveButton()
118             self.emit(SIGNAL("completeChanged()"))
119
120     def addToolchain(self):
121         """
122         Slot called when the user adds manually a toolchain.
123         """
124         sel_toolchain = unicode(QFileDialog.getOpenFileName(self, self.tr("Choose the toolchain"), ""))
125         if sel_toolchain != "":
126             item = QListWidgetItem(sel_toolchain)
127             item.setData(Qt.UserRole, qvariant_converter.convertStringDict({"path": sel_toolchain}))
128             self.pageContent.toolchainList.addItem(item)
129             toolchains = self.toolchains()
130             toolchains[sel_toolchain] = False
131             self.setToolchains(toolchains)
132
133     def removeToolchain(self):
134         """
135         Slot called when the user removes manually a toolchain.
136         """
137         if self.pageContent.toolchainList.currentRow() != -1:
138             item = self.pageContent.toolchainList.takeItem(self.pageContent.toolchainList.currentRow())
139             toolchain = qvariant_converter.getStringDict(item.data(Qt.UserRole))["path"]
140             toolchains = self.toolchains()
141             del toolchains[toolchain]
142             self.setToolchains(toolchains)
143
144     def searchToolchain(self):
145         """
146         Slot called when the user clicks on the 'search' button. It opens the
147         toolchain search dialog.
148         """
149         search = BToolchainSearch.BToolchainSearch()
150         self.connect(search, SIGNAL("accepted()"), self._search)
151         search.exec_()
152
153     def validateAllToolchains(self):
154         """
155         Slot called when the user clicks on the validate button. It starts the
156         toolchain validation procedure for all the toolchains.
157         """
158         QApplication.instance().setOverrideCursor(Qt.WaitCursor)
159         for i in range(self.pageContent.toolchainList.count()):
160             self.validateToolchain(i)
161         QApplication.instance().restoreOverrideCursor()
162
163     ####
164
165     def _populateToolchainList(self):
166         """
167         Fills the toolchain list with the toolchains stored in the QSettings.
168         """
169         toolchains = self.toolchains()
170         if os.name == "nt":
171             import winreg_importer
172             stored_toolchains = winreg_importer.getBertosToolchains()
173             for toolchain in stored_toolchains:
174                 toolchains[toolchain] = True
175         sel_toolchain = self.projectInfo("TOOLCHAIN")
176         for key, value in toolchains.items():
177             item = QListWidgetItem(key)
178             item.setData(Qt.UserRole, qvariant_converter.convertStringDict({"path": key}))
179             self.pageContent.toolchainList.addItem(item)
180             if sel_toolchain and sel_toolchain["path"] == key:
181                 self.pageContent.toolchainList.setCurrentItem(item)
182             if value:
183                 self.validateToolchain(self.pageContent.toolchainList.row(item))
184
185     def _clearList(self):
186         """
187         Removes all the toolchain from the list.
188         """
189         self.pageContent.toolchainList.clear()
190
191     def _search(self):
192         """
193         Searches for toolchains in the stored directories, and stores them in the
194         QSettings.
195         """
196         dir_list = self.searchDirList()
197         if self.pathSearch():
198             dir_list += [element for element in bertos_utils.getSystemPath()]
199         toolchain_list = bertos_utils.findToolchains(dir_list)
200         stored_toolchains = self.toolchains()
201         for element in toolchain_list:
202             if not element in stored_toolchains:
203                 item = QListWidgetItem(element)
204                 item.setData(Qt.UserRole, qvariant_converter.convertStringDict({"path": element}))
205                 self.pageContent.toolchainList.addItem(item)
206                 stored_toolchains[element] = False
207         self.setToolchains(stored_toolchains)
208         self.showMessage(self.tr("Toolchain search result."), self.tr("%1 toolchains founded").arg(len(stored_toolchains)))
209
210     def _validItem(self, index, infos):
211         """
212         Sets the item at index as a valid item and associates the given info to it.
213         """
214         item = self.pageContent.toolchainList.item(index)
215         new_data = qvariant_converter.getStringDict(self.pageContent.toolchainList.item(index).data(Qt.UserRole))
216         new_data.update(infos)
217         item.setData(Qt.UserRole, qvariant_converter.convertStringDict(new_data))
218         needed = self.projectInfo("CPU_INFOS")
219         if "target" in infos and infos["target"].find(needed["TOOLCHAIN"]) != -1:
220             item.setIcon(QIcon(":/images/ok.png"))
221             self._valid_items.append(item)
222         else:
223             item.setIcon(QIcon(":/images/warning.png"))
224         if "version" in infos and "target" in infos:
225             item.setText("GCC " + infos["version"] + " - " + infos["target"].strip())
226
227     def _invalidItem(self, index):
228         """
229         Sets the item at index as an invalid item.
230         """
231         item = self.pageContent.toolchainList.item(index)
232         item.setIcon(QIcon(":/images/error.png"))
233
234     def validateToolchain(self, i):
235         """
236         Toolchain validation procedure.
237         """
238         filename = qvariant_converter.getStringDict(self.pageContent.toolchainList.item(i).data(Qt.UserRole))["path"]
239         valid = False
240         info = {}
241         # Check for the other tools of the toolchain
242         for tool in TOOLCHAIN_ITEMS:
243             if os.path.exists(filename.replace("gcc", tool)):
244                 valid = True
245             else:
246                 valid = False
247                 break
248         # Try to retrieve the informations about the toolchain only for the valid toolchains
249         if valid:
250             self._validation_process = QProcess()
251             self._validation_process.start(filename, ["-v"])
252             self._validation_process.waitForStarted(1000)
253             if self._validation_process.waitForFinished(200):
254                 description = unicode(self._validation_process.readAllStandardError())
255                 info = bertos_utils.getToolchainInfo(description)
256                 if len(info) >= 4:
257                     valid = True
258             else:
259                 self._validation_process.kill()
260         # Add the item in the list with the appropriate associate data.
261         if valid:
262             self._validItem(i, info)
263         else:
264             self._invalidItem(i)
265         toolchains = self.toolchains()
266         toolchains[filename] = True
267         self.setToolchains(toolchains)
268     
269     def isDefaultToolchain(self, toolchain):
270         """
271         Returns True if the given toolchain is one of the default toolchains.
272         """
273         if os.name == "nt":
274             import winreg_importer
275             stored_toolchains = winreg_importer.getBertosToolchains()
276             if toolchain["path"] in stored_toolchains:
277                 return True
278         return False
279     
280     def disableRemoveButton(self):
281         """
282         Disable the remove button.
283         """
284         self.pageContent.removeButton.setEnabled(False)
285     
286     def enableRemoveButton(self):
287         """
288         Enable the remove button.
289         """
290         self.pageContent.removeButton.setEnabled(True)
291         
292     def currentItem(self):
293         return self.pageContent.toolchainList.currentItem()