mdi_pychecker.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. ######################################################################
  2. ##
  3. ## The Pychecker MDI Plug-In UserModule for Pythonwin
  4. ##
  5. ## contributed by Robert Kiendl
  6. ##
  7. ## Style is similar to (and inherited) from the SGrepMDI UserModule
  8. ##
  9. ## Usage:
  10. ##
  11. ## Start Pychecker on current file: Menu/File/New../Pychecker.
  12. ## Use it: Jump to Pychecker warning source lines by double-click.
  13. ## Auto-add "#$pycheck_no" / "#$pycheck_no=specific-re-pattern" tags
  14. ## to source lines by context/right-mouse-click on warning lines.
  15. ##
  16. ## It requires pychecker installed and the pychecker.bat to be on
  17. ## the PATH. Example pychecker.bat:
  18. ##
  19. ## REM pychecker.bat
  20. ## C:\bin\python.exe C:\PYTHON23\Lib\site-packages\pychecker\checker.py %1 %2 %3 %4 %5 %6 %7 %8 %9
  21. ##
  22. ## Adding it as default module in PythonWin:
  23. ##
  24. ## +++ ./intpyapp.py 2006-10-02 17:59:32.974161600 +0200
  25. ## @@ -272,7 +282,7 @@
  26. ## def LoadUserModules(self, moduleNames = None):
  27. ## # Load the users modules.
  28. ## if moduleNames is None:
  29. ## - default = "sgrepmdi"
  30. ## + default = "sgrepmdi,mdi_pychecker"
  31. ## moduleNames=win32ui.GetProfileVal('Python','Startup Modules',default)
  32. ## self.DoLoadModules(moduleNames)
  33. ##
  34. ######################################################################
  35. import win32ui
  36. import win32api
  37. from pywin.mfc import docview, dialog, window
  38. import win32con
  39. import sys, string, re, glob, os, stat, time
  40. import scriptutils
  41. def getsubdirs(d):
  42. dlist = []
  43. flist = glob.glob(d+'\\*')
  44. for f in flist:
  45. if os.path.isdir(f):
  46. dlist.append(f)
  47. dlist = dlist + getsubdirs(f)
  48. return dlist
  49. class dirpath:
  50. def __init__(self, str, recurse=0):
  51. dp = str.split(';')
  52. dirs = {}
  53. for d in dp:
  54. if os.path.isdir(d):
  55. d = d.lower()
  56. if d not in dirs:
  57. dirs[d] = None
  58. if recurse:
  59. subdirs = getsubdirs(d)
  60. for sd in subdirs:
  61. sd = sd.lower()
  62. if sd not in dirs:
  63. dirs[sd] = None
  64. elif os.path.isfile(d):
  65. pass
  66. else:
  67. x = None
  68. if d in os.environ:
  69. x = dirpath(os.environ[d])
  70. elif d[:5] == 'HKEY_':
  71. keystr = d.split('\\')
  72. try:
  73. root = eval('win32con.'+keystr[0])
  74. except:
  75. win32ui.MessageBox("Can't interpret registry key name '%s'" % keystr[0])
  76. try:
  77. subkey = '\\'.join(keystr[1:])
  78. val = win32api.RegQueryValue(root, subkey)
  79. if val:
  80. x = dirpath(val)
  81. else:
  82. win32ui.MessageBox("Registry path '%s' did not return a path entry" % d)
  83. except:
  84. win32ui.MessageBox("Can't interpret registry key value: %s" % keystr[1:])
  85. else:
  86. win32ui.MessageBox("Directory '%s' not found" % d)
  87. if x:
  88. for xd in x:
  89. if xd not in dirs:
  90. dirs[xd] = None
  91. if recurse:
  92. subdirs = getsubdirs(xd)
  93. for sd in subdirs:
  94. sd = sd.lower()
  95. if sd not in dirs:
  96. dirs[sd] = None
  97. self.dirs = []
  98. for d in dirs.iterkeys():
  99. self.dirs.append(d)
  100. def __getitem__(self, key):
  101. return self.dirs[key]
  102. def __len__(self):
  103. return len(self.dirs)
  104. def __setitem__(self, key, value):
  105. self.dirs[key] = value
  106. def __delitem__(self, key):
  107. del self.dirs[key]
  108. def __getslice__(self, lo, hi):
  109. return self.dirs[lo:hi]
  110. def __setslice__(self, lo, hi, seq):
  111. self.dirs[lo:hi] = seq
  112. def __delslice__(self, lo, hi):
  113. del self.dirs[lo:hi]
  114. def __add__(self, other):
  115. if type(other) == type(self) or type(other) == type([]):
  116. return self.dirs + other.dirs
  117. def __radd__(self, other):
  118. if type(other) == type(self) or type(other) == type([]):
  119. return other.dirs + self.dirs
  120. # Group(1) is the filename, group(2) is the lineno.
  121. #regexGrepResult=regex.compile("^\\([a-zA-Z]:.*\\)(\\([0-9]+\\))")
  122. #regexGrep=re.compile(r"^([a-zA-Z]:[^(]*)\((\d+)\)")
  123. regexGrep=re.compile(r"^(..[^\(:]+)?[\(:](\d+)[\):]:?\s*(.*)")
  124. #these are the atom numbers defined by Windows for basic dialog controls
  125. BUTTON = 0x80
  126. EDIT = 0x81
  127. STATIC = 0x82
  128. LISTBOX = 0x83
  129. SCROLLBAR = 0x84
  130. COMBOBOX = 0x85
  131. class TheTemplate(docview.RichEditDocTemplate):
  132. def __init__(self):
  133. docview.RichEditDocTemplate.__init__(self, win32ui.IDR_TEXTTYPE, TheDocument, TheFrame, TheView)
  134. self.SetDocStrings("\nPychecker\nPychecker\nPychecker params (*.pychecker)\n.pychecker\n\n\n")
  135. win32ui.GetApp().AddDocTemplate(self)
  136. self.docparams = None
  137. def MatchDocType(self, fileName, fileType):
  138. doc = self.FindOpenDocument(fileName)
  139. if doc: return doc
  140. ext = os.path.splitext(fileName)[1].lower()
  141. if ext =='.pychecker':
  142. return win32ui.CDocTemplate_Confidence_yesAttemptNative
  143. return win32ui.CDocTemplate_Confidence_noAttempt
  144. def setParams(self, params):
  145. self.docparams = params
  146. def readParams(self):
  147. tmp = self.docparams
  148. self.docparams = None
  149. return tmp
  150. class TheFrame(window.MDIChildWnd):
  151. # The template and doc params will one day be removed.
  152. def __init__(self, wnd = None):
  153. window.MDIChildWnd.__init__(self, wnd)
  154. class TheDocument(docview.RichEditDoc):
  155. def __init__(self, template):
  156. docview.RichEditDoc.__init__(self, template)
  157. self.dirpattern = ''
  158. self.filpattern = ''
  159. self.greppattern = ''
  160. self.casesensitive = 1
  161. self.recurse = 1
  162. self.verbose = 0
  163. def OnOpenDocument(self, fnm):
  164. #this bizarre stuff with params is so right clicking in a result window
  165. #and starting a new grep can communicate the default parameters to the
  166. #new grep.
  167. try:
  168. params = open(fnm,'r').read()
  169. except:
  170. params = None
  171. self.setInitParams(params)
  172. return self.OnNewDocument()
  173. def OnCloseDocument(self):
  174. try:
  175. win32ui.GetApp().DeleteIdleHandler(self.idleHandler)
  176. except:
  177. pass
  178. return self._obj_.OnCloseDocument()
  179. def saveInitParams(self):
  180. # Only save the flags, not the text boxes.
  181. paramstr = "\t\t\t%d\t%d" % (self.casesensitive, self.recurse)
  182. win32ui.WriteProfileVal("Pychecker", "Params", paramstr)
  183. def setInitParams(self, paramstr):
  184. if paramstr is None:
  185. paramstr = win32ui.GetProfileVal("Pychecker", "Params", '\t\t\t1\t0\t0')
  186. params = paramstr.split('\t')
  187. if len(params) < 3:
  188. params = params + ['']*(3-len(params))
  189. if len(params) < 6:
  190. params = params + [0]*(6-len(params))
  191. self.dirpattern = params[0]
  192. self.filpattern = params[1]
  193. self.greppattern = params[2] or '-#1000 --only'
  194. self.casesensitive = int(params[3])
  195. self.recurse = int(params[4])
  196. self.verbose = int(params[5])
  197. # setup some reasonable defaults.
  198. if not self.dirpattern:
  199. try:
  200. editor=win32ui.GetMainFrame().MDIGetActive()[0].GetEditorView()
  201. self.dirpattern=os.path.abspath(os.path.dirname(editor.GetDocument().GetPathName()))
  202. except (AttributeError,win32ui.error):
  203. self.dirpattern = os.getcwd()
  204. if not self.filpattern:
  205. try:
  206. editor=win32ui.GetMainFrame().MDIGetActive()[0].GetEditorView()
  207. self.filpattern=editor.GetDocument().GetPathName()
  208. except AttributeError:
  209. self.filpattern = "*.py"
  210. def OnNewDocument(self):
  211. if self.dirpattern == '':
  212. self.setInitParams(greptemplate.readParams())
  213. d = TheDialog(self.dirpattern, self.filpattern, self.greppattern, self.casesensitive, self.recurse, self.verbose)
  214. if d.DoModal() == win32con.IDOK:
  215. self.dirpattern = d['dirpattern']
  216. self.filpattern = d['filpattern']
  217. self.greppattern = d['greppattern']
  218. #self.casesensitive = d['casesensitive']
  219. #self.recurse = d['recursive']
  220. #self.verbose = d['verbose']
  221. self.doSearch()
  222. self.saveInitParams()
  223. return 1
  224. return 0 # cancelled - return zero to stop frame creation.
  225. def doSearch(self):
  226. self.dp = dirpath(self.dirpattern, self.recurse)
  227. self.SetTitle("Pychecker Run '%s' (options: %s)" % (self.filpattern, self.greppattern))
  228. #self.text = []
  229. self.GetFirstView().Append('#Pychecker Run in '+self.dirpattern+' %s\n'%time.asctime())
  230. if self.verbose:
  231. self.GetFirstView().Append('# ='+repr(self.dp.dirs)+'\n')
  232. self.GetFirstView().Append('# Files '+self.filpattern+'\n')
  233. self.GetFirstView().Append('# Options '+self.greppattern+'\n')
  234. self.fplist = self.filpattern.split(';')
  235. self.GetFirstView().Append('# Running... ( double click on result lines in order to jump to the source code ) \n')
  236. win32ui.SetStatusText("Pychecker running. Please wait...", 0)
  237. self.dpndx = self.fpndx = 0
  238. self.fndx = -1
  239. if not self.dp:
  240. self.GetFirstView().Append("# ERROR: '%s' does not resolve to any search locations" % self.dirpattern)
  241. self.SetModifiedFlag(0)
  242. else:
  243. ##self.flist = glob.glob(self.dp[0]+'\\'+self.fplist[0])
  244. import operator
  245. self.flist = reduce(operator.add, list(map(glob.glob,self.fplist)) )
  246. #import pywin.debugger;pywin.debugger.set_trace()
  247. self.startPycheckerRun()
  248. def idleHandler(self,handler,count):
  249. import time
  250. time.sleep(0.001)
  251. if self.result!=None:
  252. win32ui.GetApp().DeleteIdleHandler(self.idleHandler)
  253. return 0
  254. return 1 #more
  255. def startPycheckerRun(self):
  256. self.result=None
  257. old=win32api.SetCursor(win32api.LoadCursor(0, win32con.IDC_APPSTARTING))
  258. win32ui.GetApp().AddIdleHandler(self.idleHandler)
  259. import thread
  260. thread.start_new(self.threadPycheckerRun,())
  261. ##win32api.SetCursor(old)
  262. def threadPycheckerRun(self):
  263. result=''
  264. rc=-1
  265. try:
  266. options = self.greppattern
  267. files= ' '.join(self.flist)
  268. # Recently MarkH has failed to run pychecker without it having
  269. # been explicitly installed - so we assume it is and locate it
  270. # from its default location.
  271. # Step1 - get python.exe
  272. py = os.path.join(sys.prefix, 'python.exe')
  273. if not os.path.isfile(py):
  274. if "64 bit" in sys.version:
  275. py = os.path.join(sys.prefix, 'PCBuild', 'amd64', 'python.exe')
  276. else:
  277. py = os.path.join(sys.prefix, 'PCBuild', 'python.exe')
  278. try:
  279. py = win32api.GetShortPathName(py)
  280. except win32api.error:
  281. py = ""
  282. # Find checker.py
  283. from distutils.sysconfig import get_python_lib
  284. pychecker = os.path.join(get_python_lib(), 'pychecker', 'checker.py')
  285. if not os.path.isfile(py):
  286. result = "Can't find python.exe!\n"
  287. elif not os.path.isfile(pychecker):
  288. result = "Can't find checker.py - please install pychecker " \
  289. "(or run 'setup.py install' if you have the source version)\n"
  290. else:
  291. cmd='%s "%s" %s %s 2>&1' % (py, pychecker, options,files)
  292. ##fin,fout,ferr=os.popen3(cmd)
  293. ##result=ferr.read()+fout.read()
  294. result=os.popen(cmd).read()
  295. ##rc=f.close()
  296. self.GetFirstView().Append(result)
  297. finally:
  298. self.result=result
  299. print '== Pychecker run finished =='
  300. self.GetFirstView().Append('\n'+'== Pychecker run finished ==')
  301. self.SetModifiedFlag(0)
  302. def _inactive_idleHandler(self, handler, count):
  303. self.fndx = self.fndx + 1
  304. if self.fndx < len(self.flist):
  305. f = self.flist[self.fndx]
  306. if self.verbose:
  307. self.GetFirstView().Append('# ..'+f+'\n')
  308. win32ui.SetStatusText("Searching "+f, 0)
  309. lines = open(f, 'r').readlines()
  310. for i in range(len(lines)):
  311. line = lines[i]
  312. if self.pat.search(line) != None:
  313. self.GetFirstView().Append(f+'('+repr(i+1) + ') '+line)
  314. else:
  315. self.fndx = -1
  316. self.fpndx = self.fpndx + 1
  317. if self.fpndx < len(self.fplist):
  318. self.flist = glob.glob(self.dp[self.dpndx] + '\\' + self.fplist[self.fpndx])
  319. else:
  320. self.fpndx = 0
  321. self.dpndx = self.dpndx + 1
  322. if self.dpndx < len(self.dp):
  323. self.flist = glob.glob(self.dp[self.dpndx] + '\\' + self.fplist[self.fpndx])
  324. else:
  325. win32ui.SetStatusText("Search complete.", 0)
  326. self.SetModifiedFlag(0) # default to not modified.
  327. try:
  328. win32ui.GetApp().DeleteIdleHandler(self.idleHandler)
  329. except:
  330. pass
  331. return 0
  332. return 1
  333. def GetParams(self):
  334. return self.dirpattern+'\t'+self.filpattern+'\t'+self.greppattern+'\t'+repr(self.casesensitive)+'\t'+repr(self.recurse)+'\t'+repr(self.verbose)
  335. def OnSaveDocument(self, filename):
  336. # print 'OnSaveDocument() filename=',filename
  337. savefile = open(filename,"wb")
  338. txt = self.GetParams()+'\n'
  339. # print 'writing',txt
  340. savefile.write(txt)
  341. savefile.close()
  342. self.SetModifiedFlag(0)
  343. return 1
  344. ID_OPEN_FILE = 0xe500
  345. ID_PYCHECKER = 0xe501
  346. ID_SAVERESULTS = 0x502
  347. ID_TRYAGAIN = 0x503
  348. ID_ADDCOMMENT = 0x504
  349. ID_ADDPYCHECKNO2 = 0x505
  350. class TheView(docview.RichEditView):
  351. def __init__(self, doc):
  352. docview.RichEditView.__init__(self, doc)
  353. self.SetWordWrap(win32ui.CRichEditView_WrapNone)
  354. self.HookHandlers()
  355. def OnInitialUpdate(self):
  356. rc = self._obj_.OnInitialUpdate()
  357. format = (-402653169, 0, 200, 0, 0, 0, 49, 'Courier New')
  358. self.SetDefaultCharFormat(format)
  359. return rc
  360. def HookHandlers(self):
  361. self.HookMessage(self.OnRClick, win32con.WM_RBUTTONDOWN)
  362. self.HookCommand(self.OnCmdOpenFile, ID_OPEN_FILE)
  363. self.HookCommand(self.OnCmdThe, ID_PYCHECKER)
  364. self.HookCommand(self.OnCmdSave, ID_SAVERESULTS)
  365. self.HookCommand(self.OnTryAgain, ID_TRYAGAIN)
  366. self.HookCommand(self.OnAddComment, ID_ADDCOMMENT)
  367. self.HookCommand(self.OnAddComment, ID_ADDPYCHECKNO2)
  368. self.HookMessage(self.OnLDblClick,win32con.WM_LBUTTONDBLCLK)
  369. def OnLDblClick(self,params):
  370. line = self.GetLine()
  371. regexGrepResult = regexGrep.match(line)
  372. if regexGrepResult:
  373. fname = regexGrepResult.group(1)
  374. line = int(regexGrepResult.group(2))
  375. scriptutils.JumpToDocument(fname, line)
  376. return 0 # dont pass on
  377. return 1 # pass it on by default.
  378. def OnRClick(self, params):
  379. menu = win32ui.CreatePopupMenu()
  380. flags=win32con.MF_STRING|win32con.MF_ENABLED
  381. lineno = self._obj_.LineFromChar(-1) #selection or current line
  382. line = self._obj_.GetLine(lineno)
  383. regexGrepResult = regexGrep.match(line)
  384. charstart, charend = self._obj_.GetSel()
  385. if regexGrepResult:
  386. self.fnm = regexGrepResult.group(1)
  387. self.lnnum = int(regexGrepResult.group(2))
  388. menu.AppendMenu(flags, ID_OPEN_FILE, "&Open "+self.fnm)
  389. menu.AppendMenu(flags, ID_ADDCOMMENT, "&Add to source: Comment Tag/#$pycheck_no ..")
  390. menu.AppendMenu(flags, ID_ADDPYCHECKNO2, "&Add to source: Specific #$pycheck_no=%(errtext)s ..")
  391. menu.AppendMenu(win32con.MF_SEPARATOR)
  392. menu.AppendMenu(flags, ID_TRYAGAIN, "&Try Again")
  393. menu.AppendMenu(flags, win32ui.ID_EDIT_CUT, 'Cu&t')
  394. menu.AppendMenu(flags, win32ui.ID_EDIT_COPY, '&Copy')
  395. menu.AppendMenu(flags, win32ui.ID_EDIT_PASTE, '&Paste')
  396. menu.AppendMenu(flags, win32con.MF_SEPARATOR);
  397. menu.AppendMenu(flags, win32ui.ID_EDIT_SELECT_ALL, '&Select all')
  398. menu.AppendMenu(flags, win32con.MF_SEPARATOR);
  399. menu.AppendMenu(flags, ID_SAVERESULTS, 'Sa&ve results')
  400. menu.TrackPopupMenu(params[5])
  401. return 0
  402. def OnAddComment(self, cmd, code):
  403. addspecific= cmd==ID_ADDPYCHECKNO2
  404. _=list(self.GetSel())
  405. _.sort()
  406. start,end=_
  407. line_start, line_end = self.LineFromChar(start), self.LineFromChar(end)
  408. first=1
  409. for i in range(line_start,line_end+1):
  410. line = self.GetLine(i)
  411. m = regexGrep.match(line)
  412. if m:
  413. if first:
  414. first=0
  415. cmnt=dialog.GetSimpleInput( "Add to %s lines" % (line_end-line_start+1),
  416. addspecific and " #$pycheck_no=%(errtext)s" or " #$pycheck_no" )
  417. if not cmnt:
  418. return 0
  419. ##import pywin.debugger;pywin.debugger.set_trace()
  420. fname = m.group(1)
  421. line = int(m.group(2))
  422. view = scriptutils.JumpToDocument(fname,line)
  423. pos=view.LineIndex(line)-1
  424. if view.GetTextRange(pos-1,pos) in ('\r','\n'):
  425. pos -= 1
  426. view.SetSel(pos, pos)
  427. errtext=m.group(3)
  428. if start!=end and line_start==line_end:
  429. errtext=self.GetSelText()
  430. errtext=repr(re.escape(errtext).replace('\ ',' '))
  431. view.ReplaceSel( addspecific and cmnt % locals()
  432. or cmnt )
  433. return 0
  434. def OnCmdOpenFile(self, cmd, code):
  435. doc = win32ui.GetApp().OpenDocumentFile(self.fnm)
  436. if doc:
  437. vw = doc.GetFirstView()
  438. #hope you have an editor that implements GotoLine()!
  439. try:
  440. vw.GotoLine(int(self.lnnum))
  441. except:
  442. pass
  443. return 0
  444. def OnCmdThe(self, cmd, code):
  445. curparamsstr = self.GetDocument().GetParams()
  446. params = curparamsstr.split('\t')
  447. params[2] = self.sel
  448. greptemplate.setParams('\t'.join(params))
  449. greptemplate.OpenDocumentFile()
  450. return 0
  451. def OnTryAgain(self, cmd, code):
  452. greptemplate.setParams(self.GetDocument().GetParams())
  453. greptemplate.OpenDocumentFile()
  454. return 0
  455. def OnCmdSave(self, cmd, code):
  456. flags = win32con.OFN_OVERWRITEPROMPT
  457. dlg = win32ui.CreateFileDialog(0, None, None, flags, "Text Files (*.txt)|*.txt||", self)
  458. dlg.SetOFNTitle("Save Results As")
  459. if dlg.DoModal() == win32con.IDOK:
  460. pn = dlg.GetPathName()
  461. self._obj_.SaveFile(pn)
  462. return 0
  463. def Append(self, strng):
  464. numlines = self.GetLineCount()
  465. endpos = self.LineIndex(numlines-1) + len(self.GetLine(numlines-1))
  466. self.SetSel(endpos, endpos)
  467. self.ReplaceSel(strng)
  468. class TheDialog(dialog.Dialog):
  469. def __init__(self, dp, fp, gp, cs, r, v):
  470. style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
  471. CS = win32con.WS_CHILD | win32con.WS_VISIBLE
  472. tmp = [ ["Pychecker Run", (0, 0, 210, 90), style, None, (8, "MS Sans Serif")], ]
  473. tmp.append([STATIC, "Files:", -1, (7, 7, 50, 9), CS ])
  474. tmp.append([EDIT, gp, 103, (52, 7, 144, 11), CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER])
  475. tmp.append([STATIC, "Directories:", -1, (7, 20, 50, 9), CS ])
  476. tmp.append([EDIT, dp, 102, (52, 20, 128, 11), CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER])
  477. tmp.append([BUTTON, '...', 110, (182,20, 16, 11), CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP])
  478. tmp.append([STATIC, "Options:", -1, (7, 33, 50, 9), CS ])
  479. tmp.append([EDIT, fp, 101, (52, 33, 128, 11), CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER ])
  480. tmp.append([BUTTON, '...', 111, (182,33, 16, 11), CS | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP])
  481. #tmp.append([BUTTON,'Case sensitive', 104, (7, 45, 72, 9), CS | win32con.BS_AUTOCHECKBOX | win32con.BS_LEFTTEXT| win32con.WS_TABSTOP])
  482. #tmp.append([BUTTON,'Subdirectories', 105, (7, 56, 72, 9), CS | win32con.BS_AUTOCHECKBOX | win32con.BS_LEFTTEXT| win32con.WS_TABSTOP])
  483. #tmp.append([BUTTON,'Verbose', 106, (7, 67, 72, 9), CS | win32con.BS_AUTOCHECKBOX | win32con.BS_LEFTTEXT| win32con.WS_TABSTOP])
  484. tmp.append([BUTTON,'OK', win32con.IDOK, (166,53, 32, 12), CS | win32con.BS_DEFPUSHBUTTON| win32con.WS_TABSTOP])
  485. tmp.append([BUTTON,'Cancel', win32con.IDCANCEL, (166,67, 32, 12), CS | win32con.BS_PUSHBUTTON| win32con.WS_TABSTOP])
  486. dialog.Dialog.__init__(self, tmp)
  487. self.AddDDX(101,'greppattern')
  488. self.AddDDX(102,'dirpattern')
  489. self.AddDDX(103,'filpattern')
  490. #self.AddDDX(104,'casesensitive')
  491. #self.AddDDX(105,'recursive')
  492. #self.AddDDX(106,'verbose')
  493. self._obj_.data['greppattern'] = gp
  494. self._obj_.data['dirpattern'] = dp
  495. self._obj_.data['filpattern'] = fp
  496. #self._obj_.data['casesensitive'] = cs
  497. #self._obj_.data['recursive'] = r
  498. #self._obj_.data['verbose'] = v
  499. self.HookCommand(self.OnMoreDirectories, 110)
  500. self.HookCommand(self.OnMoreFiles, 111)
  501. def OnMoreDirectories(self, cmd, code):
  502. self.getMore('Pychecker\\Directories', 'dirpattern')
  503. def OnMoreFiles(self, cmd, code):
  504. self.getMore('Pychecker\\File Types', 'filpattern')
  505. def getMore(self, section, key):
  506. self.UpdateData(1)
  507. #get the items out of the ini file
  508. ini = win32ui.GetProfileFileName()
  509. secitems = win32api.GetProfileSection(section, ini)
  510. items = []
  511. for secitem in secitems:
  512. items.append(secitem.split('=')[1])
  513. dlg = TheParamsDialog(items)
  514. if dlg.DoModal() == win32con.IDOK:
  515. itemstr = ';'.join(dlg.getItems())
  516. self._obj_.data[key] = itemstr
  517. #update the ini file with dlg.getNew()
  518. i = 0
  519. newitems = dlg.getNew()
  520. if newitems:
  521. items = items + newitems
  522. for item in items:
  523. win32api.WriteProfileVal(section, repr(i), item, ini)
  524. i = i + 1
  525. self.UpdateData(0)
  526. def OnOK(self):
  527. self.UpdateData(1)
  528. for id, name in [(101,'greppattern'), (102,'dirpattern'), (103,'filpattern')]:
  529. if not self[name]:
  530. self.GetDlgItem(id).SetFocus()
  531. win32api.MessageBeep()
  532. win32ui.SetStatusText("Please enter a value")
  533. return
  534. self._obj_.OnOK()
  535. class TheParamsDialog(dialog.Dialog):
  536. def __init__(self, items):
  537. self.items = items
  538. self.newitems = []
  539. style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
  540. CS = win32con.WS_CHILD | win32con.WS_VISIBLE
  541. tmp = [ ["Pychecker Parameters", (0, 0, 205, 100), style, None, (8, "MS Sans Serif")], ]
  542. tmp.append([LISTBOX, '', 107, (7, 7, 150, 72), CS | win32con.LBS_MULTIPLESEL| win32con.LBS_STANDARD | win32con.LBS_HASSTRINGS | win32con.WS_TABSTOP | win32con.LBS_NOTIFY])
  543. tmp.append([BUTTON,'OK', win32con.IDOK, (167, 7, 32, 12), CS | win32con.BS_DEFPUSHBUTTON| win32con.WS_TABSTOP])
  544. tmp.append([BUTTON,'Cancel', win32con.IDCANCEL, (167,23, 32, 12), CS | win32con.BS_PUSHBUTTON| win32con.WS_TABSTOP])
  545. tmp.append([STATIC,'New:', -1, (2, 83, 15, 12), CS])
  546. tmp.append([EDIT, '', 108, (18, 83, 139, 12), CS | win32con.WS_TABSTOP | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER])
  547. tmp.append([BUTTON,'Add', 109, (167,83, 32, 12), CS | win32con.BS_PUSHBUTTON| win32con.WS_TABSTOP])
  548. dialog.Dialog.__init__(self, tmp)
  549. self.HookCommand(self.OnAddItem, 109)
  550. self.HookCommand(self.OnListDoubleClick, 107)
  551. def OnInitDialog(self):
  552. lb = self.GetDlgItem(107)
  553. for item in self.items:
  554. lb.AddString(item)
  555. return self._obj_.OnInitDialog()
  556. def OnAddItem(self, cmd, code):
  557. eb = self.GetDlgItem(108)
  558. item = eb.GetLine(0)
  559. self.newitems.append(item)
  560. lb = self.GetDlgItem(107)
  561. i = lb.AddString(item)
  562. lb.SetSel(i, 1)
  563. return 1
  564. def OnListDoubleClick(self, cmd, code):
  565. if code == win32con.LBN_DBLCLK:
  566. self.OnOK()
  567. return 1
  568. def OnOK(self):
  569. lb = self.GetDlgItem(107)
  570. self.selections = lb.GetSelTextItems()
  571. self._obj_.OnOK()
  572. def getItems(self):
  573. return self.selections
  574. def getNew(self):
  575. return self.newitems
  576. try:
  577. win32ui.GetApp().RemoveDocTemplate(greptemplate)
  578. except NameError:
  579. pass
  580. greptemplate = TheTemplate()