|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2003 - 2009 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a code metrics dialog. |
|
8 """ |
|
9 |
|
10 import sys |
|
11 import os |
|
12 import types |
|
13 |
|
14 from PyQt4.QtCore import * |
|
15 from PyQt4.QtGui import * |
|
16 |
|
17 from Ui_CodeMetricsDialog import Ui_CodeMetricsDialog |
|
18 import CodeMetrics |
|
19 import Utilities |
|
20 |
|
21 class CodeMetricsDialog(QDialog, Ui_CodeMetricsDialog): |
|
22 """ |
|
23 Class implementing a dialog to display the code metrics. |
|
24 """ |
|
25 def __init__(self, parent = None): |
|
26 """ |
|
27 Constructor |
|
28 |
|
29 @param parent parent widget (QWidget) |
|
30 """ |
|
31 QDialog.__init__(self, parent) |
|
32 self.setupUi(self) |
|
33 |
|
34 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) |
|
35 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) |
|
36 |
|
37 self.summaryList.headerItem().setText(self.summaryList.columnCount(), "") |
|
38 self.summaryList.header().resizeSection(0, 200) |
|
39 self.summaryList.header().resizeSection(1, 100) |
|
40 |
|
41 self.resultList.headerItem().setText(self.resultList.columnCount(), "") |
|
42 |
|
43 self.cancelled = False |
|
44 |
|
45 self.__menu = QMenu(self) |
|
46 self.__menu.addAction(self.trUtf8("Collapse all"), self.__resultCollapse) |
|
47 self.__menu.addAction(self.trUtf8("Expand all"), self.__resultExpand) |
|
48 self.resultList.setContextMenuPolicy(Qt.CustomContextMenu) |
|
49 self.connect(self.resultList, |
|
50 SIGNAL('customContextMenuRequested(const QPoint &)'), |
|
51 self.__showContextMenu) |
|
52 |
|
53 def __resizeResultColumns(self): |
|
54 """ |
|
55 Private method to resize the list columns. |
|
56 """ |
|
57 self.resultList.header().resizeSections(QHeaderView.ResizeToContents) |
|
58 self.resultList.header().setStretchLastSection(True) |
|
59 |
|
60 def __createResultItem(self, parent, strings): |
|
61 """ |
|
62 Private slot to create a new item in the result list. |
|
63 |
|
64 @param parent parent of the new item (QTreeWidget or QTreeWidgetItem) |
|
65 @param strings strings to be displayed (list of strings) |
|
66 @return the generated item |
|
67 """ |
|
68 itm = QTreeWidgetItem(parent, strings) |
|
69 for col in range(1,7): |
|
70 itm.setTextAlignment(col, Qt.Alignment(Qt.AlignRight)) |
|
71 return itm |
|
72 |
|
73 def __resizeSummaryColumns(self): |
|
74 """ |
|
75 Private method to resize the list columns. |
|
76 """ |
|
77 self.summaryList.doItemsLayout() |
|
78 self.summaryList.header().resizeSections(QHeaderView.ResizeToContents) |
|
79 self.summaryList.header().setStretchLastSection(True) |
|
80 |
|
81 def __createSummaryItem(self, col0, col1): |
|
82 """ |
|
83 Private slot to create a new item in the summary list. |
|
84 |
|
85 @param col0 string for column 0 (string) |
|
86 @param col1 string for column 1 (string) |
|
87 """ |
|
88 itm = QTreeWidgetItem(self.summaryList, [col0, col1]) |
|
89 itm.setTextAlignment(1, Qt.Alignment(Qt.AlignRight)) |
|
90 |
|
91 def start(self, fn): |
|
92 """ |
|
93 Public slot to start the code metrics determination. |
|
94 |
|
95 @param fn file or list of files or directory to be show |
|
96 the code metrics for (string or list of strings) |
|
97 """ |
|
98 loc = QLocale() |
|
99 if type(fn) is types.ListType: |
|
100 files = fn |
|
101 elif os.path.isdir(fn): |
|
102 files = Utilities.direntries(fn, True, '*.py', False) |
|
103 else: |
|
104 files = [fn] |
|
105 files.sort() |
|
106 # check for missing files |
|
107 for f in files[:]: |
|
108 if not os.path.exists(f): |
|
109 files.remove(f) |
|
110 |
|
111 self.checkProgress.setMaximum(len(files)) |
|
112 QApplication.processEvents() |
|
113 |
|
114 total = {} |
|
115 CodeMetrics.summarize(total, 'files', len(files)) |
|
116 |
|
117 progress = 0 |
|
118 |
|
119 try: |
|
120 # disable updates of the list for speed |
|
121 self.resultList.setUpdatesEnabled(False) |
|
122 self.resultList.setSortingEnabled(False) |
|
123 |
|
124 # now go through all the files |
|
125 for file in files: |
|
126 if self.cancelled: |
|
127 return |
|
128 |
|
129 stats = CodeMetrics.analyze(file, total) |
|
130 |
|
131 v = self.__getValues(loc, stats, 'TOTAL ') |
|
132 fitm = self.__createResultItem(self.resultList, [file] + v) |
|
133 |
|
134 identifiers = stats.identifiers |
|
135 for identifier in identifiers: |
|
136 v = self.__getValues(loc, stats, identifier) |
|
137 |
|
138 self.__createResultItem(fitm, [identifier] + v) |
|
139 self.resultList.expandItem(fitm) |
|
140 |
|
141 progress += 1 |
|
142 self.checkProgress.setValue(progress) |
|
143 QApplication.processEvents() |
|
144 finally: |
|
145 # reenable updates of the list |
|
146 self.resultList.setSortingEnabled(True) |
|
147 self.resultList.setUpdatesEnabled(True) |
|
148 self.__resizeResultColumns() |
|
149 |
|
150 # now do the summary stuff |
|
151 docstrings = total['lines'] - total['comments'] - \ |
|
152 total['empty lines'] - total['non-commentary lines'] |
|
153 self.__createSummaryItem(self.trUtf8("files"), loc.toString(total['files'])) |
|
154 self.__createSummaryItem(self.trUtf8("lines"), loc.toString(total['lines'])) |
|
155 self.__createSummaryItem(self.trUtf8("bytes"), loc.toString(total['bytes'])) |
|
156 self.__createSummaryItem(self.trUtf8("comments"), loc.toString(total['comments'])) |
|
157 self.__createSummaryItem(self.trUtf8("empty lines"), |
|
158 loc.toString(total['empty lines'])) |
|
159 self.__createSummaryItem(self.trUtf8("non-commentary lines"), |
|
160 loc.toString(total['non-commentary lines'])) |
|
161 self.__createSummaryItem(self.trUtf8("documentation lines"), |
|
162 loc.toString(docstrings)) |
|
163 self.__resizeSummaryColumns() |
|
164 self.__finish() |
|
165 |
|
166 def __getValues(self, loc, stats, identifier): |
|
167 """ |
|
168 Private method to extract the code metric values. |
|
169 |
|
170 @param loc reference to the locale object (QLocale) |
|
171 @param stats reference to the code metric statistics object |
|
172 @param identifier identifier to get values for |
|
173 @return list of values suitable for display (list of strings) |
|
174 """ |
|
175 counters = stats.counters.get(identifier, {}) |
|
176 v = [] |
|
177 for key in ('start', 'end', 'lines', 'nloc', 'comments', 'empty'): |
|
178 if counters.get(key, 0): |
|
179 v.append("{0:>7}".format(loc.toString(counters[key]))) |
|
180 else: |
|
181 v.append('') |
|
182 return v |
|
183 |
|
184 def __finish(self): |
|
185 """ |
|
186 Private slot called when the action finished or the user pressed the button. |
|
187 """ |
|
188 self.cancelled = True |
|
189 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) |
|
190 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) |
|
191 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) |
|
192 |
|
193 self.resultList.header().setResizeMode(QHeaderView.Interactive) |
|
194 self.summaryList.header().setResizeMode(QHeaderView.Interactive) |
|
195 |
|
196 def on_buttonBox_clicked(self, button): |
|
197 """ |
|
198 Private slot called by a button of the button box clicked. |
|
199 |
|
200 @param button button that was clicked (QAbstractButton) |
|
201 """ |
|
202 if button == self.buttonBox.button(QDialogButtonBox.Close): |
|
203 self.close() |
|
204 elif button == self.buttonBox.button(QDialogButtonBox.Cancel): |
|
205 self.__finish() |
|
206 |
|
207 def __showContextMenu(self, coord): |
|
208 """ |
|
209 Private slot to show the context menu of the listview. |
|
210 |
|
211 @param coord the position of the mouse pointer (QPoint) |
|
212 """ |
|
213 if self.resultList.topLevelItemCount() > 0: |
|
214 self.__menu.popup(self.mapToGlobal(coord)) |
|
215 |
|
216 def __resultCollapse(self): |
|
217 """ |
|
218 Private slot to collapse all entries of the resultlist. |
|
219 """ |
|
220 for index in range(self.resultList.topLevelItemCount()): |
|
221 self.resultList.topLevelItem(index).setExpanded(False) |
|
222 |
|
223 def __resultExpand(self): |
|
224 """ |
|
225 Private slot to expand all entries of the resultlist. |
|
226 """ |
|
227 for index in range(self.resultList.topLevelItemCount()): |
|
228 self.resultList.topLevelItem(index).setExpanded(True) |