fix refactoring bug in the search dialog
[git-cola.git] / ugit / controllers / search.py
blob5e31e6b38d6929da46b93d6e58748ecffc7b175a
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):
119 self.add_observables(
120 'input',
121 'max_results',
122 'start_date',
123 'end_date',
125 self.add_actions(
126 input = self.search_callback,
127 max_results = self.search_callback,
128 start_date = self.search_callback,
129 end_date = self.search_callback,
131 self.add_callbacks(
132 # Standard buttons
133 button_search = self.search_callback,
134 button_browse = self.browse_callback,
135 commit_list = self.display_callback,
136 # Radio buttons trigger a search
137 radio_revision = self.search_callback,
138 radio_range = self.search_callback,
139 radio_message = self.search_callback,
140 radio_path = self.search_callback,
141 radio_diff = self.search_callback,
142 radio_author = self.search_callback,
143 radio_committer = self.search_callback,
144 radio_daterange = self.search_callback,
146 self.update_fonts()
148 def update_fonts(self):
149 font = self.model.get_global_ugit_fontui()
150 if font:
151 qfont = QtGui.QFont()
152 qfont.fromString(font)
153 self.view.commit_list.setFont(qfont)
154 font = self.model.get_global_ugit_fontdiff()
155 if font:
156 qfont = QtGui.QFont()
157 qfont.fromString(font)
158 self.view.commit_text.setFont(qfont)
160 def set_mode(self, mode):
161 radio = getattr(self.view, mode)
162 radio.setChecked(True)
164 def radio_to_mode(self, radio_button):
165 return str(radio_button.objectName())
167 def get_mode(self):
168 for name in SEARCH_ENGINES:
169 radiobutton = getattr(self.view, name)
170 if radiobutton.isChecked():
171 return name
173 def search_callback(self, *args):
174 engineclass = SEARCH_ENGINES.get(self.get_mode())
175 if not engineclass:
176 print ("mode: '%s' is currently unimplemented"
177 % self.get_mode())
178 return
179 self.results = engineclass(self.model).search()
180 if self.results:
181 self.display_results()
182 else:
183 self.view.commit_list.clear()
184 self.view.commit_text.setText('')
186 def browse_callback(self):
187 paths = QtGui.QFileDialog.getOpenFileNames(
188 self.view,
189 self.tr("Choose Path(s)"))
190 if not paths:
191 return
192 filepaths = []
193 lenprefix = len(os.getcwd()) + 1
194 for path in map(lambda x: unicode(x), paths):
195 if not path.startswith(os.getcwd()):
196 continue
197 filepaths.append(path[lenprefix:])
198 input = ':'.join(filepaths)
199 self.model.set_input('')
200 self.set_mode(PATH)
201 self.model.set_input(input)
203 def display_results(self):
204 commit_list = map(lambda x: x[1], self.results)
205 self.model.set_commit_list(commit_list)
206 qtutils.set_listwidget_strings(
207 self.view.commit_list,
208 commit_list)
210 def display_callback(self, *args):
211 widget = self.view.commit_list
212 row, selected = qtutils.get_selected_row(widget)
213 if not selected or len(self.results) < row:
214 return
215 revision = self.results[row][0]
216 qtutils.set_clipboard(revision)
217 diff = self.model.get_commit_diff(revision)
218 self.view.commit_text.setText(diff)
220 def search_commits(model, mode, browse):
221 def get_date(timespec):
222 return '%04d-%02d-%02d' % time.localtime(timespec)[:3]
224 model = model.clone()
225 model.create(
226 input='',
227 max_results=500,
228 start_date='',
229 end_date='',
230 commit_list=None,
232 view = SearchView(None)
233 ctl = SearchController(model, view)
234 ctl.set_mode(mode)
235 model.set_start_date(get_date(time.time()-(87640*7)))
236 model.set_end_date(get_date(time.time()+87640))
237 view.show()
238 if browse:
239 ctl.browse_callback()