oops: fixed git reset usage
[ugit.git] / ugit / controllers / search.py
blobe875a2a57b15b28516fa28df6440cfcbb1f64240
1 #!/usr/bin/env python
2 import os
3 import re
4 import time
5 from PyQt4 import QtGui
7 from ugit.observer import Observer
8 from ugit.qobserver import QObserver
9 from ugit import qtutils
10 from ugit.views import SearchView
13 class SearchEngine(object):
14 def __init__(self, model):
15 self.model = model
16 self.parse = self.model.parse_rev_list
17 self.init()
18 def init(self):
19 pass
20 def get_rev_args(self):
21 max = self.model.get_max_results()
22 return { "max-count": max, "pretty": "oneline" }
23 def get_common_args(self):
24 return (self.model.get_input(),
25 self.get_rev_args())
26 def search(self):
27 if not self.validate():
28 return
29 return self.get_results()
30 def validate(self):
31 return len(self.model.get_input()) > 1
32 def get_results(self):
33 pass
35 class RevisionSearch(SearchEngine):
36 def get_results(self):
37 input, args = self.get_common_args()
38 expr = re.compile(input)
39 revs = self.parse(self.model.rev_list(all=True, **args))
40 return [ r for r in revs if expr.match(r[0]) ]
42 class RevisionRangeSearch(SearchEngine):
43 def init(self):
44 self.RE = re.compile(r'[^.]+\.\..+')
45 def validate(self):
46 return bool(self.RE.match(self.model.get_input()))
47 def get_results(self):
48 input, args = self.get_common_args()
49 return self.parse(self.model.rev_list(input, **args))
51 class PathSearch(SearchEngine):
52 def get_results(self):
53 input, args = self.get_common_args()
54 paths = ['--'] + input.split(':')
55 return self.parse(self.model.rev_list(all=True,*paths,**args))
57 class MessageSearch(SearchEngine):
58 def get_results(self):
59 input, args = self.get_common_args()
60 return self.parse(
61 self.model.rev_list(grep=input, all=True, **args))
63 class AuthorSearch(SearchEngine):
64 def get_results(self):
65 input, args = self.get_common_args()
66 return self.parse(
67 self.model.rev_list(author=input, all=True, **args))
69 class CommitterSearch(SearchEngine):
70 def get_results(self):
71 input, args = self.get_common_args()
72 return self.parse(
73 self.model.rev_list(committer=input, all=True, **args))
75 class DiffSearch(SearchEngine):
76 def get_results(self):
77 input, args = self.get_common_args()
78 return self.parse(
79 self.model.log('-S'+input, all=True, **args))
81 class DateRangeSearch(SearchEngine):
82 def validate(self):
83 return True
84 def get_results(self):
85 args = self.get_rev_args()
86 return self.parse(
87 self.model.rev_list(
88 date='iso',
89 after=self.model.get_start_date(),
90 before=self.model.get_end_date(),
91 all=True,
92 **args))
94 # Modes for this controller.
95 # Note: names correspond to radio button names for convenience
96 REVISION_ID = 'radio_revision'
97 REVISION_RANGE = 'radio_range'
98 PATH = 'radio_path'
99 MESSAGE = 'radio_message'
100 DIFF = 'radio_diff'
101 AUTHOR = 'radio_author'
102 COMMITTER = 'radio_committer'
103 DATE_RANGE = 'radio_daterange'
105 # Each search type is handled by a distinct SearchEngine subclass
106 SEARCH_ENGINES = {
107 REVISION_ID: RevisionSearch,
108 REVISION_RANGE: RevisionRangeSearch,
109 PATH: PathSearch,
110 MESSAGE: MessageSearch,
111 DIFF: DiffSearch,
112 AUTHOR: AuthorSearch,
113 COMMITTER: CommitterSearch,
114 DATE_RANGE: DateRangeSearch,
117 class SearchController(QObserver):
118 def __init__(self, model, view, mode):
119 QObserver.__init__(self, model, view)
120 self.add_observables(
121 'input',
122 'max_results',
123 'start_date',
124 'end_date',
126 self.add_actions(
127 input = self.search_callback,
128 max_results = self.search_callback,
129 start_date = self.search_callback,
130 end_date = self.search_callback,
132 self.add_callbacks(
133 # Standard buttons
134 button_search = self.search_callback,
135 button_browse = self.browse_callback,
136 commit_list = self.display_callback,
137 # Radio buttons trigger a search
138 radio_revision = self.search_callback,
139 radio_range = self.search_callback,
140 radio_message = self.search_callback,
141 radio_path = self.search_callback,
142 radio_diff = self.search_callback,
143 radio_author = self.search_callback,
144 radio_committer = self.search_callback,
145 radio_daterange = self.search_callback,
147 self.set_mode(mode)
148 self.update_fonts()
150 def update_fonts(self):
151 font = self.model.get_global_ugit_fontui()
152 if font:
153 qfont = QtGui.QFont()
154 qfont.fromString(font)
155 self.view.commit_list.setFont(qfont)
156 font = self.model.get_global_ugit_fontdiff()
157 if font:
158 qfont = QtGui.QFont()
159 qfont.fromString(font)
160 self.view.commit_text.setFont(qfont)
162 def set_mode(self, mode):
163 radio = getattr(self.view, mode)
164 radio.setChecked(True)
166 def radio_to_mode(self, radio_button):
167 return str(radio_button.objectName())
169 def get_mode(self):
170 for name in SEARCH_ENGINES:
171 radiobutton = getattr(self.view, name)
172 if radiobutton.isChecked():
173 return name
175 def search_callback(self, *args):
176 engineclass = SEARCH_ENGINES.get(self.get_mode())
177 if not engineclass:
178 print ("mode: '%s' is currently unimplemented"
179 % self.get_mode())
180 return
181 self.results = engineclass(self.model).search()
182 if self.results:
183 self.display_results()
184 else:
185 self.view.commit_list.clear()
186 self.view.commit_text.setText('')
188 def browse_callback(self):
189 paths = QtGui.QFileDialog.getOpenFileNames(
190 self.view,
191 self.tr("Choose Path(s)"))
192 if not paths:
193 return
194 filepaths = []
195 lenprefix = len(os.getcwd()) + 1
196 for path in map(lambda x: unicode(x), paths):
197 if not path.startswith(os.getcwd()):
198 continue
199 filepaths.append(path[lenprefix:])
200 input = ':'.join(filepaths)
201 self.model.set_input('')
202 self.set_mode(PATH)
203 self.model.set_input(input)
205 def display_results(self):
206 commit_list = map(lambda x: x[1], self.results)
207 self.model.set_commit_list(commit_list)
208 qtutils.set_listwidget_strings(
209 self.view.commit_list,
210 commit_list)
212 def display_callback(self, *args):
213 widget = self.view.commit_list
214 row, selected = qtutils.get_selected_row(widget)
215 if not selected or len(self.results) < row:
216 return
217 revision = self.results[row][0]
218 qtutils.set_clipboard(revision)
219 diff = self.model.get_commit_diff(revision)
220 self.view.commit_text.setText(diff)
222 def search_commits(model, mode, browse):
223 def get_date(timespec):
224 return '%04d-%02d-%02d' % time.localtime(timespec)[:3]
226 model = model.clone()
227 model.create(
228 input='',
229 max_results=500,
230 start_date='',
231 end_date='',
232 commit_list=None,
234 view = SearchView(None)
235 ctl = SearchController(model, view, mode)
236 model.set_start_date(get_date(time.time()-(87640*7)))
237 model.set_end_date(get_date(time.time()+87640))
238 view.show()
239 if browse:
240 ctl.browse_callback()