Fix typo.
[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 from BOutputPage import BOutputPage
41
42 import BToolchainSearch
43 import bertos_utils
44 import qvariant_converter
45
46 from toolchain_manager import ToolchainManager
47
48 from const import *
49
50 class BToolchainPage(BWizardPage):
51     """
52     Page of the wizard that permits to choose the toolchain to use for the
53     project.
54     """
55
56     def __init__(self):
57         BWizardPage.__init__(self, UI_LOCATION + "/toolchain_select.ui")
58         self.setTitle(self.tr("Select toolchain"))
59         self._validation_process = None
60         self._valid_items = []
61         self._toolchain_manager = ToolchainManager()
62
63     ## Overloaded QWizardPage methods. ##
64
65     def isComplete(self):
66         """
67         Overload of the QWizard isComplete method.
68         """
69         if self.pageContent.toolchainList.currentRow() != -1:
70             self.setProjectInfo("TOOLCHAIN",
71                 qvariant_converter.getStringDict(self.pageContent.toolchainList.currentItem().data(Qt.UserRole)))
72             return True
73         else:
74             return False
75
76     def nextId(self):
77         """
78         Overload of the QWizardPage nextId method.
79         """
80         # Route to Output page if it's a predefined easy project.
81         if self.projectInfo("PROJECT_FROM_PRESET") and self.projectInfo("BASE_MODE"):
82             return self.wizard().pageIndex(BOutputPage)
83         else:
84             return QWizardPage.nextId(self)
85
86     ####
87
88     ## Overloaded BWizardPage methods. ##
89
90     def setupUi(self):
91         """
92         Sets up the user interface.
93         """
94         self.pageContent.infoLabel.setVisible(False)
95
96     def connectSignals(self):
97         """
98         Connects the signals with the related slots.
99         """
100         self.connect(self.pageContent.toolchainList, SIGNAL("itemSelectionChanged()"), self.selectionChanged)
101         self.connect(self.pageContent.addButton, SIGNAL("clicked()"), self.addToolchain)
102         self.connect(self.pageContent.removeButton, SIGNAL("clicked()"), self.removeToolchain)
103         self.connect(self.pageContent.searchButton, SIGNAL("clicked()"), self.searchToolchain)
104         self.connect(self.pageContent.checkButton, SIGNAL("clicked()"), self.validateAllToolchains)
105
106     def reloadData(self):
107         """
108         Overload of the BWizard reloadData method.
109         """
110         self._clearList()
111         self.setupUi()
112         self._populateToolchainList()
113         if len(self._valid_items) == 1:
114             self.pageContent.toolchainList.setCurrentItem(self._valid_items[0])
115
116     ####
117
118     ## Slots ##
119
120     def selectionChanged(self):
121         """
122         Slot called when the user click on an entry of the toolchain list.
123         """
124         if self.pageContent.toolchainList.currentRow() != -1:
125             infos = collections.defaultdict(lambda: unicode("not defined"))
126             infos.update(qvariant_converter.getStringDict(self.pageContent.toolchainList.currentItem().data(Qt.UserRole)))
127             self.pageContent.infoLabel.setText("GCC " + infos["version"] + " (" + infos["build"] + ")\nTarget: " + infos["target"] + "\nPath: " + os.path.normpath(infos["path"]))
128             self.pageContent.infoLabel.setVisible(True)
129             if self.isDefaultToolchain(infos):
130                 self.disableRemoveButton()
131             else:
132                 self.enableRemoveButton()
133             self.emit(SIGNAL("completeChanged()"))
134
135     def addToolchain(self):
136         """
137         Slot called when the user adds manually a toolchain.
138         """
139         sel_toolchain = unicode(QFileDialog.getOpenFileName(self, self.tr("Choose the toolchain"), ""))
140         if sel_toolchain != "":
141             item = QListWidgetItem(sel_toolchain)
142             item.setData(Qt.UserRole, qvariant_converter.convertStringDict({"path": sel_toolchain}))
143             self.pageContent.toolchainList.addItem(item)
144             self._toolchain_manager.addToolchain(sel_toolchain)
145
146     def removeToolchain(self):
147         """
148         Slot called when the user removes manually a toolchain.
149         """
150         if self.pageContent.toolchainList.currentRow() != -1:
151             item = self.pageContent.toolchainList.takeItem(self.pageContent.toolchainList.currentRow())
152             toolchain = qvariant_converter.getStringDict(item.data(Qt.UserRole))["path"]
153             self._toolchain_manager.removeToolchain(toolchain)
154
155     def searchToolchain(self):
156         """
157         Slot called when the user clicks on the 'search' button. It opens the
158         toolchain search dialog.
159         """
160         search = BToolchainSearch.BToolchainSearch()
161         self.connect(search, SIGNAL("accepted()"), self._search)
162         search.exec_()
163
164     def validateAllToolchains(self):
165         """
166         Slot called when the user clicks on the validate button. It starts the
167         toolchain validation procedure for all the toolchains.
168         """
169         try:
170             QApplication.instance().setOverrideCursor(Qt.WaitCursor)
171             for i in range(self.pageContent.toolchainList.count()):
172                 self.validateToolchain(i)
173         finally:
174             QApplication.instance().restoreOverrideCursor()
175
176     ####
177
178     def _populateToolchainList(self):
179         """
180         Fills the toolchain list with the toolchains stored in the QSettings.
181         """
182         self.pageContent.toolchainList.clear()
183         toolchains = self._toolchain_manager.predefined_toolchains + self._toolchain_manager.toolchains
184         sel_toolchain = self.projectInfo("TOOLCHAIN")
185         for key, value in toolchains:
186             if os.path.exists(key):
187                 item = QListWidgetItem(key)
188                 item_data = {"path":key}
189                 if value:
190                     item_data.update(value)
191                 item.setData(Qt.UserRole, qvariant_converter.convertStringDict(item_data))
192                 self.pageContent.toolchainList.addItem(item)
193                 if sel_toolchain and sel_toolchain["path"] == key:
194                     self.pageContent.toolchainList.setCurrentItem(item)
195                 if value is not None:
196                     self.validateToolchain(self.pageContent.toolchainList.row(item))
197
198     def currentToolchain(self):
199         selected_toolchain = qvariant_converter.getStringDict(self.pageContent.toolchainList.currentItem().data(Qt.UserRole))
200         return selected_toolchain
201
202     def _clearList(self):
203         """
204         Removes all the toolchain from the list.
205         """
206         self.pageContent.toolchainList.clear()
207
208     def _search(self):
209         """
210         Searches for toolchains in the stored directories, and stores them in the
211         QSettings.
212         """
213         dir_list = self.searchDirList()
214         if self.pathSearch():
215             dir_list += [element for element in bertos_utils.getSystemPath()]
216         _toolchain_dict = self._toolchain_manager.storedToolchainDict()
217         toolchain_list = bertos_utils.findToolchains(dir_list)
218         for toolchain in toolchain_list:
219             self._toolchain_manager.addToolchain(toolchain, _toolchain_dict.get(toolchain, False))
220         self._populateToolchainList()
221         self.showMessage(self.tr("Toolchain search result."), self.tr("%1 toolchains found").arg(len(self._toolchain_manager.toolchains)))
222
223     def _validItem(self, index, infos):
224         """
225         Sets the item at index as a valid item and associates the given info to it.
226         """
227         item = self.pageContent.toolchainList.item(index)
228         new_data = qvariant_converter.getStringDict(self.pageContent.toolchainList.item(index).data(Qt.UserRole))
229         new_data.update(infos)
230         item.setData(Qt.UserRole, qvariant_converter.convertStringDict(new_data))
231         needed = self.projectInfo("CPU_INFOS")
232         if "target" in infos and infos["target"].find(needed["TOOLCHAIN"]) != -1:
233             item.setIcon(QIcon(":/images/ok.png"))
234             self._valid_items.append(item)
235         else:
236             item.setIcon(QIcon(":/images/warning.png"))
237         if "version" in infos and "target" in infos:
238             item.setText("GCC " + infos["version"] + " - " + infos["target"].strip())
239
240     def _invalidItem(self, index):
241         """
242         Sets the item at index as an invalid item.
243         """
244         item = self.pageContent.toolchainList.item(index)
245         item.setIcon(QIcon(":/images/error.png"))
246
247     def validateToolchain(self, i):
248         """
249         Toolchain validation procedure.
250         """
251         filename = qvariant_converter.getStringDict(self.pageContent.toolchainList.item(i).data(Qt.UserRole))["path"]
252         info = self._toolchain_manager.validateToolchain(filename)
253
254         # Add the item in the list with the appropriate associate data.
255         if info:
256             self._validItem(i, info)
257         else:
258             self._invalidItem(i)
259     
260     def isDefaultToolchain(self, toolchain):
261         """
262         Returns True if the given toolchain is one of the default toolchains.
263         """
264         return toolchain["path"] in self._toolchain_manager._predefined_toolchain_set
265     
266     def disableRemoveButton(self):
267         """
268         Disable the remove button.
269         """
270         self.pageContent.removeButton.setEnabled(False)
271     
272     def enableRemoveButton(self):
273         """
274         Enable the remove button.
275         """
276         self.pageContent.removeButton.setEnabled(True)
277         
278     def currentItem(self):
279         return self.pageContent.toolchainList.currentItem()