# HG changeset patch # User Laurent Bessard # Date 1344551525 -7200 # Node ID 1ccd08cfae0c286bb80141fc560051ea796f5337 # Parent 85a4bc7dc31e4b0a7614a702a072696965db4943 Adding support for in POU graphical and textual editor diff -r 85a4bc7dc31e -r 1ccd08cfae0c PLCControler.py --- a/PLCControler.py Wed Aug 01 12:44:51 2012 +0200 +++ b/PLCControler.py Fri Aug 10 00:32:05 2012 +0200 @@ -2960,6 +2960,12 @@ def SearchInProject(self, criteria): return self.Project.Search(criteria) + def SearchInPou(self, tagname, criteria, debug=False): + pou = self.GetEditedElement(tagname, debug) + if pou is not None: + return pou.Search(criteria) + return [] + #------------------------------------------------------------------------------- # Current Buffering Management Functions #------------------------------------------------------------------------------- diff -r 85a4bc7dc31e -r 1ccd08cfae0c PLCOpenEditor.py --- a/PLCOpenEditor.py Wed Aug 01 12:44:51 2012 +0200 +++ b/PLCOpenEditor.py Fri Aug 10 00:32:05 2012 +0200 @@ -113,7 +113,7 @@ from PLCControler import * from SearchResultPanel import SearchResultPanel from controls import CustomTree, LibraryPanel, PouInstanceVariablesPanel, DebugVariablePanel -from dialogs import ProjectDialog, PouTransitionDialog, PouActionDialog +from dialogs import ProjectDialog, PouTransitionDialog, PouActionDialog, FindInPouDialog # Define PLCOpenEditor controls id [ID_PLCOPENEDITOR, ID_PLCOPENEDITORLEFTNOTEBOOK, @@ -135,8 +135,9 @@ [ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, ID_PLCOPENEDITOREDITMENUADDDATATYPE, ID_PLCOPENEDITOREDITMENUADDFUNCTION, ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK, ID_PLCOPENEDITOREDITMENUADDPROGRAM, ID_PLCOPENEDITOREDITMENUADDCONFIGURATION, + ID_PLCOPENEDITOREDITMENUFINDNEXT, ID_PLCOPENEDITOREDITMENUFINDPREVIOUS, ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, -] = [wx.NewId() for _init_coll_EditMenu_Items in range(7)] +] = [wx.NewId() for _init_coll_EditMenu_Items in range(9)] # Define PLCOpenEditor DisplayMenu extra items id [ID_PLCOPENEDITORDISPLAYMENURESETPERSPECTIVE, @@ -446,8 +447,15 @@ AppendMenu(parent, help='', id=wx.ID_PASTE, kind=wx.ITEM_NORMAL, text=_(u'Paste\tCTRL+V')) parent.AppendSeparator() + AppendMenu(parent, help='', id=wx.ID_FIND, + kind=wx.ITEM_NORMAL, text=_(u'Find\tCTRL+F')) + AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUFINDNEXT, + kind=wx.ITEM_NORMAL, text=_(u'Find Next\tCTRL+K')) + AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUFINDPREVIOUS, + kind=wx.ITEM_NORMAL, text=_(u'Find Previous\tCTRL+SHIFT+K')) + parent.AppendSeparator() AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, - kind=wx.ITEM_NORMAL, text=_(u'Search in Project\tCTRL+F')) + kind=wx.ITEM_NORMAL, text=_(u'Search in Project\tCTRL+SHIFT+F')) parent.AppendSeparator() add_menu = wx.Menu(title='') self._init_coll_AddMenu_Items(add_menu) @@ -462,6 +470,13 @@ self.Bind(wx.EVT_MENU, self.OnCutMenu, id=wx.ID_CUT) self.Bind(wx.EVT_MENU, self.OnCopyMenu, id=wx.ID_COPY) self.Bind(wx.EVT_MENU, self.OnPasteMenu, id=wx.ID_PASTE) + self.Bind(wx.EVT_MENU, self.OnFindMenu, id=wx.ID_FIND) + self.Bind(wx.EVT_MENU, self.OnFindNextMenu, + id=ID_PLCOPENEDITOREDITMENUFINDNEXT) + self.Bind(wx.EVT_MENU, self.OnFindPreviousMenu, + id=ID_PLCOPENEDITOREDITMENUFINDPREVIOUS) + self.Bind(wx.EVT_MENU, self.OnSearchInProjectMenu, + id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT) self.Bind(wx.EVT_MENU, self.OnSearchInProjectMenu, id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT) self.Bind(wx.EVT_MENU, self.OnAddDataTypeMenu, @@ -693,6 +708,9 @@ self.AUIManager.Update() + self.FindDialog = FindInPouDialog(self) + self.FindDialog.Hide() + ## Constructor of the PLCOpenEditor class. # @param parent The parent window. # @param controler The controler been used by PLCOpenEditor (default: None). @@ -750,6 +768,7 @@ self.CurrentEditorToolBar = [] self.CurrentMenu = None self.SelectedItem = None + self.SearchParams = None self.Highlights = {} self.DrawingMode = FREEDRAWING_MODE #self.DrawingMode = DRIVENDRAWING_MODE @@ -766,6 +785,9 @@ self.SetRefreshFunctions() + def __del__(self): + self.FindDialog.Destroy() + def ResetStarting(self): self.Starting = False @@ -1066,9 +1088,11 @@ # Refresh all window elements that have changed wx.CallAfter(self._Refresh, TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) wx.CallAfter(self.RefreshTabCtrlEvent) + wx.CallAfter(self.CloseFindInPouDialog) event.Skip() else: event.Veto() + def GetCopyBuffer(self): data = None @@ -1278,6 +1302,11 @@ #self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, True) #self.EditMenu.Check(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, # self.Controler.IsProjectBufferEnabled()) + self.EditMenu.Enable(wx.ID_FIND, selected > -1) + self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUFINDNEXT, + selected > -1 and self.SearchParams is not None) + self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUFINDPREVIOUS, + selected > -1 and self.SearchParams is not None) self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, True) MenuToolBar.EnableTool(ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, True) self.EditMenu.Enable(wx.ID_ADD, True) @@ -1315,6 +1344,9 @@ self.EditMenu.Enable(wx.ID_PASTE, False) MenuToolBar.EnableTool(wx.ID_PASTE, False) self.EditMenu.Enable(wx.ID_SELECTALL, False) + self.EditMenu.Enable(wx.ID_FIND, False) + self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUFINDNEXT, False) + self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUFINDPREVIOUS, False) self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, False) MenuToolBar.EnableTool(ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, False) self.EditMenu.Enable(wx.ID_ADD, False) @@ -1394,6 +1426,29 @@ event.m_keyCode = wx.WXK_DELETE window.ProcessEvent(event) + def OnFindMenu(self, event): + if not self.FindDialog.IsShown(): + self.FindDialog.Show() + + def CloseFindInPouDialog(self): + selected = self.TabsOpened.GetSelection() + if selected == -1 and self.FindDialog.IsShown(): + self.FindDialog.Hide() + + def OnFindNextMenu(self, event): + self.FindInPou(1) + + def OnFindPreviousMenu(self, event): + self.FindInPou(-1) + + def FindInPou(self, direction, search_params=None): + if search_params is not None: + self.SearchParams = search_params + selected = self.TabsOpened.GetSelection() + if selected != -1: + window = self.TabsOpened.GetPage(selected) + window.Find(direction, self.SearchParams) + def OnSearchInProjectMenu(self, event): dialog = SearchInProjectDialog(self) if dialog.ShowModal() == wx.ID_OK: diff -r 85a4bc7dc31e -r 1ccd08cfae0c TextViewer.py --- a/TextViewer.py Wed Aug 01 12:44:51 2012 +0200 +++ b/TextViewer.py Fri Aug 10 00:32:05 2012 +0200 @@ -197,6 +197,9 @@ self.TextSyntax = None self.CurrentAction = None self.Highlights = [] + self.SearchParams = None + self.SearchResults = None + self.CurrentFindHighlight = None self.InstancePath = instancepath self.ContextStack = [] self.CallStack = [] @@ -739,6 +742,43 @@ self.RefreshModel() self.RefreshBuffer() + def Find(self, direction, search_params): + if self.SearchParams != search_params: + self.ClearHighlights(SEARCH_RESULT_HIGHLIGHT) + + self.SearchParams = search_params + criteria = { + "raw_pattern": search_params["find_pattern"], + "pattern": re.compile(search_params["find_pattern"]), + "case_sensitive": search_params["case_sensitive"], + "regular_expression": search_params["regular_expression"], + "filter": "all"} + + self.SearchResults = [ + (infos[1:], start, end, SEARCH_RESULT_HIGHLIGHT) + for infos, start, end, text in + self.Controler.SearchInPou(self.TagName, criteria, self.Debug)] + + if len(self.SearchResults) > 0: + if self.CurrentFindHighlight is not None: + old_idx = self.SearchResults.index(self.CurrentFindHighlight) + if self.SearchParams["wrap"]: + idx = (old_idx + direction) % len(self.SearchResults) + else: + idx = max(0, min(old_idx + direction, len(self.SearchResults) - 1)) + if idx != old_idx: + self.RemoveHighlight(*self.CurrentFindHighlight) + self.CurrentFindHighlight = self.SearchResults[idx] + self.AddHighlight(*self.CurrentFindHighlight) + else: + self.CurrentFindHighlight = self.SearchResults[0] + self.AddHighlight(*self.CurrentFindHighlight) + + else: + if self.CurrentFindHighlight is not None: + self.RemoveHighlight(*self.CurrentFindHighlight) + self.CurrentFindHighlight = None + def RefreshModel(self): self.RefreshJumpList() self.Controler.SetEditedElementText(self.TagName, self.GetText()) @@ -832,8 +872,18 @@ highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None) if infos[0] == "body" and highlight_type is not None: self.Highlights.append((infos[1], start, end, highlight_type)) + self.Editor.GotoPos(self.Editor.PositionFromLine(start[0]) + start[1]) self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) + def RemoveHighlight(self, infos, start, end, highlight_type): + EditorPanel.RemoveHighlight(self, infos, start, end, highlight_type) + + highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None) + if (infos[0] == "body" and highlight_type is not None and + (infos[1], start, end, highlight_type) in self.Highlights): + self.Highlights.remove((infos[1], start, end, highlight_type)) + self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) + def ShowHighlights(self, start_pos, end_pos): for indent, start, end, highlight_type in self.Highlights: if start[0] == 0: diff -r 85a4bc7dc31e -r 1ccd08cfae0c Viewer.py --- a/Viewer.py Wed Aug 01 12:44:51 2012 +0200 +++ b/Viewer.py Fri Aug 10 00:32:05 2012 +0200 @@ -22,6 +22,7 @@ #License along with this library; if not, write to the Free Software #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +import re import math import time from types import TupleType @@ -170,6 +171,14 @@ "actionBlock": actionBlockCreationFunction, } +def sort_blocks(block_infos1, block_infos2): + x1, y1 = block_infos1[0].GetPosition() + x2, y2 = block_infos2[0].GetPosition() + if y1 == y2: + return cmp(x1, x2) + else: + return cmp(y1, y2) + #------------------------------------------------------------------------------- # Graphic elements Viewer base class #------------------------------------------------------------------------------- @@ -557,6 +566,9 @@ self.current_id = 0 self.TagName = tagname self.Highlights = [] + self.SearchParams = None + self.SearchResults = None + self.CurrentFindHighlight = None self.InstancePath = instancepath self.StartMousePos = None self.StartScreenPos = None @@ -1107,6 +1119,29 @@ round(maxx / SCROLLBAR_UNIT) + width_incr, round(maxy / SCROLLBAR_UNIT) + height_incr, xstart, ystart, True) + def EnsureVisible(self, block): + xstart, ystart = self.GetViewStart() + window_size = self.Editor.GetClientSize() + block_bbx = block.GetBoundingBox() + + screen_minx, screen_miny = xstart * SCROLLBAR_UNIT, ystart * SCROLLBAR_UNIT + screen_maxx, screen_maxy = screen_minx + window_size[0], screen_miny + window_size[1] + block_minx = int(block_bbx.x * self.ViewScale[0]) + block_miny = int(block_bbx.y * self.ViewScale[1]) + block_maxx = int(round((block_bbx.x + block_bbx.width) * self.ViewScale[0])) + block_maxy = int(round((block_bbx.y + block_bbx.height) * self.ViewScale[1])) + + xpos, ypos = xstart, ystart + if block_minx < screen_minx and block_maxx < screen_maxx: + xpos -= (screen_minx - block_minx) / SCROLLBAR_UNIT + 1 + elif block_maxx > screen_maxx and block_minx > screen_minx: + xpos += (block_maxx - screen_maxx) / SCROLLBAR_UNIT + 1 + if block_miny < screen_miny and block_maxy < screen_maxy: + ypos -= (screen_miny - block_miny) / SCROLLBAR_UNIT + 1 + elif block_maxy > screen_maxy and block_miny > screen_miny: + ypos += (block_maxy - screen_maxy) / SCROLLBAR_UNIT + 1 + self.Scroll(xpos, ypos) + def SelectInGroup(self, element): element.SetSelected(True) if self.SelectedElement is None: @@ -3002,7 +3037,54 @@ self.Controler.AddEditedElementActionBlock(self.TagName, block.GetId()) self.RefreshActionBlockModel(block) - +#------------------------------------------------------------------------------- +# Find and Replace functions +#------------------------------------------------------------------------------- + + def Find(self, direction, search_params): + if self.SearchParams != search_params: + self.ClearHighlights(SEARCH_RESULT_HIGHLIGHT) + + self.SearchParams = search_params + criteria = { + "raw_pattern": search_params["find_pattern"], + "pattern": re.compile(search_params["find_pattern"]), + "case_sensitive": search_params["case_sensitive"], + "regular_expression": search_params["regular_expression"], + "filter": "all"} + + self.SearchResults = [] + blocks = [] + for infos, start, end, text in self.Controler.SearchInPou(self.TagName, criteria, self.Debug): + if infos[1] in ["var_local", "var_input", "var_output", "var_inout"]: + self.SearchResults.append((infos[1:], start, end, SEARCH_RESULT_HIGHLIGHT)) + else: + block = self.Blocks.get(infos[2]) + if block is not None: + blocks.append((block, (infos[1:], start, end, SEARCH_RESULT_HIGHLIGHT))) + blocks.sort(sort_blocks) + self.SearchResults.extend([infos for block, infos in blocks]) + + if len(self.SearchResults) > 0: + if self.CurrentFindHighlight is not None: + old_idx = self.SearchResults.index(self.CurrentFindHighlight) + if self.SearchParams["wrap"]: + idx = (old_idx + direction) % len(self.SearchResults) + else: + idx = max(0, min(old_idx + direction, len(self.SearchResults) - 1)) + if idx != old_idx: + self.RemoveHighlight(*self.CurrentFindHighlight) + self.CurrentFindHighlight = self.SearchResults[idx] + self.AddHighlight(*self.CurrentFindHighlight) + else: + self.CurrentFindHighlight = self.SearchResults[0] + self.AddHighlight(*self.CurrentFindHighlight) + + else: + if self.CurrentFindHighlight is not None: + self.RemoveHighlight(*self.CurrentFindHighlight) + self.CurrentFindHighlight = None + #------------------------------------------------------------------------------- # Highlights showing functions #------------------------------------------------------------------------------- @@ -3024,8 +3106,19 @@ EditorPanel.AddHighlight(self, infos, start, end, highlight_type) self.Highlights.append((infos, start, end, highlight_type)) - self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) - + if infos[0] not in ["var_local", "var_input", "var_output", "var_inout"]: + block = self.Blocks.get(infos[1]) + if block is not None: + self.EnsureVisible(block) + self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) + + def RemoveHighlight(self, infos, start, end, highlight_type): + EditorPanel.RemoveHighlight(self, infos, start, end, highlight_type) + + if (infos, start, end, highlight_type) in self.Highlights: + self.Highlights.remove((infos, start, end, highlight_type)) + self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) + def ShowHighlights(self): for infos, start, end, highlight_type in self.Highlights: if infos[0] in ["comment", "io_variable", "block", "connector", "coil", "contact", "step", "transition", "jump", "action_block"]: diff -r 85a4bc7dc31e -r 1ccd08cfae0c controls/CustomTable.py --- a/controls/CustomTable.py Wed Aug 01 12:44:51 2012 +0200 +++ b/controls/CustomTable.py Fri Aug 10 00:32:05 2012 +0200 @@ -168,6 +168,15 @@ col_highlights = row_highlights.setdefault(infos[1], []) col_highlights.append(highlight_type) + def RemoveHighlight(self, infos, highlight_type): + row_highlights = self.Highlights.get(infos[0]) + if row_highlights is not None: + col_highlights = row_highlights.get(infos[1]) + if col_highlights is not None and highlight_type in col_highlights: + col_highlights.remove(highlight_type) + if len(col_highlights) == 0: + row_highlights.pop(infos[1]) + def ClearHighlights(self, highlight_type=None): if highlight_type is None: self.Highlights = {} diff -r 85a4bc7dc31e -r 1ccd08cfae0c controls/EditorPanel.py --- a/controls/EditorPanel.py Wed Aug 01 12:44:51 2012 +0200 +++ b/controls/EditorPanel.py Fri Aug 10 00:32:05 2012 +0200 @@ -130,6 +130,9 @@ self.Controler.LoadNext() self.RefreshView() + def Find(self, direction, search_params): + pass + def HasNoModel(self): return False @@ -157,6 +160,10 @@ if self.VariableEditor is not None and infos[0] in ["var_local", "var_input", "var_output", "var_inout"]: self.VariableEditor.AddVariableHighlight(infos[1:], highlight_type) + def RemoveHighlight(self, infos, start, end, highlight_type): + if self.VariableEditor is not None and infos[0] in ["var_local", "var_input", "var_output", "var_inout"]: + self.VariableEditor.RemoveVariableHighlight(infos[1:], highlight_type) + def ClearHighlights(self, highlight_type=None): if self.VariableEditor is not None: self.VariableEditor.ClearHighlights(highlight_type) diff -r 85a4bc7dc31e -r 1ccd08cfae0c controls/VariablePanel.py --- a/controls/VariablePanel.py Wed Aug 01 12:44:51 2012 +0200 +++ b/controls/VariablePanel.py Fri Aug 10 00:32:05 2012 +0200 @@ -819,8 +819,20 @@ if isinstance(infos[0], TupleType): for i in xrange(*infos[0]): self.Table.AddHighlight((i,) + infos[1:], highlight_type) + cell_visible = infos[0][0] else: self.Table.AddHighlight(infos, highlight_type) + cell_visible = infos[0] + colnames = [colname.lower() for colname in self.Table.colnames] + self.VariablesGrid.MakeCellVisible(cell_visible, colnames.index(infos[1])) + self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) + + def RemoveVariableHighlight(self, infos, highlight_type): + if isinstance(infos[0], TupleType): + for i in xrange(*infos[0]): + self.Table.RemoveHighlight((i,) + infos[1:], highlight_type) + else: + self.Table.RemoveHighlight(infos, highlight_type) self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) def ClearHighlights(self, highlight_type=None): diff -r 85a4bc7dc31e -r 1ccd08cfae0c dialogs/FindInPouDialog.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dialogs/FindInPouDialog.py Fri Aug 10 00:32:05 2012 +0200 @@ -0,0 +1,139 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import wx + +class FindInPouDialog(wx.Frame): + + def __init__(self, parent): + wx.Frame.__init__(self, parent, title=_("Find"), + size=wx.Size(400, 250), style=wx.CAPTION| + wx.CLOSE_BOX| + wx.CLIP_CHILDREN| + wx.TAB_TRAVERSAL| + wx.RESIZE_BORDER| + wx.STAY_ON_TOP) + + main_sizer = wx.FlexGridSizer(cols=1, hgap=5, rows=2, vgap=5) + main_sizer.AddGrowableCol(0) + main_sizer.AddGrowableRow(0) + + controls_sizer = wx.BoxSizer(wx.VERTICAL) + main_sizer.AddSizer(controls_sizer, border=20, + flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) + + patterns_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=1, vgap=5) + patterns_sizer.AddGrowableCol(1) + controls_sizer.AddSizer(patterns_sizer, border=5, flag=wx.GROW|wx.BOTTOM) + + find_label = wx.StaticText(self, label=_("Find:")) + patterns_sizer.AddWindow(find_label, flag=wx.ALIGN_CENTER_VERTICAL) + + self.FindPattern = wx.TextCtrl(self) + self.Bind(wx.EVT_TEXT, self.OnFindPatternChanged, self.FindPattern) + patterns_sizer.AddWindow(self.FindPattern, flag=wx.GROW) + + params_sizer = wx.BoxSizer(wx.HORIZONTAL) + controls_sizer.AddSizer(params_sizer, border=5, flag=wx.GROW|wx.BOTTOM) + + direction_staticbox = wx.StaticBox(self, label=_("Direction")) + direction_staticboxsizer = wx.StaticBoxSizer( + direction_staticbox, wx.VERTICAL) + params_sizer.AddSizer(direction_staticboxsizer, 1, border=5, + flag=wx.GROW|wx.RIGHT) + + self.Forward = wx.RadioButton(self, label=_("Forward"), + style=wx.RB_GROUP) + direction_staticboxsizer.AddWindow(self.Forward, border=5, + flag=wx.ALL|wx.GROW) + + self.Backward = wx.RadioButton(self, label=_("Backward")) + direction_staticboxsizer.AddWindow(self.Backward, border=5, + flag=wx.ALL|wx.GROW) + + options_staticbox = wx.StaticBox(self, label=_("Options")) + options_staticboxsizer = wx.StaticBoxSizer( + options_staticbox, wx.VERTICAL) + params_sizer.AddSizer(options_staticboxsizer, 1, flag=wx.GROW) + + self.CaseSensitive = wx.CheckBox(self, label=_("Case sensitive")) + self.CaseSensitive.SetValue(True) + options_staticboxsizer.AddWindow(self.CaseSensitive, border=5, + flag=wx.ALL|wx.GROW) + + self.WrapSearch = wx.CheckBox(self, label=_("Wrap search")) + self.WrapSearch.SetValue(True) + options_staticboxsizer.AddWindow(self.WrapSearch, border=5, + flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW) + + self.RegularExpressions = wx.CheckBox(self, label=_("Regular expressions")) + options_staticboxsizer.AddWindow(self.RegularExpressions, border=5, + flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW) + + buttons_sizer = wx.BoxSizer(wx.HORIZONTAL) + main_sizer.AddSizer(buttons_sizer, border=20, + flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_RIGHT) + + self.FindButton = wx.Button(self, label=_("Find")) + self.Bind(wx.EVT_BUTTON, self.OnFindButton, self.FindButton) + buttons_sizer.AddWindow(self.FindButton, border=5, flag=wx.RIGHT) + + self.CloseButton = wx.Button(self, label=("Close")) + self.Bind(wx.EVT_BUTTON, self.OnCloseButton, self.CloseButton) + buttons_sizer.AddWindow(self.CloseButton) + + self.SetSizer(main_sizer) + + self.ParentWindow = parent + + self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) + + self.RefreshButtonsState() + + def RefreshButtonsState(self): + find_pattern = self.FindPattern.GetValue() + self.FindButton.Enable(find_pattern != "") + + def OnCloseFrame(self, event): + self.Hide() + event.Veto() + + def OnCloseButton(self, event): + self.Hide() + event.Skip() + + def OnFindPatternChanged(self, event): + self.RefreshButtonsState() + event.Skip() + + def OnFindButton(self, event): + infos = { + "find_pattern": self.FindPattern.GetValue(), + "wrap": self.WrapSearch.GetValue(), + "case_sensitive": self.CaseSensitive.GetValue(), + "regular_expression": self.RegularExpressions.GetValue()} + wx.CallAfter(self.ParentWindow.FindInPou, + {True: 1, False:-1}[self.Forward.GetValue()], + infos) + event.Skip() diff -r 85a4bc7dc31e -r 1ccd08cfae0c dialogs/SearchInProjectDialog.py --- a/dialogs/SearchInProjectDialog.py Wed Aug 01 12:44:51 2012 +0200 +++ b/dialogs/SearchInProjectDialog.py Fri Aug 10 00:32:05 2012 +0200 @@ -67,7 +67,7 @@ self.CaseSensitive = wx.CheckBox(self, label=_('Case sensitive')) pattern_sizer.AddWindow(self.CaseSensitive, flag=wx.GROW) - self.Pattern = wx.TextCtrl(self, size=wx.Size(0, 24)) + self.Pattern = wx.TextCtrl(self) pattern_sizer.AddWindow(self.Pattern, flag=wx.GROW) self.RegularExpression = wx.CheckBox(self, label=_('Regular expression')) @@ -140,6 +140,7 @@ event.Skip() def OnOK(self, event): + message = None if self.Pattern.GetValue() == "": message = _("Form isn't complete. Pattern to search must be filled!") else: diff -r 85a4bc7dc31e -r 1ccd08cfae0c dialogs/__init__.py --- a/dialogs/__init__.py Wed Aug 01 12:44:51 2012 +0200 +++ b/dialogs/__init__.py Fri Aug 10 00:32:05 2012 +0200 @@ -43,3 +43,4 @@ from PouDialog import PouDialog from PouTransitionDialog import PouTransitionDialog from PouActionDialog import PouActionDialog +from FindInPouDialog import FindInPouDialog