"""Subclass of MainWindow, which is generated by wxFormBuilder."""

import os
import signal
import re
import wx
import wx.html2
import wxx
import model
import app
import tran

from ctx import localcontext as context
import app.proCxxGUI as base
import app.resources as rc
import app
import activity
import ostools
import plugin.tools

#LOG_FatalError
#LOG_Error
#LOG_Warning
#LOG_Message
#LOG_Status
#LOG_Info
#LOG_Debug
#LOG_Trace
#LOG_Progress
#LOG_User
#LOG_Max


BASE_VIEW_COMMAND_ID = wx.ID_HIGHEST + 1000
TOOL_VIEW_COMMAND_ID = wx.ID_HIGHEST + 2000

#def redirectFocusWindow(method):
#    """decorador for redirecting event to focus window"""
#    def wrapped(self, event):
#        """decorator method"""
#        wnd = self.FindFocus()
#        if wnd != self:
#            wnd.ProcessEvent(event)
#        else:
#            self.method(event)
#    return wrapped

SKIP_EVENT_RECURSE = True


class mainWindow(base.MainWindow):
    """The main application window"""

    tool_id = TOOL_VIEW_COMMAND_ID

    def __init__(self, app):
        """Initialization of main window"""
        super(mainWindow, self).__init__(None)

        self.imglist = rc.GetBitmapImageList()
        self.viewBook.SetImageList(self.imglist)
        self.docBook.SetImageList(ostools.MimeHandler.imageList)
        wx.Log.SetActiveTarget(wx.LogTextCtrl(self.m_toolLog))
        self._output = wx.LogTextCtrl(self.auxOutput)
        self._output.SetLogLevel(wx.LOG_Progress)

        self._menus = {}
        self._toolsMenus = {}

        context.SetFrame(self)

        self._import_views()
        self._import_tools()


        # need for acceletator message dispatch

        icon = wx.EmptyIcon()
        icon.CopyFromBitmap(rc.GetBitmap("project"))
        self.SetIcon(icon)

        #self.Freeze()
        #self.Maximize()

        self._bind_events()

        self.addWelcome()

        #do self update check
        self._tools[plugin.tools.check_updates].doUpdate(True)

    def _bind_events(self):
        """Bind custom events"""
        self.Bind(wxx.EVT_LOGGER, self.OnOutputMessage)
        self.Bind(wxx.EVT_SEARCH, self.OnSearchResults)

    def new_tool_id(self):
        """returns new tool id"""
        value = self.tool_id
        self.tool_id = self.tool_id + 1
        return value

    def _import_views(self):
        """Reads the views definitions and prepare to handle them"""
        global BASE_VIEW_COMMAND_ID
        # initialize dict show
        self._views = dict([(cls, None) for cls in activity.ALL])
        # initialize dict hidden
        self._hviews = {}
        # initialize methods for each view
        import new
        i = BASE_VIEW_COMMAND_ID
        for cls in self._views:
            name = cls.name
            #prepare update event handler
            code = eval('lambda x, event: x.OnUpdateToggleView(activity.INDEX["{name}"], event)'.format(
                name=name))
            u_method = new.instancemethod(code, self, mainWindow)
            fname = 'OnUpdateToggle{name}'.format(name=cls.name)
            setattr(self, fname, u_method)
            u_method = eval('self.{fname}'.format(fname=fname))

            #prepare command event handler
            code = eval('lambda x, event: x.OnToggleView(activity.INDEX["{name}"], event)'.format(
                name=name))
            c_method = new.instancemethod(code, self, mainWindow)
            fname = 'OnToggle{name}'.format(name=cls.name)
            setattr(self, fname, c_method)
            c_method = eval('self.{fname}'.format(fname=fname))

            #add menu entry
            mni = wx.MenuItem(self.menuView, wx.ID_ANY,
                u"Show {name}".format(name=cls.name),
                u"show the view", wx.ITEM_NORMAL)
            mni.SetBitmap(cls.bitmap())
            self.menuView.InsertItem(0, mni)

            #add the menu handlers
            self.Bind(wx.EVT_UPDATE_UI, u_method, id=mni.GetId())
            self.Bind(wx.EVT_MENU, c_method, id=mni.GetId())
            i = i + 1

    def _import_tools(self):
        """Reads the tools definitions and import them"""
        self._tools = dict([(cls, None) for cls in plugin.tools.ALL])
        for tool in self._tools:
            tool_instance = tool.load()
            self.PushEventHandler(tool_instance)
            self._tools[tool] = tool_instance

    def SaveViews(self):
        """Store open views in config"""
        config = context.config
        # store selected view
        i = self.viewBook.GetSelection()
        activeView = (i != wx.NOT_FOUND and self.viewBook.GetPage(i).name) or ''
        config.Write('/view/active', activeView)
        for v in activity.ALL:
            config.Write('/views/perspectives/{}'.format(v.name), v.perspective)
            if v in self._views and self._views[v]:
                config.WriteInt('/views/states/{}'.format(v.name), 1)
            else:
                config.WriteInt('/views/states/{}'.format(v.name), 0)
        last = self.m_mgr.SavePerspective()
        config.Write('/frame/perspectives/current', last)

    def LoadViews(self):
        """Load open views in config"""
        self._mainPerspective = self.m_mgr.SavePerspective()
        config = context.config
        activeView = config.Read('/view/active', '')
        for v in activity.ALL:
            v.perspective = config.Read('/views/perspectives/{}'.format(v.name), '')
            if config.ReadInt('/views/states/{}'.format(v.name), 1):
                self.OpenView(v, bool(activeView == v.name))
        last = config.Read('/frame/perspectives/current', '')
        if last:
            self.m_mgr.LoadPerspective(last)

    def GetViewsStatus(self):
        """Get extra info about view status to be stored as session"""
        status = {}
        for v in activity.ALL:
            if v not in self._views:
                continue
            obj = self._views[v]
            if not obj or not hasattr(obj, 'GetViewStatus'):
                continue
            status[v.name] = obj.GetViewStatus()
        return status

    def SetViewsStatus(self, info):
        """Set extra info about view status to be stored as session"""
        for v in activity.ALL:
            if v not in self._views or v.name not in info:
                continue
            obj = self._views[v]
            if not obj or not hasattr(obj, 'SetViewStatus'):
                continue
            obj.SetViewStatus(info[v.name])
        return True

    def LoadMRU(self):
        """Load MRU"""
        mru = context.mru
        mru.UseMenu(self.menuMRU)
        mru.AddFilesToMenu()

    def addWelcome(self):
        """This adds the welcome page"""
        self.m_startPanel = wx.Panel(self.docBook, wx.ID_ANY,
            wx.DefaultPosition, wx.Size(-1, -1), wx.TAB_TRAVERSAL)
        self.m_startPanel.SetExtraStyle(wx.WS_EX_PROCESS_UI_UPDATES)
        self.m_startPanel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseStartPage)
        self.m_startPanel.Bind(wx.EVT_PAINT, self.OnPaintStartPage)
        self.docBook.AddPage(self.m_startPanel, u"Welcome!", False,
            rc.GetBitmapIndex('mini_logo'))

    def redirectedToFocus4Enabled(self, event):
        """Update new project"""
        global SKIP_EVENT_RECURSE
        if not SKIP_EVENT_RECURSE:
            event.Enable(False)
            return
        SKIP_EVENT_RECURSE = False
        wnd = self.FindFocus()
        if wnd and wnd != self:
            if wnd.ProcessEvent(event):
                SKIP_EVENT_RECURSE = True
                return
        event.Enable(False)
        SKIP_EVENT_RECURSE = True

    def redirectedToFocus(self, event):
        """Redirect command to parent"""
        wnd = self.FindFocus()
        if wnd and wnd != self:
            wnd.ProcessEvent(event)

    def OnEditUndo(self, event):
        """Implements undo command"""
        wx.LogMessage('undo {}'.format(tran.TransactionStack.instance.UndoName()))
        tran.TransactionStack.DoUndo()

    def OnUpdateEditUndo(self, event):
        """Handle update edit undo"""
        if tran.TransactionStack.instance.CanUndo():
            event.Enable(True)
            name = tran.TransactionStack.instance.UndoName()
            if not name is None:
                event.SetText("Undo " + name + "\tCtrl+Z")
            else:
                event.SetText("Undo" + "\tCtrl+Z")
        else:
            event.Enable(False)
            event.SetText("Undo" + "\tCtrl+Z")

    def OnEditRedo(self, event):
        """Implements redo command"""
        wx.LogMessage('redo {}'.format(tran.TransactionStack.instance.RedoName()))
        tran.TransactionStack.DoRedo()

    def OnUpdateEditRedo(self, event):
        """Handle update edit redo"""
        if tran.TransactionStack.instance.CanRedo():
            event.Enable(True)
            name = tran.TransactionStack.instance.RedoName()
            if not name is None:
                event.SetText("Redo " + name + "\tCtrl+Y")
            else:
                event.SetText("Redo" + "\tCtrl+Y")
        else:
            event.Enable(False)
            event.SetText("Redo" + "\tCtrl+Y")

    def OpenView(self, cls, select=True):
        """Open generic class"""
        if self._views.get(cls, None):
            return
        view = self._hviews.get(cls, None)
        if view is None:
            view = cls(self)
        else:
            del self._hviews[cls]
        self._views[cls] = view
        if wx.__version__ >= '3.0.0.0':
            self.viewBook.AddPage(view, cls.name,
                False, cls.bitmap_index())
        else:
            self.viewBook.AddPage(view, cls.name,
                False, cls.bitmap())
        if select:
            self.viewBook.SetSelection(
                self.viewBook.GetPageIndex(view))
        if self.viewBook.GetSelection() == self.viewBook.GetPageIndex(view):
            if hasattr(view, 'NotifyShow'):
                view.NotifyShow()

    def CloseView(self, cls):
        """close some generic view"""
        view = self._views.get(cls, None)
        if view:
            i = self.viewBook.GetPageIndex(view)
            if i is not wx.NOT_FOUND:
                if i == self.viewBook.GetSelection():
                    if hasattr(view, 'NotifyHide'):
                        view.NotifyHide()
                self.viewBook.RemovePage(i)
            self._hviews[cls] = view
            del self._views[cls]

    def OnToggleView(self, cls, event):
        """Toggle some generic view"""
        if self._views.get(cls, None):
            self.CloseView(cls)
        else:
            self.OpenView(cls)

    def OnUpdateToggleView(self, cls, event):
        """Update toggle tasks view"""
        try:
            if self._views.get(cls, None):
                event.SetText('Hide {name}'.format(name=cls.name))
            else:
                event.SetText('Show {name}'.format(name=cls.name))
        except:
            print 'error in {}'.format(cls)

    def AddMainMenu(self, name, menu):
        """Add on-the-fly main menu"""
        if name in self._menus:
            return False
        nmnu = self.m_menubar1.GetMenuCount()
        #skip help
        if self.m_menubar1.Insert(nmnu - 1, menu, name):
            #app.set_menu_handlers(self, menu,
            #    self.redirectedToFocus, self.redirectedToFocus4Enabled)
            self._menus[name] = menu
            return True
        return False

    def AddToolsMenu(self, name, menu):
        """Append a menu entry to tools"""
        if name in self._toolsMenus:
            return False
        nmnu = self.menuTools.GetMenuItemCount()
        if self.menuTools.InsertItem(nmnu, menu):
            self._toolsMenus[name] = menu
            return True
        return False

    def RemoveMainMenu(self, name, menu):
        """Remove existing main menu"""
        if name not in self._menus:
            return False
        mnu = self._menus[name]  # the menu object to be removed
        if mnu != menu:
            return False
        # we seach the menu, not the name
        pairs = self.m_menubar1.GetMenus()
        for i in range(0, len(pairs)):
            if pairs[i][0] == mnu:
                #ok, we find it
                #app.unset_menu_handlers(self, mnu,
                #    self.redirectedToFocus, self.redirectedToFocus4Enabled)
                self.m_menubar1.Remove(i)
                del self._menus[name]
                return True
        return False

    def RemoveToolsMenu(self, name, menu):
        """Remove existing tool menu"""
        if name not in self._toolsMenus:
            return False
        mnu = self._toolsMenus[name]  # the menu object to be removed
        if mnu != menu:
            return False
        # we search the menu, not the name
        index = self.menuTools.FindItem(mnu)
        if index != wx.NOT_FOUND:
            app.unset_menu_handlers(self, menu,
                self.redirectedToFocus, self.redirectedToFocus4Enabled)
            self.menuTools.RemoveItem(mnu)
            del self._toolsMenus[name]
            return True
        return False

    def DoRenderRemoveElement(self, obj):
        """Do remove element in tree"""
        views = self._views
        views.update(self._hviews)
        for cls in views:
            v = views[cls]
            if v and hasattr(v, 'DoRenderRemoveElement'):
                v.DoRenderRemoveElement(obj)

    def DoRenderAddElement(self, obj):
        """Add element to visual"""
        views = self._views
        views.update(self._hviews)
        for cls in views:
            v = views[cls]
            if v and hasattr(v, 'DoRenderAddElement'):
                v.DoRenderAddElement(obj)

    def UpdateElement(self, obj):
        """Update the tree label for a object"""
        if hasattr(obj, '_pane') and obj._pane:
            obj._pane.Refresh()
        views = self._views
        views.update(self._hviews)
        for cls in views:
            v = views[cls]
            if v and hasattr(v, 'UpdateElement'):
                v.UpdateElement(obj)

    def OnSalir(self, event):
        """Ends application"""
        if context.app.ExitEvenModified():
            context.Destroy()
            #sys.exit()

    def Destroy(self):
        """Destroy frame"""
        del self.m_auiToolBarFile
        del self.m_auiToolBarEdit
        views = self._views
        views.update(self._hviews)
        for cls in views:
            v = views[cls]
            if v and hasattr(v, '_delete_toolbars'):
                v._delete_toolbars()
        super(mainWindow, self).Destroy()

    @tran.TransactionalMethod('create workspace {}')
    @wxx.CreationDialog(app.ui.dlg.WorkspaceDialog, model.Workspace)
    def OnNewWorkspace(self, event):
        """Handle new workspace command"""
        return (self, None)

    def OnSettingsBuildTools(self, event):
        """Show build tools dialog"""
        app.ui.dlg.BuildTools(self).ShowModal()

    def OnEraseStartPage(self, event):
        """Erase start page event"""
        sz = self.m_startPanel.GetSize()
        dc = event.GetDC()
        bmp = wx.EmptyBitmap(729, 119)
        bmp.LoadFile('app/res/beatle.jpg', wx.BITMAP_TYPE_JPEG)
        dc.DrawBitmap(bmp, sz.x // 2 - 365, sz.y // 2 - 60)
        del bmp

    def OnPaintStartPage(self, event):
        """Start page paint event"""
        dc = wx.PaintDC(self.m_startPanel)
        #dc.SetBrush(wx.Brush(wx.RED))
        #dc.Clear()
        return

    def OnEditPreferences(self, event):
        """Handle edit preferences"""
        app.ui.dlg.PreferencesDialog(self).ShowModal()

    def OnHelpPython2Reference(self, event):
        """Handle python 2 reference"""
        self.ShowReference('https://docs.python.org/2/', 'python 2 reference')

    def OnHelpCppReference(self, event):
        """Handle python 2 reference"""
        self.ShowReference('http://en.cppreference.com', 'c++ reference')

    def OnHelpBeatsOfCode(self, event):
        """Handle beats of code reference"""
        self.ShowReference('http://beatsofcode.com', 'online tutorials')

    def ShowReference(self, url, title='Help'):
        """Handle help cpp reference"""
        import app.ui.pane as pane
        for index in range(0, self.docBook.GetPageCount()):
            p = self.docBook.GetPage(index)
            if type(p) is not pane.NavigatorPane:
                continue
            # ok, check url
            if p._url != url:
                continue
            self.docBook.SetSelection(index)
            return
        # ok,there are not a navigation page
        p = pane.NavigatorPane(self.docBook, self)
        if wx.__version__ >= '3.0.0.0':
            #self.docBook.Freeze()
            self.docBook.AddPage(p, title, True, rc.GetBitmapIndex("info"))
            #self.docBook.Thaw()
        else:
            self.docBook.AddPage(p, title, True,
                rc.GetBitmap("info"))
        p.NavigateTo(url)

    @tran.TransactionalMethod('open workspace {}')
    def OnOpenWorkspace(self, event):
        """Handle open workspace method"""
        dialog = wx.FileDialog(self, "Select workspace file", wx.EmptyString,
            wx.EmptyString, "Workspace files (*.wrk)|*.wrk", wx.FD_OPEN)
        if dialog.ShowModal() != wx.ID_OK:
            return False
        workspace = context.app.LoadWorkspace(dialog.GetPath())
        if workspace:
            tran.TransactionStack.DoLoad(workspace)
        return True

    @tran.TransactionalMethod('reload last workspace')
    def ReloadLastFile(self):
        """Opens a project file from MRU"""
        mru = context.mru
        if mru.GetCount() == 0:
            return False
        pf = mru.GetHistoryFile(0)
        if len(pf) == 0:
            return False
        import traceback
        import sys
        try:
            if re.match(r"(.)*\.pcc", pf):
                obj = context.app.LoadProject(pf)
                if not isinstance(obj, model.Project):
                    return False
            elif re.match(r"(.)*\.wrk", pf):
                obj = context.app.LoadWorkspace(pf)
                if not isinstance(obj, model.Workspace):
                    return False
            tran.TransactionStack.DoLoad(obj)
            # as special thing, expanding is good...
            #self.m_tree.Expand(obj=obj)
        except Exception as inst:
            traceback.print_exc(file=sys.stdout)
            print type(inst)     # the exception instance
            print inst.args      # arguments stored in .args
            print inst
            return False
        return True

    @tran.TransactionalMethod('open recent')
    def OnMRUFile(self, event):
        """Opens a project file from MRU"""
        mru = context.mru
        pf = mru.GetHistoryFile(event.GetId() - wx.ID_FILE1)
        if len(pf) == 0:
            return False
        import traceback
        import sys
        try:
            if re.match(r"(.)*\.pcc", pf):
                obj = context.app.LoadProject(pf)
                if not isinstance(obj, model.Project):
                    return False
            elif re.match(r"(.)*\.wrk", pf):
                obj = context.app.LoadWorkspace(pf)
                if not isinstance(obj, model.Workspace):
                    return False
            tran.TransactionStack.DoLoad(obj)
        except Exception as inst:
            traceback.print_exc(file=sys.stdout)
            print type(inst)     # the exception instance
            print inst.args      # arguments stored in .args
            print inst
            return False
        return True

    #def ClosePane(self, index):
    #    """This is a programatic page close"""
    #    if index == wx.NOT_FOUND:
    #        return

    def CloseCurrentDocPane(self, event):
        """This is a programatic page close"""
        index = self.docBook.GetSelection()
        page = self.docBook.GetPage(index)
        if hasattr(page, '_object'):
            obj = page._object
            obj._pane = None
            page.Commit()

        # We have a reported issue in ubuntu, with touch solution:
        # (from Manas Pathak on
        # http://thehacklist.blogspot.com.es/
        # 2010/06/resolving-murrinestyledrawbox-assertion.html)
        """When using Emacs 23 and a few other applications
        on Ubuntu running GNOME, I often get a irritatingly cryptic
        error message ** (emacs:25074): CRITICAL **: murrine_style_draw_box:
        assertion `height >= -1' failed. Turns out it has got
        something to do with the theme I'm running.

        Thanks to Alf, it is very easy to get rid of that by tweaking
        Gtk configuration. Modify the entry
        in /usr/share/themes/Ambiance/gtk-2.0/gtkrc
            from GtkRange::trough-under-steppers = 0 to
        GtkRange::trough-under-steppers = 1."""

        from activity.models.ui import pane
        if type(page) in [pane.MethodPane, pane.PyMethodPane,
            pane.ConstructorPane, pane.PyModulePane]:
            page.PreDelete()
        self.docBook.DeletePage(index)
        # after closing the pane, we must set the focus!
        index = self.docBook.GetSelection()
        if index != wx.NOT_FOUND:
            p = self.docBook.GetPage(index)
            if type(p) in [pane.MethodPane, pane.PyMethodPane,
                pane.ConstructorPane, pane.PyModulePane]:
                    p.m_editor.SetFocus()
                    p.Refresh()
                    p.Update()

    def OnViewPageChanged(self, event):
        """update menus"""
        index = self.viewBook.GetSelection()
        if index != wx.NOT_FOUND:
            page = self.viewBook.GetPage(index)
            if hasattr(page, 'NotifyShow'):
                page.NotifyShow()
        event.Skip()  # fails to skip will block event

    def OnViewPageClose(self, event):
        """update menus"""
        index = self.viewBook.GetSelection()
        if index != wx.NOT_FOUND:
            page = self.viewBook.GetPage(index)
            if hasattr(page, 'NotifyHide'):
                page.NotifyHide()
            if type(page) in self._views:
                del self._views[type(page)]
        event.Skip()  # fails to skip will block event

    def OnPageChanged(self, event):
        """update menus"""
        index = self.docBook.GetSelection()
        if index != wx.NOT_FOUND:
            page = self.docBook.GetPage(index)
            if hasattr(page, 'NotifyShow'):
                page.NotifyShow()
        self.m_mgr.Update()
        event.Skip()  # fails to skip will block event

    def OnViewPageChanging(self, event):
        """add menus"""
        index = self.viewBook.GetSelection()
        if index != wx.NOT_FOUND:
            page = self.viewBook.GetPage(index)
            if hasattr(page, 'NotifyHide'):
                page.NotifyHide()
        event.Skip()  # fails to skip will block event

    def OnPageChanging(self, event):
        """remove menus"""
        index = self.docBook.GetSelection()
        if index != wx.NOT_FOUND:
            page = self.docBook.GetPage(index)
            if hasattr(page, 'NotifyHide'):
                page.NotifyHide()
        event.Skip()  # fails to skip will block event

    def OnClosePane(self, event):
        """close pane"""
        index = event.GetSelection()
        page = self.docBook.GetPage(index)
        if hasattr(page, 'PreDelete'):
            page.PreDelete()
        if hasattr(page, '_object'):
            obj = page._object
            obj._pane = None
            page.Commit()
        if  index != self.docBook.GetSelection():
            return
        p = self.docBook.GetPage(index)
        if hasattr(p, 'm_editor'):
            p.m_editor.SetFocus()
        p.Refresh()
        p.Update()
        event.Skip()

    def OpenDoc(self, _class, obj):
        """Opens a document for a object"""
        assert not hasattr(obj, "_pane") or obj._pane is None
        # create document instance
        p = _class(self.docBook, self, obj)
        obj._pane = p
        self.docBook.AddPage(p, obj.name, True, obj.bitmap_index)

    def OnResetPerpective(self, event):
        """Reset default perspective"""
        self.m_mgr.LoadPerspective(self._mainPerspective)

    def OnOutputMessage(self, event):
        """Receives a output mensage for showing in output pane"""
        s = self.auxOutput.GetNumberOfLines() - 200
        if s > 0:
            k = sum((self.auxOutput.GetLineLength(i) for i in range(0, s))) + s
            self.auxOutput.Remove(0, k)
        self._output.LogTextAtLevel(event.level, event.message)

    def StopRunning(self):
        """Stop running process"""
        if not hasattr(self, '_runProcess'):
            # there are now a running process!!
            return True
        if self._runProcess:
            os.killpg(os.getpgid(self._runProcess.pid), signal.SIGTERM)

    def RunPythonScript(self, script):
        """Executes a python script, redirecting output to the output"""
        import subprocess
        import threading

        if hasattr(self, '_runProcess'):
            # there are now a running process!!
            return False

        # show output aux pane
        self.CleanOutputPane()
        if self.m_aux_panes.GetCurrentPage() != self.m_aux_output_pane:
            # we attempt to show output window if it exist (may be closed by the user)
            try:
                i = max(i for i in range(0, self.m_aux_panes.GetPageCount())
                    if self.m_aux_panes.GetPage(i) == self.m_aux_output_pane)
                self.m_aux_panes.SetSelection(i)
            except:
                pass

        def worker_pipe(self):
            """funcion que realiza el trabajo en el thread"""
            handler = self.GetEventHandler()
            handler.AddPendingEvent(wxx.LoggerEvent('watching process ...'))
            for line in iter(self._runProcess.stdout.readline, ""):
                handler.AddPendingEvent(wxx.LoggerEvent(line.strip()))
                wx.YieldIfNeeded()
            self._runProcess.stdout.close()
            self._runProcess.wait()
            del self._runProcess
            handler.AddPendingEvent(wxx.LoggerEvent('execution ended'))

        command = '/usr/bin/python {script}'.format(script=script)
        try:
            self._runProcess = subprocess.Popen(command,
                stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True,
                preexec_fn=os.setsid)
            threading.Thread(target=worker_pipe, args=(self,)).start()
        except:
            handler = self.GetEventHandler()
            handler.AddPendingEvent(wxx.LoggerEvent('execution failed'))

    def CleanOutputPane(self):
        """Clean the output pane"""
        self.auxOutput.SetValue(wx.EmptyString)

    def search_proc(self, text):
        """Search a the context specified files for text"""
        #activate output pane
        i = max(i for i in range(0, self.m_aux_panes.GetPageCount())
        if self.m_aux_panes.GetPage(i) == self.m_searchPane)
        self.m_aux_panes.SetSelection(i)
        #
        theApp = context.app
        maxResults = 200
        handler = self.GetEventHandler()
        for wrk in theApp.workspaces:
            for prj in wrk(model.Project):
                rdir = os.path.realpath(prj.dir)
                if not os.access(rdir, os.R_OK):
                    continue
                for dirName, subdirList, fileList in os.walk(rdir):
                    for fname in fileList:
                        #avoid scan hidden files
                        if re.match(r'^\.(.)*', fname):
                            continue
                        f = os.path.realpath(
                            os.path.join(dirName, fname))
                        if not os.access(f, os.R_OK):
                            continue
                        with open(f, "r") as sf:
                            cnt = 0
                            print f
                            for line in sf:
                                cnt = cnt + 1
                                try:
                                    if text in line:
                                        #post message(file/line)
                                        maxResults = maxResults - 1
                                        if maxResults <= 0:
                                            # avoid crashing
                                            handler.AddPendingEvent(wxx.SearchEvent(cnt, '**TRUNCATED**'))
                                            return 0
                                        handler.AddPendingEvent(
                                            wxx.SearchEvent(cnt, f))
                                except:
                                    pass
        return 0

    def OnFindInFiles(self, event):
        """Lanza el cuadro de dialogo de buscar"""
        theDialog = app.ui.dlg.FindInFilesDialog(self)
        if theDialog.ShowModal() != wx.ID_OK:
            return
        self.m_searchList.ClearAll()
        w, h = self.m_searchList.GetSize()
        self.m_searchList.InsertColumn(0, "file", width=w - 40)
        self.m_searchList.InsertColumn(1, "line", width=40)
        import threading
        threading.Thread(target=mainWindow.search_proc,
            args=(self, theDialog.searchString)).start()

    def OnSearchResults(self, event):
        """Put results in search pane"""
        m_list = self.m_searchList
        m_list.Append((event.fname, event.line))

    def OnSelectSearchItem(self, event):
        """Attempts to open the file"""
        index = event.GetIndex()
        try:
            import activity.files.ui.pane as fpane
            import model.file
            path = self.m_searchList.GetItem(index, 0).GetText()
            line = int(self.m_searchList.GetItem(index, 1).GetText())
            p = os.path.abspath(path)
            if re.match(r"(.)*\.cpp$", p) or re.match(r"(.)*\.h$", p):
                cls = fpane.FilePane
            elif re.match(r"(.)*\.py$", p):
                cls = fpane.FilePythonPane
            else:
                cls = fpane.TextPane
            for wrk in context.app.workspaces:
                items = wrk(model.file.File, filter=lambda x: x._file == p)
                if not len(items):
                    continue
                # Ordenamos la apertura del fichero
                obj = items[0]
                if hasattr(obj, '_pane') and obj._pane is not None:
                    self.docBook.SetSelection(
                        self.docBook.GetPageIndex(obj._pane))
                else:
                    self.OpenDoc(cls, obj)
                obj._pane.GotoLine(line - 1, True)
                self.m_searchList.SetFocus()
                break
        except:
            pass

