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