Exemple #1
0
    def __init__(self, giface, cmdfile=None, mapfile=None):
        """Map composition (stack of map layers and overlays)

        :param cmdline: full path to the cmd file (defined by d.mon)
        :param mapfile: full path to the map file (defined by d.mon)
        """

        Map.__init__(self)

        self._giface = giface

        # environment settings
        self.env   = dict()

        self.cmdfile = cmdfile

        # list of layers for rendering added from cmd file
        # TODO temporary solution, layer managment by different tools in GRASS should be resovled
        self.ownedLayers = []

        if mapfile:
            self.mapfileCmd = mapfile
            self.maskfileCmd = os.path.splitext(mapfile)[0] + '.pgm'

        # generated file for g.pnmcomp output for rendering the map
        self.mapfile = monFile['map']
        if os.path.splitext(self.mapfile)[1] != '.ppm':
            self.mapfile += '.ppm'
        
        # signal sent when d.out.file/d.to.rast appears in cmd file, attribute is cmd
        self.saveToFile = Signal('DMonMap.saveToFile')
        self.dToRast = Signal('DMonMap.dToRast')
        # signal sent when d.what.rast/vect appears in cmd file, attribute is cmd
        self.query = Signal('DMonMap.query')
Exemple #2
0
    def __init__(self, parent, giface, Map, properties, tree=None,
                 id=wx.ID_ANY, lmgr=None,
                 style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
        BufferedMapWindow.__init__(self, parent=parent, giface=giface, Map=Map,
                                   properties=properties,
                                   style=style, **kwargs)
        self.lmgr = lmgr
        self.tree = tree
        self.pdcVector = wx.PseudoDC()
        self.toolbar   = self.parent.GetToolbar('vdigit')
        self.digit     = None # wxvdigit.IVDigit
        self._digitizingInfo = False  # digitizing with info

        # Emitted when info about digitizing updated
        # Parameter text is a string with information
        # currently used only for coordinates of mouse cursor + segmnt and
        # total feature length
        self.digitizingInfo = Signal('VDigitWindow.digitizingInfo')
        # Emitted when some info about digitizing is or will be availbale
        self.digitizingInfoAvailable = Signal('VDigitWindow.digitizingInfo')
        # Emitted when some info about digitizing is or will be availbale
        # digitizingInfo signal is emmited only between digitizingInfoAvailable
        # and digitizingInfoUnavailable signals
        self.digitizingInfoUnavailable = Signal('VDigitWindow.digitizingInfo')

        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        self.mouseMoving.connect(self._mouseMovingToDigitizingInfo)
Exemple #3
0
    def __init__(self, bitmapPool, mapFilesPool, tempDir,
                 imageWidth=640, imageHeight=480):

        self._bitmapPool = bitmapPool
        self._mapFilesPool = mapFilesPool
        self.imageWidth = imageWidth  # width of the image to render with d.rast or d.vect
        # height of the image to render with d.rast or d.vect
        self.imageHeight = imageHeight
        self._tempDir = tempDir

        self._uniqueCmds = []
        self._cmdsForComposition = []
        self._opacities = []

        self._cmds3D = []
        self._regionFor3D = None
        self._regions = []
        self._regionsForUniqueCmds = []

        self._renderer = BitmapRenderer(self._mapFilesPool, self._tempDir,
                                        self.imageWidth, self.imageHeight)
        self._composer = BitmapComposer(self._tempDir, self._mapFilesPool,
                                        self._bitmapPool, self.imageWidth,
                                        self.imageHeight)
        self.renderingStarted = Signal('BitmapProvider.renderingStarted')
        self.compositionStarted = Signal('BitmapProvider.compositionStarted')
        self.renderingContinues = Signal('BitmapProvider.renderingContinues')
        self.compositionContinues = Signal(
            'BitmapProvider.compositionContinues')
        self.renderingFinished = Signal('BitmapProvider.renderingFinished')
        self.compositionFinished = Signal('BitmapProvider.compositionFinished')
        self.mapsLoaded = Signal('BitmapProvider.mapsLoaded')

        self._renderer.renderingContinues.connect(self.renderingContinues)
        self._composer.compositionContinues.connect(self.compositionContinues)
Exemple #4
0
class ProfileController(AnalysisControllerBase):
    """Class controls profiling in map display.
    It should be used inside ProfileFrame
    """
    def __init__(self, giface, mapWindow):
        AnalysisControllerBase.__init__(self, giface=giface, mapWindow=mapWindow)

        self.transectChanged = Signal('ProfileController.transectChanged')
        self._graphicsType = 'line'

    def _doAnalysis(self, coords):
        """Informs profile dialog that profile changed.

        :param coords: EN coordinates
        """
        self.transectChanged.emit(coords=coords)

    def _disconnectAll(self):
        self._mapWindow.mouseLeftDown.disconnect(self._start)
        self._mapWindow.mouseLeftUp.disconnect(self._addPoint)

    def _connectAll(self):
        self._mapWindow.mouseLeftDown.connect(self._start)
        self._mapWindow.mouseLeftUp.connect(self._addPoint)

    def _getPen(self):
        return wx.Pen(colour=wx.Colour(0, 100, 0), width=2, style=wx.SHORT_DASH)

    def Stop(self, restore=True):
        AnalysisControllerBase.Stop(self, restore=restore)

        self.transectChanged.emit(coords=[])
Exemple #5
0
    def __init__(self, guiparent, giface):

        self.data = {}

        self.guiparent = guiparent
        self.giface = giface
        self.mapWin = giface.GetMapWindow()

        self.goutput = GConsole(guiparent = guiparent) 

        self.vnet_data = VNETData(guiparent = guiparent, mapWin = self.mapWin)

        self.results = {"analysis" : None,
                        "vect_map" : None} #TODO more results

        # this class instance manages all temporary vector maps created during life of VNETDialog  
        self.tmp_maps = VNETTmpVectMaps(parent = guiparent, mapWin = self.mapWin)

        # initialization of History class used for saving and reading data from file
        # it is used for browsing analysis results
        self.history = VNETHistory(self.guiparent, self.vnet_data, self.tmp_maps)
        self.analyses = VNETAnalyses(self.vnet_data, self.RunAnDone, self.goutput, self.tmp_maps)

        self.snap_nodes = SnappingNodes(self.giface, self.vnet_data, self.tmp_maps, self.mapWin)

        self.ttbCreated = Signal('VNETManager.ttbCreated')
        self.analysisDone = Signal('VNETManager.analysisDone')
        self.pointsChanged = self.vnet_data.pointsChanged
        self.parametersChanged = self.vnet_data.parametersChanged

        self.snapping = self.snap_nodes.snapping
        self.pointsChanged.connect(self.PointsChanged)
    def __init__(self, giface, mapWindow):
        wx.EvtHandler.__init__(self)
        self._giface = giface
        self._mapWindow = mapWindow

        self._thread = gThread()
        self._editedRaster = None
        self._backgroundRaster = None
        self._backupRasterName = None
        self._areas = None
        self._lines = None
        self._points = None
        self._all = []
        self._drawing = False
        self._running = False
        self._drawColor = wx.GREEN
        self._drawTransparency = 100
        self._graphicsType = 'area'
        self._currentCellValue = None
        self._currentWidthValue = None

        self._oldMouseUse = None
        self._oldCursor = None

        self.newRasterCreated = Signal('RDigitController:newRasterCreated')
        self.newFeatureCreated = Signal('RDigitController:newFeatureCreated')
        self.uploadMapCategories = Signal('RDigitController:uploadMapCategories')
        self.quitDigitizer = Signal('RDigitController:quitDigitizer')
        self.showNotification = Signal('RDigitController:showNotification')
Exemple #7
0
    def __init__(self, layer, mapfile, maskfile):
        if not haveGdal:
            sys.stderr.write(_("Unable to load GDAL Python bindings.\n"\
                               "WMS layers can not be displayed without the bindings.\n"))

        self.layer = layer

        wx.EvtHandler.__init__(self)

        # thread for d.wms commands
        self.thread = CmdThread(self)
        self.Bind(EVT_CMD_DONE, self.OnDataFetched)

        self.downloading = False
        self.renderedRegion = None
        self.updateMap = True
        self.fetched_data_cmd = None

        self.cmdStdErr = GStderr(self)

        self.mapfile = mapfile
        self.maskfile = maskfile
        self.tempMap = grass.tempfile()
        self.dstSize = {}
 
        self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)
        
        self.dataFetched = Signal('RenderWMSMgr.dataFetched')
        self.updateProgress = Signal('RenderWMSMgr.updateProgress')
Exemple #8
0
    def __init__(self):
        self.statisticsDict = {}
        self.statisticsList = []

        self.statisticsAdded = Signal("StatisticsData.statisticsAdded") 
        self.statisticsDeleted = Signal("StatisticsData.statisticsDeleted") 
        self.allStatisticsDeleted = Signal("StatisticsData.allStatisticsDeleted") 

        self.statisticsSet = Signal("StatisticsData.statisticsSet") 
Exemple #9
0
 def __init__(self, mapframe, statusbar, sbManager, position=0):
     self.progressShown = Signal("SbProgress.progressShown")
     self.progressHidden = Signal("SbProgress.progressHidden")
     SbItem.__init__(self, mapframe, statusbar, position)
     self.name = "progress"
     self.sbManager = sbManager
     # on-render gauge
     self.widget = wx.Gauge(parent=self.statusbar, id=wx.ID_ANY, range=0, style=wx.GA_HORIZONTAL)
     self.Hide()
Exemple #10
0
 def __init__(self):
     self._resolution = None
     self.resolutionChanged = Signal('MapWindowProperties.resolutionChanged')
     self._autoRender = None
     self.autoRenderChanged = Signal('MapWindowProperties.autoRenderChanged')
     self._showRegion = None
     self.showRegionChanged = Signal('MapWindowProperties.showRegionChanged')
     self._alignExtent = None
     self.alignExtentChanged = Signal('MapWindowProperties.alignExtentChanged')
Exemple #11
0
    def __init__(self, parent, samplingType, icon=None, map_=None):
        wx.Panel.__init__(self, parent=parent)

        self.mapWindowProperties = MapWindowProperties()
        self.mapWindowProperties.setValuesFromUserSettings()
        giface = StandaloneGrassInterface()
        self.samplingtype = samplingType
        self.parent = parent

        if map_:
            self.map_ = map_
        else:
            self.map_ = Map()
        self.map_.region = self.map_.GetRegion()

        self._mgr = wx.aui.AuiManager(self)
        self.mapWindow = BufferedMapWindow(parent=self, giface=giface,
                                           Map=self.map_,
                                           properties=self.mapWindowProperties)
        self._mgr.AddPane(self.mapWindow, wx.aui.AuiPaneInfo().CentrePane().
                          Dockable(True).BestSize((-1, -1)).Name('mapwindow').
                          CloseButton(False).DestroyOnClose(True).
                          Layer(0))
        self._toolSwitcher = ToolSwitcher()
        self._toolSwitcher.toggleToolChanged.connect(self._onToolChanged)
        self.toolbar = RLiSetupToolbar(self, self._toolSwitcher)

        self.catId = 1

        self._mgr.AddPane(self.toolbar,
                          wx.aui.AuiPaneInfo().
                          Name("maptoolbar").Caption(_("Map Toolbar")).
                          ToolbarPane().Left().Name('mapToolbar').
                          CloseButton(False).Layer(1).Gripper(False).
                          BestSize((self.toolbar.GetBestSize())))
        self._mgr.Update()

        if self.samplingtype == SamplingType.REGIONS:
            self.afterRegionDrawn = Signal('RLiSetupMapPanel.afterRegionDrawn')
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='line')
        elif self.samplingtype in [SamplingType.MUNITSR, SamplingType.MMVWINR]:
            self.sampleFrameChanged = Signal('RLiSetupMapPanel.sampleFrameChanged')
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='rectangle')
        elif self.samplingtype in [SamplingType.MUNITSC, SamplingType.MMVWINC]:
            self.afterCircleDrawn = Signal('RLiSetupMapPanel.afterCircleDrawn')
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='line')
        else:
            self.sampleFrameChanged = Signal('RLiSetupMapPanel.sampleFrameChanged')
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='rectangle')

        self._registeredGraphics.AddPen('rlisetup', wx.Pen(wx.GREEN, width=2,
                                                           style=wx.SOLID))
        self._registeredGraphics.AddItem(coords=[[0, 0], [0, 0]],
                                         penName='rlisetup', hide=True)

        if self.samplingtype != SamplingType.VECT:
            self.toolbar.SelectDefault()
Exemple #12
0
    def __init__(self, giface, mapWindow):
        """Constructs controller

        :param giface: grass interface object
        :param mapWindow: instance of BufferedMapWindow
        """
        wx.EvtHandler.__init__(self)
        self._giface = giface
        self._mapWindow = mapWindow

        # thread for running rasterization process
        self._thread = gThread()
        # name of raster map which is edited (also new one)
        self._editedRaster = None
        # name of optional background raster
        self._backgroundRaster = None
        # name of temporary raster used to backup original state
        self._backupRasterName = None
        # if we edit an old raster or a new one (important for setting color
        # table)
        self._editOldRaster = False
        # type of output raster map (CELL, FCELL, DCELL)
        self._mapType = None
        # GraphicsSet for drawing areas, lines, points
        self._areas = None
        self._lines = None
        self._points = None
        # list of all GraphicsItems in the order of drawing
        self._all = []
        # if in state of drawing lin or area
        self._drawing = False
        # if running digitizing process in thread (to block drawing)
        self._running = False
        # color used to draw (should be moved to settings)
        self._drawColor = wx.GREEN
        # transparency used to draw (should be moved to settings)
        self._drawTransparency = 100
        # current selected drawing method
        self._graphicsType = 'area'
        # last edited cell value
        self._currentCellValue = None
        # last edited buffer value
        self._currentWidthValue = None

        self._oldMouseUse = None
        self._oldCursor = None

        # signal to add new raster to toolbar items
        self.newRasterCreated = Signal('RDigitController:newRasterCreated')
        # signal to add just used cell value in toolbar combo
        self.newFeatureCreated = Signal('RDigitController:newFeatureCreated')
        # signal to upload unique categories of background map into toolbar
        # combo
        self.uploadMapCategories = Signal(
            'RDigitController:uploadMapCategories')
        self.quitDigitizer = Signal('RDigitController:quitDigitizer')
        self.showNotification = Signal('RDigitController:showNotification')
Exemple #13
0
    def __init__(self, guiparent, giface, iclass_mapwin=None):
        self.giface = giface
        self.mapDisp = giface.GetMapDisplay()

        if iclass_mapwin:
            self.mapWin = iclass_mapwin
        else:
            self.mapWin = giface.GetMapWindow()

        self.guiparent = guiparent

        self.show_add_scatt_plot = False

        self.core = Core()

        self.cats_mgr = CategoriesManager(self, self.core)
        self.render_mgr = PlotsRenderingManager(scatt_mgr=self,
                                                cats_mgr=self.cats_mgr,
                                                core=self.core)

        self.thread = gThread()

        self.plots = {}

        self.plot_mode = None
        self.pol_sel_mode = [False, None]

        self.data_set = False

        self.cursorPlotMove = Signal("ScattsManager.cursorPlotMove")

        self.renderingStarted = self.render_mgr.renderingStarted
        self.renderingFinished = self.render_mgr.renderingFinished

        self.computingStarted = Signal("ScattsManager.computingStarted")

        if iclass_mapwin:
            self.digit_conn = IClassDigitConnection(self,
                                                    self.mapWin,
                                                    self.core.CatRastUpdater())
            self.iclass_conn = IClassConnection(self,
                                                iclass_mapwin.parent,
                                                self.cats_mgr)
        else:
            self.digit_conn = IMapWinDigitConnection()
            self.iclass_conn = IMapDispConnection(scatt_mgr=self,
                                                  cats_mgr=self.cats_mgr,
                                                  giface=self.giface)

        self._initSettings()

        self.modeSet = Signal("ScattsManager.mondeSet")
Exemple #14
0
    def __init__(self, parent, menuModel, margin = False):
        GPrompt.__init__(self, parent = parent, menuModel = menuModel)
        wx.stc.StyledTextCtrl.__init__(self, self.panel, id = wx.ID_ANY)
        
        #
        # styles
        #                
        self.SetWrapMode(True)
        self.SetUndoCollection(True)        
        
        #
        # create command and map lists for autocompletion
        #
        self.AutoCompSetIgnoreCase(False) 
                
        #
        # line margins
        #
        # TODO print number only from cmdlog
        self.SetMarginWidth(1, 0)
        self.SetMarginWidth(2, 0)
        if margin:
            self.SetMarginType(0, wx.stc.STC_MARGIN_NUMBER)
            self.SetMarginWidth(0, 30)
        else:
            self.SetMarginWidth(0, 0)
        
        #
        # miscellaneous
        #
        self.SetViewWhiteSpace(False)
        self.SetUseTabs(False)
        self.UsePopUp(True)
        self.SetSelBackground(True, "#FFFF00")
        self.SetUseHorizontalScrollBar(True)
        
        #
        # bindings
        #
        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
        self.Bind(wx.EVT_CHAR, self.OnChar)
        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
        self.Bind(wx.stc.EVT_STC_AUTOCOMP_SELECTION, self.OnItemSelected)
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemChanged)
        if sys.platform != 'darwin':  # unstable on Mac with wxPython 3
            self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)

        # signal which requests showing of a notification
        self.showNotification = Signal('GPromptSTC.showNotification')

        # signal to notify selected command
        self.commandSelected = Signal('GPromptSTC.commandSelected')
Exemple #15
0
    def __init__(self, giface, cmdfile=None, mapfile=None):
        """Map composition (stack of map layers and overlays)

        :param cmdline: full path to the cmd file (defined by d.mon)
        :param mapfile: full path to the map file (defined by d.mon)
        """
        Map.__init__(self)

        self._giface = giface

        # environment settings
        self.env = dict()

        self.cmdfile = cmdfile

        # list of layers for rendering added from cmd file
        # TODO temporary solution, layer managment by different tools in GRASS
        # should be resovled
        self.ownedLayers = []
        self.oldOverlays = []

        if mapfile:
            self.mapfileCmd = mapfile
            self.maskfileCmd = os.path.splitext(mapfile)[0] + '.pgm'

        # generated file for g.pnmcomp output for rendering the map
        self.mapfile = monFile['map']
        if os.path.splitext(self.mapfile)[1] != '.ppm':
            self.mapfile += '.ppm'

        # signal sent when d.out.file/d.to.rast appears in cmd file, attribute
        # is cmd
        self.saveToFile = Signal('DMonMap.saveToFile')
        self.dToRast = Signal('DMonMap.dToRast')
        # signal sent when d.what.rast/vect appears in cmd file, attribute is
        # cmd
        self.query = Signal('DMonMap.query')

        self.renderMgr = RenderMapMgr(self)

        # update legend file variable with the one d.mon uses
        with open(monFile['env'], 'r') as f:
            lines = f.readlines()
            for line in lines:
                if 'GRASS_LEGEND_FILE' in line:
                    legfile = line.split('=', 1)[1].strip()
                    self.renderMgr.UpdateRenderEnv({'GRASS_LEGEND_FILE': legfile})
                    break
Exemple #16
0
    def __init__(self, gisrc = None):
        """Map composition (stack of map layers and overlays)

        :param gisrc: alternative gisrc (used eg. by georectifier)
        """
        # region/extent settigns
        self.wind      = dict() # WIND settings (wind file)
        self.region    = dict() # region settings (g.region)
        self.width     = 640    # map width
        self.height    = 480    # map height

        # list of layers
        self.layers    = list()  # stack of available GRASS layer

        self.overlays  = list()  # stack of available overlays
        self.ovlookup  = dict()  # lookup dictionary for overlay items and overlays

        # path to external gisrc
        self.gisrc = gisrc

        # generated file for g.pnmcomp output for rendering the map
        self.mapfile = grass.tempfile(create = False) + '.ppm'

        # setting some initial env. variables
        if not self.GetWindow():
            sys.stderr.write(_("Trying to recover from default region..."))
            RunCommand('g.region', flags='d')

        # info to report progress
        self.progressInfo = None

        # GRASS environment variable (for rendering)
        self.default_env = {"GRASS_RENDER_BACKGROUNDCOLOR" : "000000",
                            "GRASS_RENDER_FILE_COMPRESSION" : "0",
                            "GRASS_RENDER_TRUECOLOR"       : "TRUE",
                            "GRASS_RENDER_TRANSPARENT"     : "TRUE"
                            }

        # projection info
        self.projinfo = self._projInfo()

        # is some layer being downloaded?
        self.downloading = False

        self.layerChanged = Signal('Map.layerChanged')
        self.updateProgress = Signal('Map.updateProgress')
        self.layerRemoved = Signal('Map:layerRemoved')
        self.layerAdded = Signal('Map:layerAdded')
Exemple #17
0
    def __init__(self, scatt_mgr, core):

        self.core = core
        self.scatt_mgr = scatt_mgr

        self.cats = {}
        self.cats_ids = []

        self.sel_cat_id = None

        self.exportRaster = None

        self.initialized = Signal('CategoriesManager.initialized')
        self.setCategoryAttrs = Signal('CategoriesManager.setCategoryAttrs')
        self.deletedCategory = Signal('CategoriesManager.deletedCategory')
        self.addedCategory = Signal('CategoriesManager.addedCategory')
Exemple #18
0
class GConsole(wx.EvtHandler):
    """
    """
    def __init__(self, guiparent=None, giface=None, ignoredCmdPattern=None):
        """
        :param guiparent: parent window for created GUI objects
        :param lmgr: layer manager window (TODO: replace by giface)
        :param ignoredCmdPattern: regular expression specifying commads
                                  to be ignored (e.g. @c '^d\..*' for
                                  display commands)
        """
        wx.EvtHandler.__init__(self)

        # Signal when some map is created or updated by a module.
        # attributes: name: map name, ltype: map type,
        self.mapCreated = Signal('GConsole.mapCreated')
        # emitted when map display should be re-render
        self.updateMap = Signal('GConsole.updateMap')
        # emitted when log message should be written
        self.writeLog = Signal('GConsole.writeLog')
        # emitted when command log message should be written
        self.writeCmdLog = Signal('GConsole.writeCmdLog')
        # emitted when warning message should be written
        self.writeWarning = Signal('GConsole.writeWarning')
        # emitted when error message should be written
        self.writeError = Signal('GConsole.writeError')

        self._guiparent = guiparent
        self._giface = giface
        self._ignoredCmdPattern = ignoredCmdPattern

        # create queues
        self.requestQ = Queue.Queue()
        self.resultQ = Queue.Queue()

        self.cmdOutputTimer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnProcessPendingOutputWindowEvents)
        self.Bind(EVT_CMD_RUN, self.OnCmdRun)
        self.Bind(EVT_CMD_DONE, self.OnCmdDone)
        self.Bind(EVT_CMD_ABORT, self.OnCmdAbort)

        # stream redirection
        self.cmdStdOut = GStdout(receiver=self)
        self.cmdStdErr = GStderr(receiver=self)

        # thread
        self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)

    def Redirect(self):
        """Redirect stdout/stderr
        """
        if Debug.GetLevel() == 0 and int(grass.gisenv().get('DEBUG', 0)) == 0:
            # don't redirect when debugging is enabled
            sys.stdout = self.cmdStdOut
            sys.stderr = self.cmdStdErr
        else:
            enc = locale.getdefaultlocale()[1]
            if enc:
                sys.stdout = codecs.getwriter(enc)(sys.__stdout__)
                sys.stderr = codecs.getwriter(enc)(sys.__stderr__)
            else:
                sys.stdout = sys.__stdout__
                sys.stderr = sys.__stderr__

    def WriteLog(self,
                 text,
                 style=None,
                 wrap=None,
                 notification=Notification.HIGHLIGHT):
        """Generic method for writing log message in
        given style

        :param text: text line
        :param notification: form of notification
        """
        self.writeLog.emit(text=text, wrap=wrap, notification=notification)

    def WriteCmdLog(self,
                    text,
                    pid=None,
                    notification=Notification.MAKE_VISIBLE):
        """Write message in selected style

        :param text: message to be printed
        :param pid: process pid or None
        :param notification: form of notification
        """
        self.writeCmdLog.emit(text=text, pid=pid, notification=notification)

    def WriteWarning(self, text):
        """Write message in warning style"""
        self.writeWarning.emit(text=text)

    def WriteError(self, text):
        """Write message in error style"""
        self.writeError.emit(text=text)

    def RunCmd(self,
               command,
               compReg=True,
               skipInterface=False,
               onDone=None,
               onPrepare=None,
               userData=None,
               notification=Notification.MAKE_VISIBLE):
        """Run command typed into console command prompt (GPrompt).

        .. todo::
            Document the other event.
        .. todo::
            Solve problem with the other event (now uses gOutputText
            event but there is no text, use onPrepare handler instead?)

        Posts event EVT_IGNORED_CMD_RUN when command which should be ignored
        (according to ignoredCmdPattern) is run.
        For example, see layer manager which handles d.* on its own.

        :param command: command given as a list (produced e.g. by utils.split())
        :param compReg: True use computation region
        :param notification: form of notification
        :param bool skipInterface: True to do not launch GRASS interface
                                   parser when command has no arguments
                                   given
        :param onDone: function to be called when command is finished
        :param onPrepare: function to be called before command is launched
        :param userData: data defined for the command
        """
        if len(command) == 0:
            Debug.msg(2, "GPrompt:RunCmd(): empty command")
            return

        # update history file
        self.UpdateHistoryFile(' '.join(command))

        if command[0] in globalvar.grassCmd:
            # send GRASS command without arguments to GUI command interface
            # except ignored commands (event is emitted)

            if self._ignoredCmdPattern and \
              re.compile(self._ignoredCmdPattern).search(' '.join(command)) and \
              '--help' not in command and '--ui' not in command:
                event = gIgnoredCmdRun(cmd=command)
                wx.PostEvent(self, event)
                return

            else:
                # other GRASS commands (r|v|g|...)
                try:
                    task = GUI(show=None).ParseCommand(command)
                except GException as e:
                    GError(parent=self._guiparent,
                           message=unicode(e),
                           showTraceback=False)
                    return

                hasParams = False
                if task:
                    options = task.get_options()
                    hasParams = options['params'] and options['flags']
                    # check for <input>=-
                    for p in options['params']:
                        if p.get('prompt', '') == 'input' and \
                                p.get('element', '') == 'file' and \
                                p.get('age', 'new') == 'old' and \
                                p.get('value', '') == '-':
                            GError(
                                parent=self._guiparent,
                                message=
                                _("Unable to run command:\n%(cmd)s\n\n"
                                  "Option <%(opt)s>: read from standard input is not "
                                  "supported by wxGUI") % {
                                      'cmd': ' '.join(command),
                                      'opt': p.get('name', '')
                                  })
                            return

                if len(command) == 1 and hasParams and \
                        command[0] != 'v.krige':
                    # no arguments given
                    try:
                        GUI(parent=self._guiparent,
                            giface=self._giface).ParseCommand(command)
                    except GException as e:
                        print >> sys.stderr, e
                    return

                # activate computational region (set with g.region)
                # for all non-display commands.
                if compReg:
                    tmpreg = os.getenv("GRASS_REGION")
                    if "GRASS_REGION" in os.environ:
                        del os.environ["GRASS_REGION"]

                # process GRASS command with argument
                self.cmdThread.RunCmd(command,
                                      stdout=self.cmdStdOut,
                                      stderr=self.cmdStdErr,
                                      onDone=onDone,
                                      onPrepare=onPrepare,
                                      userData=userData,
                                      env=os.environ.copy(),
                                      notification=notification)
                self.cmdOutputTimer.Start(50)

                # deactivate computational region and return to display settings
                if compReg and tmpreg:
                    os.environ["GRASS_REGION"] = tmpreg
        else:
            # Send any other command to the shell. Send output to
            # console output window
            #
            # Check if the script has an interface (avoid double-launching
            # of the script)

            # check if we ignore the command (similar to grass commands part)
            if self._ignoredCmdPattern and \
               re.compile(self._ignoredCmdPattern).search(' '.join(command)):
                event = gIgnoredCmdRun(cmd=command)
                wx.PostEvent(self, event)
                return

            skipInterface = True
            if os.path.splitext(command[0])[1] in ('.py', '.sh'):
                try:
                    sfile = open(command[0], "r")
                    for line in sfile.readlines():
                        if len(line) < 2:
                            continue
                        if line[0] is '#' and line[1] is '%':
                            skipInterface = False
                            break
                    sfile.close()
                except IOError:
                    pass

            if len(command) == 1 and not skipInterface:
                try:
                    task = gtask.parse_interface(command[0])
                except:
                    task = None
            else:
                task = None

            if task:
                # process GRASS command without argument
                GUI(parent=self._guiparent,
                    giface=self._giface).ParseCommand(command)
            else:
                self.cmdThread.RunCmd(command,
                                      stdout=self.cmdStdOut,
                                      stderr=self.cmdStdErr,
                                      onDone=onDone,
                                      onPrepare=onPrepare,
                                      userData=userData,
                                      notification=notification)
            self.cmdOutputTimer.Start(50)

    def GetLog(self, err=False):
        """Get widget used for logging

        .. todo::
           what's this?

        :param bool err: True to get stderr widget
        """
        if err:
            return self.cmdStdErr

        return self.cmdStdOut

    def GetCmd(self):
        """Get running command or None"""
        return self.requestQ.get()

    def OnCmdAbort(self, event):
        """Abort running command"""
        self.cmdThread.abort()
        event.Skip()

    def OnCmdRun(self, event):
        """Run command"""
        self.WriteCmdLog('(%s)\n%s' % (str(time.ctime()), ' '.join(event.cmd)),
                         notification=event.notification)
        event.Skip()

    def OnCmdDone(self, event):
        """Command done (or aborted)

        Sends signal mapCreated if map is recognized in output
        parameters or for specific modules (as r.colors).
        """
        # Process results here
        try:
            ctime = time.time() - event.time
            if ctime < 60:
                stime = _("%d sec") % int(ctime)
            else:
                mtime = int(ctime / 60)
                stime = _("%(min)d min %(sec)d sec") % {
                    'min': mtime,
                    'sec': int(ctime - (mtime * 60))
                }
        except KeyError:
            # stopped deamon
            stime = _("unknown")

        if event.aborted:
            # Thread aborted (using our convention of None return)
            self.WriteWarning(
                _('Please note that the data are left in'
                  ' inconsistent state and may be corrupted'))
            msg = _('Command aborted')
        else:
            msg = _('Command finished')

        self.WriteCmdLog('(%s) %s (%s)' % (str(time.ctime()), msg, stime),
                         notification=event.notification)

        if event.onDone:
            event.onDone(cmd=event.cmd, returncode=event.returncode)

        self.cmdOutputTimer.Stop()

        if event.cmd[0] == 'g.gisenv':
            Debug.SetLevel()
            self.Redirect()

        # do nothing when no map added
        if event.returncode != 0 or event.aborted:
            event.Skip()
            return

        if event.cmd[0] not in globalvar.grassCmd:
            return

        # find which maps were created
        try:
            task = GUI(show=None).ParseCommand(event.cmd)
        except GException as e:
            print >> sys.stderr, e
            task = None
            return

        name = task.get_name()
        for p in task.get_options()['params']:
            prompt = p.get('prompt', '')
            if prompt in ('raster', 'vector', '3d-raster') and p.get(
                    'value', None):
                if p.get('age', 'old') == 'new' or \
                        name in ('r.colors', 'r3.colors', 'v.colors', 'v.proj', 'r.proj'):
                    # if multiple maps (e.g. r.series.interp), we need add each
                    if p.get('multiple', False):
                        lnames = p.get('value').split(',')
                        # in case multiple input (old) maps in r.colors
                        # we don't want to rerender it multiple times! just once
                        if p.get('age', 'old') == 'old':
                            lnames = lnames[0:1]
                    else:
                        lnames = [p.get('value')]
                    for lname in lnames:
                        if '@' not in lname:
                            lname += '@' + grass.gisenv()['MAPSET']
                        self.mapCreated.emit(name=lname, ltype=prompt)
        if name == 'r.mask':
            self.updateMap.emit()

        event.Skip()

    def OnProcessPendingOutputWindowEvents(self, event):
        wx.GetApp().ProcessPendingEvents()

    def UpdateHistoryFile(self, command):
        """Update history file
        
        :param command: the command given as a string
        """
        env = grass.gisenv()
        try:
            filePath = os.path.join(env['GISDBASE'], env['LOCATION_NAME'],
                                    env['MAPSET'], '.bash_history')
            fileHistory = codecs.open(filePath, encoding='utf-8', mode='a')
        except IOError as e:
            GError(
                _("Unable to write file '%(filePath)s'.\n\nDetails: %(error)s")
                % {
                    'filePath': filePath,
                    'error': e
                },
                parent=self._guiparent)
            return

        try:
            fileHistory.write(command + os.linesep)
        finally:
            fileHistory.close()

        # update wxGUI prompt
        if self._giface:
            self._giface.UpdateCmdHistory(command)
Exemple #19
0
class RLiSetupMapPanel(wx.Panel):
    """Panel with mapwindow used in r.li.setup"""
    def __init__(self, parent, samplingType, icon=None, map_=None):
        wx.Panel.__init__(self, parent=parent)

        self.mapWindowProperties = MapWindowProperties()
        self.mapWindowProperties.setValuesFromUserSettings()
        giface = StandaloneGrassInterface()
        self.samplingtype = samplingType
        self.parent = parent

        if map_:
            self.map_ = map_
        else:
            self.map_ = Map()
        self.map_.region = self.map_.GetRegion()

        self._mgr = wx.aui.AuiManager(self)
        self.mapWindow = BufferedMapWindow(
            parent=self,
            giface=giface,
            Map=self.map_,
            properties=self.mapWindowProperties,
        )
        self._mgr.AddPane(
            self.mapWindow,
            wx.aui.AuiPaneInfo().CentrePane().Dockable(True).BestSize(
                (-1, -1)).Name("mapwindow").CloseButton(False).DestroyOnClose(
                    True).Layer(0),
        )
        self._toolSwitcher = ToolSwitcher()
        self._toolSwitcher.toggleToolChanged.connect(self._onToolChanged)
        self.toolbar = RLiSetupToolbar(self, self._toolSwitcher)

        self.catId = 1

        self._mgr.AddPane(
            self.toolbar,
            wx.aui.AuiPaneInfo().Name("maptoolbar").Caption(
                _("Map Toolbar")).ToolbarPane().Left().Name("mapToolbar").
            CloseButton(False).Layer(1).Gripper(False).BestSize(
                (self.toolbar.GetBestSize())),
        )
        self._mgr.Update()

        if self.samplingtype == SamplingType.REGIONS:
            self.afterRegionDrawn = Signal("RLiSetupMapPanel.afterRegionDrawn")
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
                graphicsType="line")
        elif self.samplingtype in [SamplingType.MUNITSR, SamplingType.MMVWINR]:
            self.sampleFrameChanged = Signal(
                "RLiSetupMapPanel.sampleFrameChanged")
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
                graphicsType="rectangle")
        elif self.samplingtype in [SamplingType.MUNITSC, SamplingType.MMVWINC]:
            self.afterCircleDrawn = Signal("RLiSetupMapPanel.afterCircleDrawn")
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
                graphicsType="line")
        else:
            self.sampleFrameChanged = Signal(
                "RLiSetupMapPanel.sampleFrameChanged")
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
                graphicsType="rectangle")

        self._registeredGraphics.AddPen(
            "rlisetup", wx.Pen(wx.GREEN, width=2, style=wx.SOLID))
        self._registeredGraphics.AddItem(coords=[[0, 0], [0, 0]],
                                         penName="rlisetup",
                                         hide=True)

        if self.samplingtype != SamplingType.VECT:
            self.toolbar.SelectDefault()

    def GetMap(self):
        return self.map_

    def OnPan(self, event):
        """Panning, set mouse to drag."""
        self.mapWindow.SetModePan()

    def OnZoomIn(self, event):
        """Zoom in the map."""
        self.mapWindow.SetModeZoomIn()

    def OnZoomOut(self, event):
        """Zoom out the map."""
        self.mapWindow.SetModeZoomOut()

    def OnZoomToMap(self, event):
        layers = self.map_.GetListOfLayers()
        self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)

    def OnDrawRadius(self, event):
        """Start draw mode"""
        self.mapWindow.mouse["use"] = "None"
        self.mapWindow.mouse["box"] = "line"
        self.mapWindow.pen = wx.Pen(colour=wx.RED,
                                    width=1,
                                    style=wx.SHORT_DASH)
        self.mapWindow.SetNamedCursor("cross")
        self.mapWindow.mouseLeftUp.connect(self._radiusDrawn)

    def OnDigitizeRegion(self, event):
        """Start draw mode"""
        self.mapWindow.mouse["use"] = "None"
        self.mapWindow.mouse["box"] = "line"
        self.mapWindow.pen = wx.Pen(colour=wx.RED,
                                    width=1,
                                    style=wx.SHORT_DASH)
        self.mapWindow.SetNamedCursor("cross")
        self.mapWindow.mouseLeftUp.connect(self._lineSegmentDrawn)
        self.mapWindow.mouseDClick.connect(self._mouseDbClick)

        self._registeredGraphics.GetItem(0).SetCoords([])

    def OnDraw(self, event):
        """Start draw mode"""
        self.mapWindow.mouse["use"] = "None"
        self.mapWindow.mouse["box"] = "box"
        self.mapWindow.pen = wx.Pen(colour=wx.RED,
                                    width=2,
                                    style=wx.SHORT_DASH)
        self.mapWindow.SetNamedCursor("cross")
        self.mapWindow.mouseLeftUp.connect(self._rectangleDrawn)

    def _lineSegmentDrawn(self, x, y):
        item = self._registeredGraphics.GetItem(0)
        coords = item.GetCoords()
        if len(coords) == 0:
            coords.extend(
                [self.mapWindow.Pixel2Cell(self.mapWindow.mouse["begin"])])
        coords.extend([[x, y]])

        item.SetCoords(coords)
        item.SetPropertyVal("hide", False)
        self.mapWindow.ClearLines()
        self._registeredGraphics.Draw()

    def _mouseDbClick(self, x, y):
        item = self._registeredGraphics.GetItem(0)
        coords = item.GetCoords()
        coords.extend([[x, y]])
        item.SetCoords(coords)
        item.SetPropertyVal("hide", False)
        self.mapWindow.ClearLines()
        self._registeredGraphics.Draw()
        self.createRegion()

    def createRegion(self):
        dlg = wx.TextEntryDialog(None, "Name of sample region",
                                 "Create region", "region" + str(self.catId))
        ret = dlg.ShowModal()
        while True:
            if ret == wx.ID_OK:
                raster = dlg.GetValue()
                if checkMapExists(raster):
                    GMessage(
                        parent=self,
                        message=_("The raster file %s already"
                                  " exists, please change name") % raster,
                    )
                    ret = dlg.ShowModal()
                else:
                    dlg.Destroy()
                    marea = self.writeArea(
                        self._registeredGraphics.GetItem(0).GetCoords(),
                        raster)
                    self.nextRegion(next=True, area=marea)
                    break
            else:
                self.nextRegion(next=False)
                break

    def nextRegion(self, next=True, area=None):
        self.mapWindow.ClearLines()
        item = self._registeredGraphics.GetItem(0)
        item.SetCoords([])
        item.SetPropertyVal("hide", True)

        layers = self.map_.GetListOfLayers()
        self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
        if next is True:
            self.afterRegionDrawn.emit(marea=area)
        else:
            gcmd.GMessage(
                parent=self.parent,
                message=_("Raster map not created. Please redraw region."),
            )

    def writeArea(self, coords, rasterName):
        polyfile = tempfile.NamedTemporaryFile(delete=False)
        polyfile.write("AREA\n")
        for coor in coords:
            east, north = coor
            point = " %s %s\n" % (east, north)
            polyfile.write(point)

        catbuf = "=%d a\n" % self.catId
        polyfile.write(catbuf)
        self.catId = self.catId + 1

        polyfile.close()
        region_settings = grass.parse_command("g.region",
                                              flags="p",
                                              delimiter=":")
        pname = polyfile.name.split("/")[-1]
        tmpraster = "rast_" + pname
        tmpvector = "vect_" + pname
        wx.BeginBusyCursor()
        wx.GetApp().Yield()
        RunCommand(
            "r.in.poly",
            input=polyfile.name,
            output=tmpraster,
            rows=region_settings["rows"],
            overwrite=True,
        )

        RunCommand("r.to.vect",
                   input=tmpraster,
                   output=tmpvector,
                   type="area",
                   overwrite=True)

        RunCommand("v.to.rast",
                   input=tmpvector,
                   output=rasterName,
                   value=1,
                   use="val")
        wx.EndBusyCursor()
        grass.use_temp_region()
        grass.run_command("g.region", vector=tmpvector)
        region = grass.region()

        marea = MaskedArea(region, rasterName)

        RunCommand("g.remove", flags="f", type="raster", name=tmpraster)
        RunCommand("g.remove", flags="f", type="vector", name=tmpvector)

        os.unlink(polyfile.name)
        return marea

    def _onToolChanged(self):
        """Helper function to disconnect drawing"""
        try:
            self.mapWindow.mouseLeftUp.disconnect(self._rectangleDrawn)
            self.mapWindow.mouseLeftUp.disconnect(self._radiusDrawn)
            self.mapWindow.mouseMoving.disconnect(self._mouseMoving)
            self.mapWindow.mouseLeftDown.disconnect(self._mouseLeftDown)
            self.mapWindow.mouseDClick.disconnect(self._mouseDbClick)
        except DispatcherKeyError:
            pass

    def _radiusDrawn(self, x, y):
        """When drawing finished, get region values"""
        mouse = self.mapWindow.mouse
        item = self._registeredGraphics.GetItem(0)
        p1 = mouse["begin"]
        p2 = mouse["end"]
        dist, (north, east) = self.mapWindow.Distance(p1, p2, False)
        circle = Circle(p1, dist)
        self.mapWindow.ClearLines()
        self.mapWindow.pdcTmp.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
        pen = wx.Pen(colour=wx.RED, width=2)
        self.mapWindow.pdcTmp.SetPen(pen)
        self.mapWindow.pdcTmp.DrawCircle(circle.point[0], circle.point[1],
                                         circle.radius)
        self._registeredGraphics.Draw()
        self.createCricle(circle)

    def createCricle(self, c):
        dlg = wx.TextEntryDialog(
            None,
            "Name of sample circle region",
            "Create circle region",
            "circle" + str(self.catId),
        )
        ret = dlg.ShowModal()
        while True:
            if ret == wx.ID_OK:
                raster = dlg.GetValue()
                if checkMapExists(raster):
                    GMessage(
                        parent=self,
                        message=_("The raster file %s already"
                                  " exists, please change name") % raster,
                    )
                    ret = dlg.ShowModal()
                else:
                    dlg.Destroy()
                    circle = self.writeCircle(c, raster)
                    self.nextCircle(next=True, circle=circle)
                    break
            else:
                self.nextCircle(next=False)
                break

    def nextCircle(self, next=True, circle=None):
        self.mapWindow.ClearLines()
        item = self._registeredGraphics.GetItem(0)
        item.SetPropertyVal("hide", True)
        layers = self.map_.GetListOfLayers()
        self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
        if next is True:
            self.afterCircleDrawn.emit(region=circle)
        else:
            gcmd.GMessage(
                parent=self.parent,
                message=_("Raster map not created. redraw region again."),
            )

    def writeCircle(self, circle, rasterName):
        coords = self.mapWindow.Pixel2Cell(circle.point)
        RunCommand(
            "r.circle",
            output=rasterName,
            max=circle.radius,
            coordinate=coords,
            flags="b",
        )
        grass.use_temp_region()
        grass.run_command("g.region", zoom=rasterName)
        region = grass.region()
        marea = MaskedArea(region, rasterName, circle.radius)
        return marea

    def _rectangleDrawn(self):
        """When drawing finished, get region values"""
        mouse = self.mapWindow.mouse
        item = self._registeredGraphics.GetItem(0)
        p1 = self.mapWindow.Pixel2Cell(mouse["begin"])
        p2 = self.mapWindow.Pixel2Cell(mouse["end"])
        item.SetCoords([p1, p2])
        region = {
            "n": max(p1[1], p2[1]),
            "s": min(p1[1], p2[1]),
            "w": min(p1[0], p2[0]),
            "e": max(p1[0], p2[0]),
        }
        item.SetPropertyVal("hide", False)
        self.mapWindow.ClearLines()
        self._registeredGraphics.Draw()
        if self.samplingtype in [SamplingType.MUNITSR, SamplingType.MMVWINR]:
            dlg = wx.MessageDialog(
                self,
                "Is this area ok?",
                "select sampling unit",
                wx.YES_NO | wx.ICON_QUESTION,
            )
            ret = dlg.ShowModal()
            if ret == wx.ID_YES:
                grass.use_temp_region()
                grass.run_command(
                    "g.region",
                    n=region["n"],
                    s=region["s"],
                    e=region["e"],
                    w=region["w"],
                )
                tregion = grass.region()
                self.sampleFrameChanged.emit(region=tregion)
                self.mapWindow.ClearLines()
                item = self._registeredGraphics.GetItem(0)
                item.SetPropertyVal("hide", True)
                layers = self.map_.GetListOfLayers()
                self.mapWindow.ZoomToMap(layers=layers,
                                         ignoreNulls=False,
                                         render=True)
            else:
                self.nextRegion(next=False)
            dlg.Destroy()

        elif self.samplingtype != SamplingType.WHOLE:
            """When drawing finished, get region values"""
            self.sampleFrameChanged.emit(region=region)
Exemple #20
0
class DataCatalogTree(LocationMapTree):
    def __init__(self, parent, giface=None):
        """Data Catalog Tree constructor."""
        super(DataCatalogTree, self).__init__(parent)
        self._giface = giface
        self._restricted = True

        self._initVariablesCatalog()
        self.beginDrag = Signal('DataCatalogTree.beginDrag')
        self.endDrag = Signal('DataCatalogTree.endDrag')
        self.startEdit = Signal('DataCatalogTree.startEdit')
        self.endEdit = Signal('DataCatalogTree.endEdit')

        self.Bind(
            wx.EVT_TREE_BEGIN_DRAG, lambda evt: self._emitSignal(
                evt.GetItem(), self.beginDrag, event=evt))
        self.Bind(
            wx.EVT_TREE_END_DRAG, lambda evt: self._emitSignal(
                evt.GetItem(), self.endDrag, event=evt))
        self.beginDrag.connect(self.OnBeginDrag)
        self.endDrag.connect(self.OnEndDrag)

        self.Bind(
            wx.EVT_TREE_BEGIN_LABEL_EDIT, lambda evt: self._emitSignal(
                evt.GetItem(), self.startEdit, event=evt))
        self.Bind(
            wx.EVT_TREE_END_LABEL_EDIT, lambda evt: self._emitSignal(
                evt.GetItem(), self.endEdit, event=evt))
        self.startEdit.connect(self.OnStartEditLabel)
        self.endEdit.connect(self.OnEditLabel)

    def _initVariablesCatalog(self):
        """Init variables."""
        self.copy_mode = False
        self.copy_layer = None
        self.copy_type = None
        self.copy_mapset = None
        self.copy_location = None

    def SetRestriction(self, restrict):
        self._restricted = restrict

    def _runCommand(self, prog, **kwargs):
        cmdString = ' '.join(gscript.make_command(prog, **kwargs))
        ret = RunCommand(prog, parent=self, **kwargs)

        return ret, cmdString

    def InitTreeItems(self):
        """Add locations, mapsets and layers to the tree."""
        self._initTreeItems()

    def OnMoveMap(self, event):
        """Move layer or mapset (just save it temporarily, copying is done by paste)"""
        self.copy_mode = False
        self.copy_layer = self.selected_layer[:]
        self.copy_type = self.selected_type[:]
        self.copy_mapset = self.selected_mapset[:]
        self.copy_location = self.selected_location[:]
        if len(self.copy_layer) > 1:
            label = _("{c} maps marked for moving.").format(
                c=len(self.selected_layer))
        else:
            label = _("Map <{layer}> marked for moving.").format(
                layer=self.copy_layer[0].label)
        self.showNotification.emit(message=label)

    def OnCopyMap(self, event):
        """Copy layer or mapset (just save it temporarily, copying is done by paste)"""
        self.copy_mode = True
        self.copy_layer = self.selected_layer[:]
        self.copy_type = self.selected_type[:]
        self.copy_mapset = self.selected_mapset[:]
        self.copy_location = self.selected_location[:]
        if len(self.copy_layer) > 1:
            label = _("{c} maps marked for copying.").format(
                c=len(self.selected_layer))
        else:
            label = _("Map <{layer}> marked for copying.").format(
                layer=self.copy_layer[0].label)
        self.showNotification.emit(message=label)

    def OnRenameMap(self, event):
        """Rename layer with dialog"""
        old_name = self.selected_layer[0].label
        gisrc, env = gscript.create_environment(
            gisenv()['GISDBASE'],
            self.selected_location[0].label,
            mapset=self.selected_mapset[0].label)
        new_name = self._getNewMapName(_('New name'),
                                       _('Rename map'),
                                       old_name,
                                       env=env,
                                       mapset=self.selected_mapset[0].label,
                                       element=self.selected_type[0].label)
        if new_name:
            self.Rename(old_name, new_name)

    def OnStartEditLabel(self, node, event):
        """Start label editing"""
        self.DefineItems([node])
        Debug.msg(1, "Start label edit {name}".format(name=node.label))
        label = _("Editing {name}").format(name=node.label)
        self.showNotification.emit(message=label)
        if not self.selected_layer:
            event.Veto()

    def OnEditLabel(self, node, event):
        """End label editing"""
        if self.selected_layer and not event.IsEditCancelled():
            old_name = node.label
            Debug.msg(1, "End label edit {name}".format(name=old_name))
            new_name = event.GetLabel()
            self.Rename(old_name, new_name)

    def Rename(self, old, new):
        """Rename layer"""
        string = old + ',' + new
        gisrc, env = gscript.create_environment(
            gisenv()['GISDBASE'], self.selected_location[0].label,
            self.selected_mapset[0].label)
        label = _("Renaming map <{name}>...").format(name=string)
        self.showNotification.emit(message=label)
        if self.selected_type[0].label == 'vector':
            renamed, cmd = self._runCommand('g.rename', vector=string, env=env)
        elif self.selected_type[0].label == 'raster':
            renamed, cmd = self._runCommand('g.rename', raster=string, env=env)
        else:
            renamed, cmd = self._runCommand('g.rename',
                                            raster3d=string,
                                            env=env)
        if renamed == 0:
            self.selected_layer[0].label = new
            self.selected_layer[0].data['name'] = new
            self.RefreshNode(self.selected_layer[0])
            self.showNotification.emit(message=_("{cmd} -- completed").format(
                cmd=cmd))
            Debug.msg(1, "LAYER RENAMED TO: " + new)
        gscript.try_remove(gisrc)

    def OnPasteMap(self, event):
        # copying between mapsets of one location
        if not self.copy_layer:
            if self.copy_mode:
                GMessage(_("No map selected for copying."), parent=self)
            else:
                GMessage(_("No map selected for moving."), parent=self)
            return

        for i in range(len(self.copy_layer)):
            gisrc, env = gscript.create_environment(
                gisenv()['GISDBASE'],
                self.selected_location[0].label,
                mapset=self.selected_mapset[0].label)
            gisrc2, env2 = gscript.create_environment(
                gisenv()['GISDBASE'],
                self.copy_location[i].label,
                mapset=self.copy_mapset[i].label)
            new_name = self.copy_layer[i].label
            if self.selected_location[0] == self.copy_location[i]:
                # within one mapset
                if self.selected_mapset[0] == self.copy_mapset[i]:
                    # ignore when just moves map
                    if self.copy_mode is False:
                        return
                    new_name = self._getNewMapName(
                        _('New name for <{n}>').format(
                            n=self.copy_layer[i].label),
                        _('Select new name'),
                        self.copy_layer[i].label,
                        env=env,
                        mapset=self.selected_mapset[0].label,
                        element=self.copy_type[i].label)
                    if not new_name:
                        return
                # within one location, different mapsets
                else:
                    if map_exists(new_name,
                                  element=self.copy_type[i].label,
                                  env=env,
                                  mapset=self.selected_mapset[0].label):
                        new_name = self._getNewMapName(
                            _('New name for <{n}>').format(
                                n=self.copy_layer[i].label),
                            _('Select new name'),
                            self.copy_layer[i].label,
                            env=env,
                            mapset=self.selected_mapset[0].label,
                            element=self.copy_type[i].label)
                        if not new_name:
                            return

                string = self.copy_layer[i].label + '@' + self.copy_mapset[
                    i].label + ',' + new_name
                pasted = 0
                if self.copy_mode:
                    label = _("Copying <{name}>...").format(name=string)
                else:
                    label = _("Moving <{name}>...").format(name=string)
                self.showNotification.emit(message=label)
                if self.copy_type[i].label == 'vector':
                    pasted, cmd = self._runCommand('g.copy',
                                                   vector=string,
                                                   env=env)
                    node = 'vector'
                elif self.copy_type[i].label == 'raster':
                    pasted, cmd = self._runCommand('g.copy',
                                                   raster=string,
                                                   env=env)
                    node = 'raster'
                else:
                    pasted, cmd = self._runCommand('g.copy',
                                                   raster_3d=string,
                                                   env=env)
                    node = 'raster_3d'
                if pasted == 0:
                    self.InsertLayer(name=new_name,
                                     mapset_node=self.selected_mapset[0],
                                     element_name=node)
                    Debug.msg(1, "COPIED TO: " + new_name)
                    if self.copy_mode:
                        self.showNotification.emit(
                            message=_("g.copy completed"))
                    else:
                        self.showNotification.emit(
                            message=_("g.copy completed"))

                    # remove old
                    if not self.copy_mode:
                        self._removeMapAfterCopy(self.copy_layer[i],
                                                 self.copy_type[i], env2)

                gscript.try_remove(gisrc)
                gscript.try_remove(gisrc2)
                # expand selected mapset
            else:
                if self.copy_type[i].label == 'raster_3d':
                    GError(_("Reprojection is not implemented for 3D rasters"),
                           parent=self)
                    return
                if map_exists(new_name,
                              element=self.copy_type[i].label,
                              env=env,
                              mapset=self.selected_mapset[0].label):
                    new_name = self._getNewMapName(
                        _('New name'),
                        _('Select new name'),
                        self.copy_layer[i].label,
                        env=env,
                        mapset=self.selected_mapset[0].label,
                        element=self.copy_type[i].label)
                    if not new_name:
                        continue
                gisdbase = gisenv()['GISDBASE']
                callback = lambda gisrc2=gisrc2, gisrc=gisrc, cLayer=self.copy_layer[i], \
                                  cType=self.copy_type[i], cMode=self.copy_mode, name=new_name: \
                                  self._onDoneReprojection(env2, gisrc2, gisrc, cLayer, cType, cMode, name)
                dlg = CatalogReprojectionDialog(
                    self, self._giface, gisdbase, self.copy_location[i].label,
                    self.copy_mapset[i].label, self.copy_layer[i].label, env2,
                    gisdbase, self.selected_location[0].label,
                    self.selected_mapset[0].label, new_name,
                    self.copy_type[i].label, env, callback)
                dlg.ShowModal()
        self.ExpandNode(self.selected_mapset[0], recursive=True)
        self._initVariablesCatalog()

    def _onDoneReprojection(self, iEnv, iGisrc, oGisrc, cLayer, cType, cMode,
                            name):
        self.InsertLayer(name=name,
                         mapset_node=self.selected_mapset[0],
                         element_name=cType.label)
        if not cMode:
            self._removeMapAfterCopy(cLayer, cType, iEnv)
        gscript.try_remove(iGisrc)
        gscript.try_remove(oGisrc)
        self.ExpandNode(self.selected_mapset[0], recursive=True)

    def _removeMapAfterCopy(self, cLayer, cType, env):
        removed, cmd = self._runCommand('g.remove',
                                        type=cType.label,
                                        name=cLayer.label,
                                        flags='f',
                                        env=env)
        if removed == 0:
            self._model.RemoveNode(cLayer)
            self.RefreshNode(cType, recursive=True)
            Debug.msg(1, "LAYER " + cLayer.label + " DELETED")
            self.showNotification.emit(message=_("g.remove completed"))

    def InsertLayer(self, name, mapset_node, element_name):
        """Insert layer into model and refresh tree"""
        found_element = self._model.SearchNodes(parent=mapset_node,
                                                type='element',
                                                name=element_name)
        found_element = found_element[0] if found_element else None
        if not found_element:
            # add type node if not exists
            found_element = self._model.AppendNode(parent=mapset_node,
                                                   label=element_name,
                                                   data=dict(
                                                       type='element',
                                                       name=element_name))
        found = self._model.SearchNodes(parent=found_element, name=name)
        if len(found) == 0:
            self._model.AppendNode(parent=found_element,
                                   label=name,
                                   data=dict(type=element_name, name=name))
            self._model.SortChildren(found_element)
            self.RefreshNode(mapset_node, recursive=True)

    def OnDeleteMap(self, event):
        """Delete layer or mapset"""
        names = [
            self.selected_layer[i].label + '@' + self.selected_mapset[i].label
            for i in range(len(self.selected_layer))
        ]
        if len(names) < 10:
            question = _("Do you really want to delete map(s) <{m}>?").format(
                m=', '.join(names))
        else:
            question = _("Do you really want to delete {n} maps?").format(
                n=len(names))
        if self._confirmDialog(question, title=_('Delete map')) == wx.ID_YES:
            label = _("Deleting {name}...").format(name=names)
            self.showNotification.emit(message=label)
            for i in range(len(self.selected_layer)):
                gisrc, env = gscript.create_environment(
                    gisenv()['GISDBASE'], self.selected_location[i].label,
                    self.selected_mapset[i].label)
                removed, cmd = self._runCommand(
                    'g.remove',
                    flags='f',
                    type=self.selected_type[i].label,
                    name=self.selected_layer[i].label,
                    env=env)
                if removed == 0:
                    self._model.RemoveNode(self.selected_layer[i])
                    self.RefreshNode(self.selected_type[i], recursive=True)
                    Debug.msg(
                        1,
                        "LAYER " + self.selected_layer[i].label + " DELETED")

                    # remove map layer from layer tree if exists
                    if not isinstance(self._giface, StandaloneGrassInterface):
                        name = self.selected_layer[
                            i].label + '@' + self.selected_mapset[i].label
                        layers = self._giface.GetLayerList().GetLayersByName(
                            name)
                        for layer in layers:
                            self._giface.GetLayerList().DeleteLayer(layer)

                gscript.try_remove(gisrc)
            self.UnselectAll()
            self.showNotification.emit(message=_("g.remove completed"))

    def OnDisplayLayer(self, event):
        """Display layer in current graphics view"""
        self.DisplayLayer()

    def DisplayLayer(self):
        """Display selected layer in current graphics view"""
        all_names = []
        names = {'raster': [], 'vector': [], 'raster3d': []}
        for i in range(len(self.selected_layer)):
            name = self.selected_layer[i].label + '@' + self.selected_mapset[
                i].label
            names[self.selected_type[i].label].append(name)
            all_names.append(name)
        #if self.selected_location[0].label == gisenv()['LOCATION_NAME'] and self.selected_mapset[0]:
        for ltype in names:
            if names[ltype]:
                self._giface.lmgr.AddMaps(list(reversed(names[ltype])), ltype,
                                          True)

        if len(self._giface.GetLayerList()) == 1:
            # zoom to map if there is only one map layer
            self._giface.GetMapWindow().ZoomToMap()

        Debug.msg(1, "Displayed layer(s): " + str(all_names))

    def OnBeginDrag(self, node, event):
        """Just copy necessary data"""
        self.DefineItems(self.GetSelected())
        if self.selected_layer and not (self._restricted
                                        and gisenv()['LOCATION_NAME'] !=
                                        self.selected_location[0].label):
            event.Allow()
            self.OnCopyMap(event)
            Debug.msg(1, "DRAG")
        else:
            event.Veto()

    def OnEndDrag(self, node, event):
        """Copy layer into target"""
        self.copy_mode = wx.GetMouseState().ControlDown()
        if node:
            self.DefineItems([node])
            if self._restricted and gisenv(
            )['MAPSET'] != self.selected_mapset[0].label:
                GMessage(_(
                    "To move or copy maps to other mapsets, unlock editing of other mapsets"
                ),
                         parent=self)
                event.Veto()
                return

            event.Allow()
            Debug.msg(1, "DROP DONE")
            self.OnPasteMap(event)

    def OnSwitchLocationMapset(self, event):
        genv = gisenv()
        if self.selected_location[0].label == genv['LOCATION_NAME']:
            self.changeMapset.emit(mapset=self.selected_mapset[0].label)
        else:
            self.changeLocation.emit(mapset=self.selected_mapset[0].label,
                                     location=self.selected_location[0].label)
        self.ExpandCurrentMapset()

    def OnMetadata(self, event):
        """Show metadata of any raster/vector/3draster"""
        def done(event):
            gscript.try_remove(event.userData)

        for i in range(len(self.selected_layer)):
            if self.selected_type[i].label == 'raster':
                cmd = ['r.info']
            elif self.selected_type[i].label == 'vector':
                cmd = ['v.info']
            elif self.selected_type[i].label == 'raster_3d':
                cmd = ['r3.info']
            cmd.append(
                'map=%s@%s' %
                (self.selected_layer[i].label, self.selected_mapset[i].label))

            gisrc, env = gscript.create_environment(
                gisenv()['GISDBASE'], self.selected_location[i].label,
                self.selected_mapset[i].label)
            # print output to command log area
            # temp gisrc file must be deleted onDone
            self._giface.RunCmd(cmd, env=env, onDone=done, userData=gisrc)

    def OnCopyName(self, event):
        """Copy layer name to clipboard"""
        if wx.TheClipboard.Open():
            do = wx.TextDataObject()
            text = []
            for i in range(len(self.selected_layer)):
                text.append('%s@%s' % (self.selected_layer[i].label,
                                       self.selected_mapset[i].label))
            do.SetText(','.join(text))
            wx.TheClipboard.SetData(do)
            wx.TheClipboard.Close()

    def Filter(self, text):
        """Filter tree based on name and type."""
        text = text.strip()
        if len(text.split(':')) > 1:
            name = text.split(':')[1].strip()
            elem = text.split(':')[0].strip()
            if 'r' == elem:
                element = 'raster'
            elif 'r3' == elem:
                element = 'raster_3d'
            elif 'v' == elem:
                element = 'vector'
            else:
                element = None
        else:
            element = None
            name = text.strip()

        self._model = filterModel(self._orig_model, name=name, element=element)
        self.RefreshItems()
        self.ExpandCurrentMapset()

    def _getNewMapName(self, message, title, value, element, mapset, env):
        """Dialog for simple text entry"""
        dlg = NameEntryDialog(parent=self,
                              message=message,
                              caption=title,
                              element=element,
                              env=env,
                              mapset=mapset)
        dlg.SetValue(value)
        if dlg.ShowModal() == wx.ID_OK:
            name = dlg.GetValue()
        else:
            name = None
        dlg.Destroy()

        return name

    def _confirmDialog(self, question, title):
        """Confirm dialog"""
        dlg = wx.MessageDialog(self, question, title, wx.YES_NO)
        res = dlg.ShowModal()
        dlg.Destroy()
        return res

    def _isCurrent(self, genv):
        if self._restricted:
            currentMapset = currentLocation = True
            for i in range(len(self.selected_location)):
                if self.selected_location[i].label != genv['LOCATION_NAME']:
                    currentLocation = False
                    currentMapset = False
                    break
            if currentMapset:
                for i in range(len(self.selected_mapset)):
                    if self.selected_mapset[i].label != genv['MAPSET']:
                        currentMapset = False
                        break

            return currentLocation, currentMapset
        else:
            return True, True

    def _popupMenuLayer(self):
        """Create popup menu for layers"""
        menu = Menu()
        genv = gisenv()
        currentLocation, currentMapset = self._isCurrent(genv)

        item = wx.MenuItem(menu, wx.NewId(), _("&Cut"))
        menu.AppendItem(item)
        self.Bind(wx.EVT_MENU, self.OnMoveMap, item)
        if not currentMapset:
            item.Enable(False)

        item = wx.MenuItem(menu, wx.NewId(), _("&Copy"))
        menu.AppendItem(item)
        self.Bind(wx.EVT_MENU, self.OnCopyMap, item)

        item = wx.MenuItem(menu, wx.NewId(), _("Copy &name"))
        menu.AppendItem(item)
        self.Bind(wx.EVT_MENU, self.OnCopyName, item)

        item = wx.MenuItem(menu, wx.NewId(), _("&Paste"))
        menu.AppendItem(item)
        self.Bind(wx.EVT_MENU, self.OnPasteMap, item)
        if not (currentMapset and self.copy_layer):
            item.Enable(False)

        item = wx.MenuItem(menu, wx.NewId(), _("&Delete"))
        menu.AppendItem(item)
        self.Bind(wx.EVT_MENU, self.OnDeleteMap, item)
        item.Enable(currentMapset)

        item = wx.MenuItem(menu, wx.NewId(), _("&Rename"))
        menu.AppendItem(item)
        self.Bind(wx.EVT_MENU, self.OnRenameMap, item)
        item.Enable(currentMapset and len(self.selected_layer) == 1)

        menu.AppendSeparator()

        if not isinstance(self._giface, StandaloneGrassInterface):
            if all([
                    each.label == genv['LOCATION_NAME']
                    for each in self.selected_location
            ]):
                if len(self.selected_layer) > 1:
                    item = wx.MenuItem(menu, wx.NewId(), _("&Display layers"))
                else:
                    item = wx.MenuItem(menu, wx.NewId(), _("&Display layer"))
                menu.AppendItem(item)
                self.Bind(wx.EVT_MENU, self.OnDisplayLayer, item)

        item = wx.MenuItem(menu, wx.NewId(), _("Show &metadata"))
        menu.AppendItem(item)
        self.Bind(wx.EVT_MENU, self.OnMetadata, item)

        self.PopupMenu(menu)
        menu.Destroy()

    def _popupMenuMapset(self):
        """Create popup menu for mapsets"""
        menu = Menu()
        genv = gisenv()
        currentLocation, currentMapset = self._isCurrent(genv)

        item = wx.MenuItem(menu, wx.NewId(), _("&Paste"))
        menu.AppendItem(item)
        self.Bind(wx.EVT_MENU, self.OnPasteMap, item)
        if not (currentMapset and self.copy_layer):
            item.Enable(False)

        item = wx.MenuItem(menu, wx.NewId(), _("&Switch mapset"))
        menu.AppendItem(item)
        self.Bind(wx.EVT_MENU, self.OnSwitchLocationMapset, item)
        if (self.selected_location[0].label == genv['LOCATION_NAME']
                and self.selected_mapset[0].label == genv['MAPSET']):
            item.Enable(False)
        self.PopupMenu(menu)
        menu.Destroy()

    def _popupMenuElement(self):
        """Create popup menu for elements"""
        menu = Menu()
        item = wx.MenuItem(menu, wx.NewId(), _("&Paste"))
        menu.AppendItem(item)
        self.Bind(wx.EVT_MENU, self.OnPasteMap, item)
        genv = gisenv()
        currentLocation, currentMapset = self._isCurrent(genv)
        if not (currentMapset and self.copy_layer):
            item.Enable(False)

        self.PopupMenu(menu)
        menu.Destroy()

    def _popupMenuEmpty(self):
        """Create empty popup when multiple different types of items are selected"""
        menu = Menu()
        item = wx.MenuItem(menu, wx.NewId(), _("No available options"))
        menu.AppendItem(item)
        item.Enable(False)
        self.PopupMenu(menu)
        menu.Destroy()
Exemple #21
0
    def __init__(self,
                 parent,
                 handlerObj,
                 giface,
                 model,
                 id=wx.ID_ANY,
                 **kwargs):
        self.parent = parent
        self._handlerObj = handlerObj
        self._giface = giface

        self.showNotification = Signal('SearchModuleWindow.showNotification')
        wx.Panel.__init__(self, parent=parent, id=id, **kwargs)

        # tree
        self._tree = CTreeView(model=model, parent=self)
        self._tree.SetToolTip(
            _("Double-click or Ctrl-Enter to run selected module"))

        #        self._dataBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
        #                                     label = " %s " % _("Module tree"))

        # search widget
        self._search = SearchModuleWidget(parent=self,
                                          model=model,
                                          showChoice=False)
        self._search.showSearchResult.connect(
            lambda result: self._tree.Select(result))
        self._search.showNotification.connect(self.showNotification)

        self._helpText = StaticText(
            parent=self,
            id=wx.ID_ANY,
            label="Press Enter for next match, Ctrl+Enter to run command")
        self._helpText.SetForegroundColour(
            wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))

        # buttons
        self._btnRun = Button(self, id=wx.ID_OK, label=_("&Run"))
        self._btnRun.SetToolTip(_("Run selected module from the tree"))
        self._btnHelp = Button(self, id=wx.ID_ANY, label=_("H&elp"))
        self._btnHelp.SetToolTip(
            _("Show manual for selected module from the tree"))
        self._btnAdvancedSearch = Button(self,
                                         id=wx.ID_ANY,
                                         label=_("Adva&nced search..."))
        self._btnAdvancedSearch.SetToolTip(
            _("Do advanced search using %s module") % 'g.search.module')

        # bindings
        self._btnRun.Bind(wx.EVT_BUTTON, lambda evt: self.Run())
        self._btnHelp.Bind(wx.EVT_BUTTON, lambda evt: self.Help())
        self._btnAdvancedSearch.Bind(wx.EVT_BUTTON,
                                     lambda evt: self.AdvancedSearch())
        self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)

        self._tree.selectionChanged.connect(self.OnItemSelected)
        self._tree.itemActivated.connect(lambda node: self.Run(node))

        self._layout()

        self._search.SetFocus()
    def __init__(self, parent, giface, settings, scaniface):
        wx.Panel.__init__(self, parent)
        self.group = None
        self.segment = 'segment'
        self.segment_clump = 'segment_clump'
        self.signature = 'signature'
        self.classification = 'classification'
        self.filtered_classification = 'fclassification'
        self.reject = 'reject'
        self.output = 'objects'

        self.env = None
        self.giface = giface
        self.parent = parent
        self.settings = settings
        self.scaniface = scaniface
        self.settingsChanged = Signal('ColorInteractionPanel.settingsChanged')

        if 'color' not in self.settings:
            self.settings['color'] = {}
            self.settings['color']['active'] = False
            self.settings['color']['name'] = ''
            self.settings['color']['training'] = ''

        self.hide = []
        self.ifColor = wx.CheckBox(self, label=_("Save color rasters:"))
        self.ifColor.SetValue(self.settings['color']['active'])
        self.ifColor.Bind(wx.EVT_CHECKBOX, self.OnChange)
        self.exportColor = Select(self, size=(-1, -1), type='raster')
        self.exportColor.SetValue(self.settings['color']['name'])
        self.exportColor.Bind(wx.EVT_TEXT, self.OnChange)
        self.hide.append(self.exportColor)
        if self.settings['color']['name']:
            self.group = self.settings['color']['name']

        self.trainingAreas = Select(self, size=(-1, -1), type='raster')
        self.trainingAreas.SetValue(self.settings['color']['training'])
        self.trainingAreas.Bind(wx.EVT_TEXT, self.OnChange)
        labelTraining = wx.StaticText(self, label=_("Training areas:"))
        self.hide.append(self.trainingAreas)
        self.hide.append(labelTraining)
        calibrateBtn = wx.Button(self, label=_("Calibrate"))
        calibrateBtn.Bind(wx.EVT_BUTTON, self.OnCalibration)
        self.hide.append(calibrateBtn)

        analyzeBtn = wx.Button(self, label=_("Scan and process"))
        analyzeBtn.Bind(wx.EVT_BUTTON, self.OnAnalysis)
        self.hide.append(analyzeBtn)

        self.mainSizer = wx.BoxSizer(wx.VERTICAL)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(self.ifColor, flag=wx.ALIGN_CENTER_VERTICAL, border=5)
        sizer.Add(self.exportColor,
                  proportion=1,
                  flag=wx.ALIGN_CENTER_VERTICAL,
                  border=5)
        self.mainSizer.Add(sizer, flag=wx.EXPAND | wx.ALL, border=5)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(labelTraining, flag=wx.ALIGN_CENTER_VERTICAL, border=5)
        sizer.Add(self.trainingAreas,
                  proportion=1,
                  flag=wx.ALIGN_CENTER_VERTICAL,
                  border=5)
        sizer.Add(calibrateBtn, flag=wx.ALIGN_CENTER_VERTICAL, border=5)
        self.mainSizer.Add(sizer, flag=wx.EXPAND | wx.ALL, border=5)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.AddStretchSpacer()
        sizer.Add(analyzeBtn, flag=wx.ALIGN_CENTER_VERTICAL, border=5)
        self.mainSizer.Add(sizer, flag=wx.EXPAND | wx.ALL, border=5)
        self.SetSizer(self.mainSizer)
        self.mainSizer.Fit(self)

        self._enable()
Exemple #23
0
    def __init__(self, guiparent=None, giface=None, ignoredCmdPattern=None):
        """
        :param guiparent: parent window for created GUI objects
        :param lmgr: layer manager window (TODO: replace by giface)
        :param ignoredCmdPattern: regular expression specifying commads
                                  to be ignored (e.g. @c '^d\..*' for
                                  display commands)
        """
        wx.EvtHandler.__init__(self)

        # Signal when some map is created or updated by a module.
        # attributes: name: map name, ltype: map type,
        self.mapCreated = Signal("GConsole.mapCreated")
        # emitted when map display should be re-render
        self.updateMap = Signal("GConsole.updateMap")
        # emitted when log message should be written
        self.writeLog = Signal("GConsole.writeLog")
        # emitted when command log message should be written
        self.writeCmdLog = Signal("GConsole.writeCmdLog")
        # emitted when warning message should be written
        self.writeWarning = Signal("GConsole.writeWarning")
        # emitted when error message should be written
        self.writeError = Signal("GConsole.writeError")

        self._guiparent = guiparent
        self._giface = giface
        self._ignoredCmdPattern = ignoredCmdPattern

        # create queues
        self.requestQ = Queue.Queue()
        self.resultQ = Queue.Queue()

        self.cmdOutputTimer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnProcessPendingOutputWindowEvents)
        self.Bind(EVT_CMD_RUN, self.OnCmdRun)
        self.Bind(EVT_CMD_DONE, self.OnCmdDone)
        self.Bind(EVT_CMD_ABORT, self.OnCmdAbort)

        # stream redirection
        self.cmdStdOut = GStdout(receiver=self)
        self.cmdStdErr = GStderr(receiver=self)

        # thread
        self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)
Exemple #24
0
class GConsole(wx.EvtHandler):
    """Backend for command execution, esp. interactive command execution"""

    def __init__(self, guiparent=None, giface=None, ignoredCmdPattern=None):
        """
        :param guiparent: parent window for created GUI objects
        :param lmgr: layer manager window (TODO: replace by giface)
        :param ignoredCmdPattern: regular expression specifying commads
                                  to be ignored (e.g. @c '^d\..*' for
                                  display commands)
        """
        wx.EvtHandler.__init__(self)

        # Signal when some map is created or updated by a module.
        # attributes: name: map name, ltype: map type,
        self.mapCreated = Signal("GConsole.mapCreated")
        # emitted when map display should be re-render
        self.updateMap = Signal("GConsole.updateMap")
        # emitted when log message should be written
        self.writeLog = Signal("GConsole.writeLog")
        # emitted when command log message should be written
        self.writeCmdLog = Signal("GConsole.writeCmdLog")
        # emitted when warning message should be written
        self.writeWarning = Signal("GConsole.writeWarning")
        # emitted when error message should be written
        self.writeError = Signal("GConsole.writeError")

        self._guiparent = guiparent
        self._giface = giface
        self._ignoredCmdPattern = ignoredCmdPattern

        # create queues
        self.requestQ = Queue.Queue()
        self.resultQ = Queue.Queue()

        self.cmdOutputTimer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnProcessPendingOutputWindowEvents)
        self.Bind(EVT_CMD_RUN, self.OnCmdRun)
        self.Bind(EVT_CMD_DONE, self.OnCmdDone)
        self.Bind(EVT_CMD_ABORT, self.OnCmdAbort)

        # stream redirection
        self.cmdStdOut = GStdout(receiver=self)
        self.cmdStdErr = GStderr(receiver=self)

        # thread
        self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)

    def Redirect(self):
        """Redirect stdout/stderr"""
        if Debug.GetLevel() == 0 and grass.debug_level(force=True) == 0:
            # don't redirect when debugging is enabled
            sys.stdout = self.cmdStdOut
            sys.stderr = self.cmdStdErr
        else:
            enc = locale.getdefaultlocale()[1]
            if enc:
                if sys.version_info.major == 2:
                    sys.stdout = codecs.getwriter(enc)(sys.__stdout__)
                    sys.stderr = codecs.getwriter(enc)(sys.__stderr__)
                else:
                    # https://stackoverflow.com/questions/4374455/how-to-set-sys-stdout-encoding-in-python-3
                    sys.stdout = codecs.getwriter(enc)(sys.__stdout__.detach())
                    sys.stderr = codecs.getwriter(enc)(sys.__stderr__.detach())
            else:
                sys.stdout = sys.__stdout__
                sys.stderr = sys.__stderr__

    def WriteLog(
        self, text, style=None, wrap=None, notification=Notification.HIGHLIGHT
    ):
        """Generic method for writing log message in
        given style

        :param text: text line
        :param notification: form of notification
        """
        self.writeLog.emit(text=text, wrap=wrap, notification=notification)

    def WriteCmdLog(self, text, pid=None, notification=Notification.MAKE_VISIBLE):
        """Write message in selected style

        :param text: message to be printed
        :param pid: process pid or None
        :param notification: form of notification
        """
        self.writeCmdLog.emit(text=text, pid=pid, notification=notification)

    def WriteWarning(self, text):
        """Write message in warning style"""
        self.writeWarning.emit(text=text)

    def WriteError(self, text):
        """Write message in error style"""
        self.writeError.emit(text=text)

    def RunCmd(
        self,
        command,
        compReg=True,
        env=None,
        skipInterface=False,
        onDone=None,
        onPrepare=None,
        userData=None,
        addLayer=None,
        notification=Notification.MAKE_VISIBLE,
    ):
        """Run command typed into console command prompt (GPrompt).

        .. todo::
            Document the other event.
        .. todo::
            Solve problem with the other event (now uses gOutputText
            event but there is no text, use onPrepare handler instead?)
        .. todo::
            Skip interface is ignored and determined always automatically.

        Posts event EVT_IGNORED_CMD_RUN when command which should be ignored
        (according to ignoredCmdPattern) is run.
        For example, see layer manager which handles d.* on its own.

        :param command: command given as a list (produced e.g. by utils.split())
        :param compReg: True use computation region
        :param notification: form of notification
        :param bool skipInterface: True to do not launch GRASS interface
                                   parser when command has no arguments
                                   given
        :param onDone: function to be called when command is finished
        :param onPrepare: function to be called before command is launched
        :param addLayer: to be passed in the mapCreated signal
        :param userData: data defined for the command
        """
        if len(command) == 0:
            Debug.msg(2, "GPrompt:RunCmd(): empty command")
            return

        # update history file
        self.UpdateHistoryFile(" ".join(command))

        if command[0] in globalvar.grassCmd:
            # send GRASS command without arguments to GUI command interface
            # except ignored commands (event is emitted)
            if (
                self._ignoredCmdPattern
                and re.compile(self._ignoredCmdPattern).search(" ".join(command))
                and "--help" not in command
                and "--ui" not in command
            ):
                event = gIgnoredCmdRun(cmd=command)
                wx.PostEvent(self, event)
                return

            else:
                # other GRASS commands (r|v|g|...)
                try:
                    task = GUI(show=None).ParseCommand(command)
                except GException as e:
                    GError(parent=self._guiparent, message=str(e), showTraceback=False)
                    return

                hasParams = False
                if task:
                    options = task.get_options()
                    hasParams = options["params"] and options["flags"]
                    # check for <input>=-
                    for p in options["params"]:
                        if (
                            p.get("prompt", "") == "input"
                            and p.get("element", "") == "file"
                            and p.get("age", "new") == "old"
                            and p.get("value", "") == "-"
                        ):
                            GError(
                                parent=self._guiparent,
                                message=_(
                                    "Unable to run command:\n%(cmd)s\n\n"
                                    "Option <%(opt)s>: read from standard input is not "
                                    "supported by wxGUI"
                                )
                                % {"cmd": " ".join(command), "opt": p.get("name", "")},
                            )
                            return

                if len(command) == 1:
                    if command[0].startswith("g.gui."):
                        import imp
                        import inspect

                        pyFile = command[0]
                        if sys.platform == "win32":
                            pyFile += ".py"
                        pyPath = os.path.join(os.environ["GISBASE"], "scripts", pyFile)
                        if not os.path.exists(pyPath):
                            pyPath = os.path.join(
                                os.environ["GRASS_ADDON_BASE"], "scripts", pyFile
                            )
                        if not os.path.exists(pyPath):
                            GError(
                                parent=self._guiparent,
                                message=_("Module <%s> not found.") % command[0],
                            )
                        pymodule = imp.load_source(command[0].replace(".", "_"), pyPath)
                        try:  # PY3
                            pymain = inspect.getfullargspec(pymodule.main)
                        except AttributeError:
                            pymain = inspect.getargspec(pymodule.main)
                        if pymain and "giface" in pymain.args:
                            pymodule.main(self._giface)
                            return

                    # no arguments given
                    if hasParams and not isinstance(self._guiparent, FormNotebook):
                        # also parent must be checked, see #3135 for details
                        try:
                            GUI(
                                parent=self._guiparent, giface=self._giface
                            ).ParseCommand(command)
                        except GException as e:
                            print(e, file=sys.stderr)

                        return

                if env:
                    env = env.copy()
                else:
                    env = os.environ.copy()
                # activate computational region (set with g.region)
                # for all non-display commands.
                if compReg and "GRASS_REGION" in env:
                    del env["GRASS_REGION"]

                # process GRASS command with argument
                self.cmdThread.RunCmd(
                    command,
                    stdout=self.cmdStdOut,
                    stderr=self.cmdStdErr,
                    onDone=onDone,
                    onPrepare=onPrepare,
                    userData=userData,
                    addLayer=addLayer,
                    env=env,
                    notification=notification,
                )
                self.cmdOutputTimer.Start(50)

                # we don't need to change computational region settings
                # because we work on a copy
        else:
            # Send any other command to the shell. Send output to
            # console output window
            #
            # Check if the script has an interface (avoid double-launching
            # of the script)

            # check if we ignore the command (similar to grass commands part)
            if self._ignoredCmdPattern and re.compile(self._ignoredCmdPattern).search(
                " ".join(command)
            ):
                event = gIgnoredCmdRun(cmd=command)
                wx.PostEvent(self, event)
                return

            skipInterface = True
            if os.path.splitext(command[0])[1] in (".py", ".sh"):
                try:
                    sfile = open(command[0], "r")
                    for line in sfile.readlines():
                        if len(line) < 2:
                            continue
                        if line[0] == "#" and line[1] == "%":
                            skipInterface = False
                            break
                    sfile.close()
                except IOError:
                    pass

            if len(command) == 1 and not skipInterface:
                try:
                    task = gtask.parse_interface(command[0])
                except:
                    task = None
            else:
                task = None

            if task:
                # process GRASS command without argument
                GUI(parent=self._guiparent, giface=self._giface).ParseCommand(command)
            else:
                self.cmdThread.RunCmd(
                    command,
                    stdout=self.cmdStdOut,
                    stderr=self.cmdStdErr,
                    onDone=onDone,
                    onPrepare=onPrepare,
                    userData=userData,
                    addLayer=addLayer,
                    env=env,
                    notification=notification,
                )
            self.cmdOutputTimer.Start(50)

    def GetLog(self, err=False):
        """Get widget used for logging

        .. todo::
           what's this?

        :param bool err: True to get stderr widget
        """
        if err:
            return self.cmdStdErr

        return self.cmdStdOut

    def GetCmd(self):
        """Get running command or None"""
        return self.requestQ.get()

    def OnCmdAbort(self, event):
        """Abort running command"""
        self.cmdThread.abort()
        event.Skip()

    def OnCmdRun(self, event):
        """Run command"""
        self.WriteCmdLog(
            "(%s)\n%s" % (str(time.ctime()), " ".join(event.cmd)),
            notification=event.notification,
        )
        event.Skip()

    def OnCmdDone(self, event):
        """Command done (or aborted)

        Sends signal mapCreated if map is recognized in output
        parameters or for specific modules (as r.colors).
        """
        # Process results here
        try:
            ctime = time.time() - event.time
            if ctime < 60:
                stime = _("%d sec") % int(ctime)
            else:
                mtime = int(ctime / 60)
                stime = _("%(min)d min %(sec)d sec") % {
                    "min": mtime,
                    "sec": int(ctime - (mtime * 60)),
                }
        except KeyError:
            # stopped deamon
            stime = _("unknown")

        if event.aborted:
            # Thread aborted (using our convention of None return)
            self.WriteWarning(
                _(
                    "Please note that the data are left in"
                    " inconsistent state and may be corrupted"
                )
            )
            msg = _("Command aborted")
        else:
            msg = _("Command finished")

        self.WriteCmdLog(
            "(%s) %s (%s)" % (str(time.ctime()), msg, stime),
            notification=event.notification,
        )

        if event.onDone:
            event.onDone(event)

        self.cmdOutputTimer.Stop()

        if event.cmd[0] == "g.gisenv":
            Debug.SetLevel()
            self.Redirect()

        # do nothing when no map added
        if event.returncode != 0 or event.aborted:
            event.Skip()
            return

        if event.cmd[0] not in globalvar.grassCmd:
            return

        # find which maps were created
        try:
            task = GUI(show=None).ParseCommand(event.cmd)
        except GException as e:
            print(e, file=sys.stderr)
            task = None
            return

        name = task.get_name()
        for p in task.get_options()["params"]:
            prompt = p.get("prompt", "")
            if prompt in ("raster", "vector", "raster_3d") and p.get("value", None):
                if p.get("age", "old") == "new" or name in (
                    "r.colors",
                    "r3.colors",
                    "v.colors",
                    "v.proj",
                    "r.proj",
                ):
                    # if multiple maps (e.g. r.series.interp), we need add each
                    if p.get("multiple", False):
                        lnames = p.get("value").split(",")
                        # in case multiple input (old) maps in r.colors
                        # we don't want to rerender it multiple times! just
                        # once
                        if p.get("age", "old") == "old":
                            lnames = lnames[0:1]
                    else:
                        lnames = [p.get("value")]
                    for lname in lnames:
                        if "@" not in lname:
                            lname += "@" + grass.gisenv()["MAPSET"]
                        if grass.find_file(lname, element=p.get("element"))["fullname"]:
                            self.mapCreated.emit(
                                name=lname, ltype=prompt, add=event.addLayer
                            )
                            gisenv = grass.gisenv()
                            self._giface.grassdbChanged.emit(
                                grassdb=gisenv["GISDBASE"],
                                location=gisenv["LOCATION_NAME"],
                                mapset=gisenv["MAPSET"],
                                action="new",
                                map=lname.split("@")[0],
                                element=prompt,
                            )
        if name == "r.mask":
            self.updateMap.emit()

        event.Skip()

    def OnProcessPendingOutputWindowEvents(self, event):
        wx.GetApp().ProcessPendingEvents()

    def UpdateHistoryFile(self, command):
        """Update history file

        :param command: the command given as a string
        """
        env = grass.gisenv()
        try:
            filePath = os.path.join(
                env["GISDBASE"], env["LOCATION_NAME"], env["MAPSET"], ".wxgui_history"
            )
            fileHistory = codecs.open(filePath, encoding="utf-8", mode="a")
        except IOError as e:
            GError(
                _("Unable to write file '%(filePath)s'.\n\nDetails: %(error)s")
                % {"filePath": filePath, "error": e},
                parent=self._guiparent,
            )
            return

        try:
            fileHistory.write(command + os.linesep)
        finally:
            fileHistory.close()

        # update wxGUI prompt
        if self._giface:
            self._giface.UpdateCmdHistory(command)
Exemple #25
0
class DMonMap(Map):
    def __init__(self, giface, cmdfile=None, mapfile=None):
        """Map composition (stack of map layers and overlays)

        :param cmdline: full path to the cmd file (defined by d.mon)
        :param mapfile: full path to the map file (defined by d.mon)
        """
        Map.__init__(self)

        self._giface = giface

        # environment settings
        self.env = dict()

        self.cmdfile = cmdfile

        # list of layers for rendering added from cmd file
        # TODO temporary solution, layer management by different tools in GRASS
        # should be resolved
        self.ownedLayers = []
        self.oldOverlays = []

        if mapfile:
            self.mapfileCmd = mapfile
            self.maskfileCmd = os.path.splitext(mapfile)[0] + ".pgm"

        # generated file for g.pnmcomp output for rendering the map
        self.mapfile = monFile["map"]
        if os.path.splitext(self.mapfile)[1] != ".ppm":
            self.mapfile += ".ppm"

        # signal sent when d.out.file/d.to.rast appears in cmd file, attribute
        # is cmd
        self.saveToFile = Signal("DMonMap.saveToFile")
        self.dToRast = Signal("DMonMap.dToRast")
        # signal sent when d.what.rast/vect appears in cmd file, attribute is
        # cmd
        self.query = Signal("DMonMap.query")

        self.renderMgr = RenderMapMgr(self)

        # update legend file variable with the one d.mon uses
        with open(monFile["env"], "r") as f:
            lines = f.readlines()
            for line in lines:
                if "GRASS_LEGEND_FILE" in line:
                    legfile = line.split("=", 1)[1].strip()
                    self.renderMgr.UpdateRenderEnv(
                        {"GRASS_LEGEND_FILE": legfile})
                    break

    def GetLayersFromCmdFile(self):
        """Get list of map layers from cmdfile"""
        if not self.cmdfile:
            return

        nlayers = 0
        try:
            fd = open(self.cmdfile, "r")
            lines = fd.readlines()
            fd.close()
            # detect d.out.file, delete the line from the cmd file and export
            # graphics
            if len(lines) > 0:
                if lines[-1].startswith("d.out.file") or lines[-1].startswith(
                        "d.to.rast"):
                    dCmd = lines[-1].strip()
                    fd = open(self.cmdfile, "w")
                    fd.writelines(lines[:-1])
                    fd.close()
                    if lines[-1].startswith("d.out.file"):
                        self.saveToFile.emit(cmd=utils.split(dCmd))
                    else:
                        self.dToRast.emit(cmd=utils.split(dCmd))
                    return
                if lines[-1].startswith("d.what"):
                    dWhatCmd = lines[-1].strip()
                    fd = open(self.cmdfile, "w")
                    fd.writelines(lines[:-1])
                    fd.close()
                    if "=" in utils.split(dWhatCmd)[1]:
                        maps = utils.split(dWhatCmd)[1].split("=")[1].split(
                            ",")
                    else:
                        maps = utils.split(dWhatCmd)[1].split(",")
                    self.query.emit(
                        ltype=utils.split(dWhatCmd)[0].split(".")[-1],
                        maps=maps)
                    return
            else:
                # clean overlays after erase
                self.oldOverlays = []
                overlays = list(
                    self._giface.GetMapDisplay().decorations.keys())
                for each in overlays:
                    self._giface.GetMapDisplay().RemoveOverlay(each)

            existingLayers = self.GetListOfLayers()

            # holds new rendreing order for every layer in existingLayers
            layersOrder = [-1] * len(existingLayers)

            # next number in rendering order
            next_layer = 0
            mapFile = None
            render_env = dict()
            for line in lines:
                if line.startswith("#"):
                    if "GRASS_RENDER_FILE" in line:
                        mapFile = line.split("=", 1)[1].strip()
                    try:
                        k, v = line[2:].strip().split("=", 1)
                    except:
                        pass
                    render_env[k] = v
                    continue

                cmd = utils.split(line.strip())

                ltype = None
                try:
                    ltype = utils.command2ltype[cmd[0]]
                except KeyError:
                    grass.warning(_("Unsupported command %s.") % cmd[0])
                    continue

                name = utils.GetLayerNameFromCmd(cmd,
                                                 fullyQualified=True,
                                                 layerType=ltype)[0]

                args = {}

                if ltype in ("barscale", "rastleg", "northarrow", "text",
                             "vectleg"):
                    # TODO: this is still not optimal
                    # it is there to prevent adding the same overlay multiple times
                    if cmd in self.oldOverlays:
                        continue
                    if ltype == "rastleg":
                        self._giface.GetMapDisplay().AddLegendRast(cmd=cmd)
                    elif ltype == "barscale":
                        self._giface.GetMapDisplay().AddBarscale(cmd=cmd)
                    elif ltype == "northarrow":
                        self._giface.GetMapDisplay().AddArrow(cmd=cmd)
                    elif ltype == "text":
                        self._giface.GetMapDisplay().AddDtext(cmd=cmd)
                    elif ltype == "vectleg":
                        self._giface.GetMapDisplay().AddLegendVect(cmd=cmd)
                    self.oldOverlays.append(cmd)
                    continue

                classLayer = MapLayer
                args["ltype"] = ltype

                exists = False
                for i, layer in enumerate(existingLayers):
                    if layer.GetCmd(string=True) == utils.GetCmdString(
                            cmdlist_to_tuple(cmd)):
                        exists = True

                        if layersOrder[i] == -1:
                            layersOrder[i] = next_layer
                            next_layer += 1
                        # layer must be put higher in render order (same cmd was insered more times)
                        # TODO delete rendurant cmds from cmd file?
                        else:
                            for j, l_order in enumerate(layersOrder):
                                if l_order > layersOrder[i]:
                                    layersOrder[j] -= 1
                            layersOrder[i] = next_layer - 1

                        break
                if exists:
                    continue

                mapLayer = classLayer(
                    name=name,
                    cmd=cmd,
                    Map=None,
                    hidden=True,
                    render=False,
                    mapfile=mapFile,
                    **args,
                )
                mapLayer.GetRenderMgr().updateProgress.connect(
                    self.GetRenderMgr().ReportProgress)
                if render_env:
                    mapLayer.GetRenderMgr().UpdateRenderEnv(render_env)
                    render_env = dict()

                newLayer = self._addLayer(mapLayer)

                existingLayers.append(newLayer)
                self.ownedLayers.append(newLayer)

                layersOrder.append(next_layer)
                next_layer += 1

                nlayers += 1

            reorderedLayers = [-1] * next_layer
            for i, layer in enumerate(existingLayers):

                # owned layer was not found in cmd file -> is deleted
                if layersOrder[i] == -1 and layer in self.ownedLayers:
                    self.ownedLayers.remove(layer)
                    self.DeleteLayer(layer)

                # other layer e. g. added by wx.vnet are added to the top
                elif layersOrder[i] == -1 and layer not in self.ownedLayers:
                    reorderedLayers.append(layer)

                # owned layer found in cmd file is added into proper rendering
                # position
                else:
                    reorderedLayers[layersOrder[i]] = layer

            self.SetLayers(reorderedLayers)

        except IOError as e:
            grass.warning(
                _("Unable to read cmdfile '%(cmd)s'. Details: %(det)s") % {
                    "cmd": self.cmdfile,
                    "det": e
                })
            return

        Debug.msg(
            1,
            "Map.GetLayersFromCmdFile(): cmdfile=%s, nlayers=%d" %
            (self.cmdfile, nlayers),
        )

        self._giface.updateMap.emit(render=False)

    def Render(self, *args, **kwargs):
        """Render layer to image.

        For input params and returned data see overridden method in Map class.
        """
        return Map.Render(self, *args, **kwargs)

    def AddLayer(self, *args, **kwargs):
        """Adds generic map layer to list of layers.

        For input params and returned data see overridden method in Map class.
        """
        driver = UserSettings.Get(group="display", key="driver", subkey="type")

        if driver == "png":
            os.environ["GRASS_RENDER_IMMEDIATE"] = "png"
        else:
            os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo"

        layer = Map.AddLayer(self, *args, **kwargs)

        del os.environ["GRASS_RENDER_IMMEDIATE"]

        return layer
Exemple #26
0
    def __init__(
            self, parent, layerList, lmgrStyle=SIMPLE_LMGR_RASTER |
            SIMPLE_LMGR_VECTOR | SIMPLE_LMGR_TB_LEFT, toolbarCls=None,
            modal=False):
        wx.Panel.__init__(self, parent=parent, name='SimpleLayerManager')

        self._style = lmgrStyle
        self._layerList = layerList
        self._checkList = CheckListBox(self, style=wx.LB_EXTENDED)
        if not toolbarCls:
            toolbarCls = SimpleLmgrToolbar
        self._toolbar = toolbarCls(self, lmgrStyle=self._style)

        self._auimgr = wx.aui.AuiManager(self)

        self._modal = modal
        # d.* dialogs are recreated each time, attempt to hide it resulted
        # in completely mysterious memory corruption and crash when opening
        # any dialog with stock labels (wx.ID_OK and so on)

        # needed in order not to change selection when moving layers
        self._blockSelectionChanged = False

        self._checkList.Bind(
            wx.EVT_LISTBOX,
            lambda evt: self._selectionChanged())
        self._checkList.Bind(
            wx.EVT_LISTBOX_DCLICK,
            self.OnLayerChangeProperties)
        self._checkList.Bind(wx.EVT_CHECKLISTBOX, self.OnLayerChecked)
        self._checkList.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)

        # signal emitted when somethin in layer list changes
        self.opacityChanged = Signal('SimpleLayerManager.opacityChanged')
        self.cmdChanged = Signal('SimpleLayerManager.cmdChanged')
        self.layerAdded = Signal('SimpleLayerManager.layerAdded')
        self.layerRemoved = Signal('SimpleLayerManager.layerRemoved')
        self.layerActivated = Signal('SimpleLayerManager.layerActivated')
        self.layerMovedUp = Signal('SimpleLayerManager.layerMovedUp')
        self.layerMovedDown = Signal('SimpleLayerManager.layerMovedDown')
        # emitted by any change (e.g. for rerendering)
        self.anyChange = Signal('SimpleLayerManager.layerChange')

        self._layout()
        self.SetMinSize((200, -1))
        self._update()
Exemple #27
0
class SimpleLayerManager(wx.Panel):
    """Simple layer manager class provides similar functionality to
    Layertree, but it's just list, not tree."""

    def __init__(
            self, parent, layerList, lmgrStyle=SIMPLE_LMGR_RASTER |
            SIMPLE_LMGR_VECTOR | SIMPLE_LMGR_TB_LEFT, toolbarCls=None,
            modal=False):
        wx.Panel.__init__(self, parent=parent, name='SimpleLayerManager')

        self._style = lmgrStyle
        self._layerList = layerList
        self._checkList = CheckListBox(self, style=wx.LB_EXTENDED)
        if not toolbarCls:
            toolbarCls = SimpleLmgrToolbar
        self._toolbar = toolbarCls(self, lmgrStyle=self._style)

        self._auimgr = wx.aui.AuiManager(self)

        self._modal = modal
        # d.* dialogs are recreated each time, attempt to hide it resulted
        # in completely mysterious memory corruption and crash when opening
        # any dialog with stock labels (wx.ID_OK and so on)

        # needed in order not to change selection when moving layers
        self._blockSelectionChanged = False

        self._checkList.Bind(
            wx.EVT_LISTBOX,
            lambda evt: self._selectionChanged())
        self._checkList.Bind(
            wx.EVT_LISTBOX_DCLICK,
            self.OnLayerChangeProperties)
        self._checkList.Bind(wx.EVT_CHECKLISTBOX, self.OnLayerChecked)
        self._checkList.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)

        # signal emitted when somethin in layer list changes
        self.opacityChanged = Signal('SimpleLayerManager.opacityChanged')
        self.cmdChanged = Signal('SimpleLayerManager.cmdChanged')
        self.layerAdded = Signal('SimpleLayerManager.layerAdded')
        self.layerRemoved = Signal('SimpleLayerManager.layerRemoved')
        self.layerActivated = Signal('SimpleLayerManager.layerActivated')
        self.layerMovedUp = Signal('SimpleLayerManager.layerMovedUp')
        self.layerMovedDown = Signal('SimpleLayerManager.layerMovedDown')
        # emitted by any change (e.g. for rerendering)
        self.anyChange = Signal('SimpleLayerManager.layerChange')

        self._layout()
        self.SetMinSize((200, -1))
        self._update()

    def _layout(self):
        self._auimgr.AddPane(self._checkList,
                             wx.aui.AuiPaneInfo().
                             Name("checklist").
                             CenterPane().
                             CloseButton(False).
                             BestSize((self._checkList.GetBestSize())))
        paneInfo = wx.aui.AuiPaneInfo(). \
            Name("toolbar").Caption(_("Toolbar")).ToolbarPane(). \
            CloseButton(False).Layer(1).Gripper(False). \
            BestSize((self._toolbar.GetBestSize()))
        if self._style & SIMPLE_LMGR_TB_LEFT:
            paneInfo.Left()
        elif self._style & SIMPLE_LMGR_TB_RIGHT:
            paneInfo.Right()
        elif self._style & SIMPLE_LMGR_TB_TOP:
            paneInfo.Top()
        else:
            paneInfo.Bottom()

        self._auimgr.AddPane(self._toolbar, paneInfo)
        self._auimgr.Update()

    def _selectionChanged(self):
        """Selection was changed externally,
        updates selection info in layers."""
        if self._blockSelectionChanged:
            return
        selected = self._checkList.GetSelections()
        for i, layer in enumerate(self._layerList):
            layer.Select(i in selected)

    def OnContextMenu(self, event):
        """Show context menu.

        So far offers only copying layer list to clipboard
        """
        if len(self._layerList) < 1:
            event.Skip()
            return

        menu = Menu()
        llist = [layer.name for layer in self._layerList]
        texts = [','.join(llist), ','.join(reversed(llist))]
        labels = [_("Copy map names to clipboard (top to bottom)"),
                  _("Copy map names to clipboard (bottom to top)")]
        for label, text in zip(labels, texts):
            id = wx.NewId()
            self.Bind(
                wx.EVT_MENU,
                lambda evt,
                t=text,
                id=id: self._copyText(t),
                id=id)

            menu.Append(id, label)

        # show the popup menu
        self.PopupMenu(menu)
        menu.Destroy()
        event.Skip()

    def _copyText(self, text):
        """Helper function for copying

        TODO: move to utils?
        """
        if wx.TheClipboard.Open():
            do = wx.TextDataObject()
            do.SetText(text)
            wx.TheClipboard.SetData(do)
            wx.TheClipboard.Close()

    def OnLayerChecked(self, event):
        """Layer was (un)checked, update layer's info."""
        checkedIdxs = self._checkList.GetChecked()
        for i, layer in enumerate(self._layerList):
            if i in checkedIdxs and not layer.IsActive():
                layer.Activate()
                self.layerActivated.emit(index=i, layer=layer)
            elif i not in checkedIdxs and layer.IsActive():
                layer.Activate(False)
                self.layerActivated.emit(index=i, layer=layer)
        self.anyChange.emit()
        event.Skip()

    def OnAddRaster(self, event):
        """Opens d.rast dialog and adds layer.
        Dummy layer is added first."""
        cmd = ['d.rast']
        layer = self.AddRaster(name='', cmd=cmd, hidden=True, dialog=None)
        GUI(parent=self, giface=None, modal=self._modal).ParseCommand(
            cmd=cmd, completed=(self.GetOptData, layer, ''))
        event.Skip()

    def OnAddVector(self, event):
        """Opens d.vect dialog and adds layer.
        Dummy layer is added first."""
        cmd = ['d.vect']

        layer = self.AddVector(name='', cmd=cmd, hidden=True, dialog=None)
        GUI(parent=self, giface=None, modal=self._modal).ParseCommand(
            cmd=cmd, completed=(self.GetOptData, layer, ''))
        event.Skip()

    def OnAddRast3d(self, event):
        """Opens d.rast3d dialog and adds layer.
        Dummy layer is added first."""
        cmd = ['d.rast3d']
        layer = self.AddRast3d(name='', cmd=cmd, hidden=True, dialog=None)
        GUI(parent=self, giface=None, modal=self._modal).ParseCommand(
            cmd=cmd, completed=(self.GetOptData, layer, ''))
        event.Skip()

    def OnAddRGB(self, event):
        """Opens d.rgb dialog and adds layer.
        Dummy layer is added first."""
        cmd = ['d.rgb']
        layer = self.AddRGB(name='', cmd=cmd, hidden=True, dialog=None)
        GUI(parent=self, giface=None, modal=self._modal).ParseCommand(
            cmd=cmd, completed=(self.GetOptData, layer, ''))
        event.Skip()

    def OnRemove(self, event):
        """Removes selected layers from list."""
        layers = self._layerList.GetSelectedLayers(activeOnly=False)
        for layer in layers:
            self.layerRemoved.emit(
                index=self._layerList.GetLayerIndex(layer), layer=layer)
            self._layerList.RemoveLayer(layer)
        self._update()
        self.anyChange.emit()
        event.Skip()

    def OnLayerUp(self, event):
        """Moves selected layers one step up.

        Note: not completely correct for multiple layers."""
        layers = self._layerList.GetSelectedLayers()
        self._blockSelectionChanged = True
        for layer in layers:
            idx = self._layerList.GetLayerIndex(layer)
            if idx > 0:
                self.layerMovedUp.emit(index=idx, layer=layer)
                self._layerList.MoveLayerUp(layer)
        self._update()
        self._blockSelectionChanged = False
        self.anyChange.emit()
        event.Skip()

    def OnLayerDown(self, event):
        """Moves selected layers one step down.

        Note: not completely correct for multiple layers."""
        layers = self._layerList.GetSelectedLayers()
        self._blockSelectionChanged = True
        for layer in layers:
            idx = self._layerList.GetLayerIndex(layer)
            if idx < len(self._layerList) - 1:
                self.layerMovedDown.emit(
                    index=self._layerList.GetLayerIndex(layer), layer=layer)
                self._layerList.MoveLayerDown(layer)
        self._update()
        self._blockSelectionChanged = False
        self.anyChange.emit()
        event.Skip()

    def OnLayerChangeProperties(self, event):
        """Opens module dialog to edit layer command."""
        layers = self._layerList.GetSelectedLayers()
        if not layers or len(layers) > 1:
            return
        self._layerChangeProperties(layers[0])
        event.Skip()

    def _layerChangeProperties(self, layer):
        """Opens new module dialog or recycles it."""
        GUI(parent=self, giface=None, modal=self._modal).ParseCommand(
            cmd=layer.cmd, completed=(self.GetOptData, layer, ''))

    def OnLayerChangeOpacity(self, event):
        """Opacity of a layer is changing."""
        layers = self._layerList.GetSelectedLayers()
        if not layers or len(layers) > 1:
            return
        layer = layers[0]
        dlg = SetOpacityDialog(self, opacity=layer.opacity,
                               title=_("Set opacity of <%s>") % layer.name)
        dlg.applyOpacity.connect(lambda value:
                                 self._setLayerOpacity(layer, value))
        dlg.CentreOnParent()

        if dlg.ShowModal() == wx.ID_OK:
            self._setLayerOpacity(layer, dlg.GetOpacity())
        dlg.Destroy()
        event.Skip()

    def _setLayerOpacity(self, layer, value):
        """Sets layer's opacity.'"""
        layer.opacity = value
        self._update()
        self.opacityChanged.emit(
            index=self._layerList.GetLayerIndex(layer),
            layer=layer)
        self.anyChange.emit()

    def _update(self):
        """Updates checklistbox according to layerList structure."""
        items = []
        active = []
        selected = []

        # remove hidden (temporary) layers first
        for layer in reversed(self._layerList):
            if layer.hidden:
                self._layerList.RemoveLayer(layer)

        for layer in self._layerList:
            if layer.opacity < 1:
                items.append(
                    "{name} (opacity {opacity}%)".format(
                        name=layer.name, opacity=int(
                            layer.opacity * 100)))
            else:
                items.append(layer.name)
            active.append(layer.IsActive())
            selected.append(layer.IsSelected())

        self._checkList.SetItems(items)
        for i, check in enumerate(active):
            self._checkList.Check(i, check)

        for i, layer in enumerate(self._layerList):
            if selected[i]:
                self._checkList.Select(i)
            else:
                self._checkList.Deselect(i)

    def GetOptData(self, dcmd, layer, params, propwin):
        """Handler for module dialogs."""
        if dcmd:
            layer.cmd = dcmd
            layer.selected = True
            mapName, found = GetLayerNameFromCmd(dcmd)
            if found:
                try:
                    if layer.hidden:
                        layer.hidden = False
                        signal = self.layerAdded
                    else:
                        signal = self.cmdChanged

                    layer.name = mapName
                    signal.emit(
                        index=self._layerList.GetLayerIndex(layer),
                        layer=layer)
                except ValueError as e:
                    self._layerList.RemoveLayer(layer)
                    GError(parent=self,
                           message=str(e),
                           showTraceback=False)

            self._update()
            self.anyChange.emit()

    def AddRaster(self, name, cmd, hidden, dialog):
        """Ads new raster layer."""
        layer = self._layerList.AddNewLayer(name=name, mapType='raster',
                                            active=True,
                                            cmd=cmd, hidden=hidden)
        return layer

    def AddRast3d(self, name, cmd, hidden, dialog):
        """Ads new raster3d layer."""
        layer = self._layerList.AddNewLayer(name=name, mapType='raster_3d',
                                            active=True,
                                            cmd=cmd, hidden=hidden)
        return layer

    def AddVector(self, name, cmd, hidden, dialog):
        """Ads new vector layer."""
        layer = self._layerList.AddNewLayer(name=name, mapType='vector',
                                            active=True,
                                            cmd=cmd, hidden=hidden)
        return layer

    def AddRGB(self, name, cmd, hidden, dialog):
        """Ads new vector layer."""
        layer = self._layerList.AddNewLayer(name=name, mapType='rgb',
                                            active=True,
                                            cmd=cmd, hidden=hidden)
        return layer

    def GetLayerInfo(self, layer, key):
        """Just for compatibility, should be removed in the future"""
        value = getattr(layer, key)
        # hack to return empty list, required in OnCancel in forms
        # not sure why it should be empty
        if key == 'cmd' and len(value) == 1:
            return []
        return value

    def Delete(self, layer):
        """Just for compatibility, should be removed in the future"""
        self._layerList.RemoveLayer(layer)
Exemple #28
0
class GPrompt(object):
    """Abstract class for interactive wxGUI prompt

    Signal promptRunCmd - emitted to run command from prompt
                        - attribute 'cmd'

    See subclass GPromptPopUp and GPromptSTC.
    """
    def __init__(self, parent, giface, menuModel):
        self.parent = parent  # GConsole
        self.panel = self.parent.GetPanel()

        self.promptRunCmd = Signal("GPrompt.promptRunCmd")

        # probably only subclasses need this
        self._menuModel = menuModel

        self.mapList = self._getListOfMaps()
        self.mapsetList = utils.ListOfMapsets()

        # auto complete items
        self.autoCompList = list()
        self.autoCompFilter = None

        # command description (gtask.grassTask)
        self.cmdDesc = None

        self._loadHistory()
        if giface:
            giface.currentMapsetChanged.connect(self._loadHistory)

        # list of traced commands
        self.commands = list()

        # reload map lists when needed
        if giface:
            giface.currentMapsetChanged.connect(self._reloadListOfMaps)
            giface.grassdbChanged.connect(self._reloadListOfMaps)

    def _readHistory(self):
        """Get list of commands from history file"""
        hist = list()
        env = grass.gisenv()
        try:
            fileHistory = codecs.open(
                os.path.join(
                    env["GISDBASE"],
                    env["LOCATION_NAME"],
                    env["MAPSET"],
                    ".wxgui_history",
                ),
                encoding="utf-8",
                mode="r",
                errors="replace",
            )
        except IOError:
            return hist

        try:
            for line in fileHistory.readlines():
                hist.append(line.replace("\n", ""))
        finally:
            fileHistory.close()

        return hist

    def _loadHistory(self):
        """Load history from a history file to data structures"""
        self.cmdbuffer = self._readHistory()
        self.cmdindex = len(self.cmdbuffer)

    def _getListOfMaps(self):
        """Get list of maps"""
        result = dict()
        result["raster"] = grass.list_strings("raster")
        result["vector"] = grass.list_strings("vector")

        return result

    def _reloadListOfMaps(self):
        self.mapList = self._getListOfMaps()

    def _runCmd(self, cmdString):
        """Run command

        :param str cmdString: command to run
        """
        if not cmdString:
            return

        # parse command into list
        try:
            cmd = utils.split(str(cmdString))
        except UnicodeError:
            cmd = utils.split(EncodeString((cmdString)))
        cmd = list(map(DecodeString, cmd))

        self.promptRunCmd.emit(cmd=cmd)

        self.OnCmdErase(None)
        self.ShowStatusText("")

    def GetCommands(self):
        """Get list of launched commands"""
        return self.commands

    def ClearCommands(self):
        """Clear list of commands"""
        del self.commands[:]
Exemple #29
0
    def __init__(self, parent, giface, menuModel, margin=False):
        GPrompt.__init__(self,
                         parent=parent,
                         giface=giface,
                         menuModel=menuModel)
        wx.stc.StyledTextCtrl.__init__(self, self.panel, id=wx.ID_ANY)

        #
        # styles
        #
        self.SetWrapMode(True)
        self.SetUndoCollection(True)

        #
        # create command and map lists for autocompletion
        #
        self.AutoCompSetIgnoreCase(False)

        #
        # line margins
        #
        # TODO print number only from cmdlog
        self.SetMarginWidth(1, 0)
        self.SetMarginWidth(2, 0)
        if margin:
            self.SetMarginType(0, wx.stc.STC_MARGIN_NUMBER)
            self.SetMarginWidth(0, 30)
        else:
            self.SetMarginWidth(0, 0)

        #
        # miscellaneous
        #
        self.SetViewWhiteSpace(False)
        self.SetUseTabs(False)
        self.UsePopUp(True)
        self.SetUseHorizontalScrollBar(True)

        # support light and dark mode
        bg_color = wx.SystemSettings().GetColour(wx.SYS_COLOUR_WINDOW)
        fg_color = wx.SystemSettings().GetColour(wx.SYS_COLOUR_WINDOWTEXT)
        selection_color = wx.SystemSettings().GetColour(
            wx.SYS_COLOUR_HIGHLIGHT)
        self.StyleSetBackground(wx.stc.STC_STYLE_DEFAULT, bg_color)
        self.StyleSetForeground(wx.stc.STC_STYLE_DEFAULT, fg_color)
        self.SetCaretForeground(fg_color)
        self.SetSelBackground(True, selection_color)
        self.StyleClearAll()

        #
        # bindings
        #
        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
        self.Bind(wx.EVT_CHAR, self.OnChar)
        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
        self.Bind(wx.stc.EVT_STC_AUTOCOMP_SELECTION, self.OnItemSelected)
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemChanged)
        if sys.platform != "darwin":  # unstable on Mac with wxPython 3
            self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)

        # signal which requests showing of a notification
        self.showNotification = Signal("GPromptSTC.showNotification")

        # signal to notify selected command
        self.commandSelected = Signal("GPromptSTC.commandSelected")
class ScanningPanel(wx.Panel):
    def __init__(self, parent, giface, settings, scaniface):
        wx.Panel.__init__(self, parent)
        self.giface = giface
        self.settings = settings
        self.scaniface = scaniface
        if 'scan' not in self.settings:
            self.settings['scan'] = {}
            self.settings['scan']['elevation'] = ''
            self.settings['scan']['region'] = ''
            self.settings['scan']['zexag'] = 1
            self.settings['scan']['smooth'] = 8
            self.settings['scan']['numscans'] = 1
            self.settings['scan']['rotation_angle'] = 180
            self.settings['scan']['resolution'] = 2
            self.settings['scan']['trim_nsewtb'] = '30,30,30,30,50,150'
            self.settings['scan']['interpolate'] = False
            self.settings['scan']['trim_tolerance'] = ''
            self.settings['scan']['resolution'] = 2

        self.scan = self.settings['scan']

        self.settingsChanged = Signal('ScanningPanel.settingsChanged')

        mainSizer = wx.BoxSizer(wx.VERTICAL)
        # define static boxes before all widgets are defined
        georefBox = wx.StaticBox(self, label='  Georeferencing  ')
        georefSizer = wx.StaticBoxSizer(georefBox, wx.VERTICAL)
        geomBox = wx.StaticBox(self, label='  Scan geometry  ')
        geomSizer = wx.StaticBoxSizer(geomBox, wx.VERTICAL)
        demBox = wx.StaticBox(self, label=' DEM quality ')
        demSizer = wx.StaticBoxSizer(demBox, wx.VERTICAL)

        # create widgets
        self.btnCalibrateTilt = wx.Button(self, label="Calibration 1")
        self.btnCalibrateTilt.SetToolTipString('Calibrate to remove tilt of the scanner and to set suitable distance from the scanner')
        self.btnCalibrateExtent = wx.Button(self, label="Calibration 2")
        self.btnCalibrateExtent.SetToolTipString('Calibrate to identify the extent and position of the scanned object')

        # widgets for model
        self.elevInput = Select(self, size=(-1, -1), type='raster')
        self.elevInput.SetToolTipString('Raster from which we take the georeferencing information')
        self.regionInput = Select(self, size=(-1, -1), type='region')
        self.regionInput.SetToolTipString('Saved region from which we take the georeferencing information')
        self.zexag = wx.TextCtrl(self)
        self.zexag.SetToolTipString('Set vertical exaggeration of the physical model')
        self.numscans = wx.SpinCtrl(self, min=1, max=5, initial=1)
        self.numscans.SetToolTipString('Set number of scans to integrate')
        self.rotate = wx.SpinCtrl(self, min=0, max=360, initial=180)
        self.rotate.SetToolTipString('Set angle of rotation of the sensor around Z axis (typically 180 degrees)')
        self.smooth = wx.TextCtrl(self)
        self.smooth.SetToolTipString('Set smoothing of the DEM (typically between 7 to 12, higher value means more smoothing)')
        self.resolution = wx.TextCtrl(self)
        self.resolution.SetToolTipString('Raster resolution in mm of the ungeoreferenced scan')
        self.trim = {}
        for each in 'tbnsew':
            self.trim[each] = wx.TextCtrl(self, size=(40, -1))
            if each in 'tb':
                self.trim[each].SetToolTipString('Distance from the scanner')
            else:
                self.trim[each].SetToolTipString('Distance from the center of scanning to the scanning boundary')
        self.trim_tolerance = wx.TextCtrl(self)
        self.trim_tolerance.SetToolTipString('Automatic trimming of the edges for rectangular models')
        self.interpolate = wx.CheckBox(self, label="Use interpolation instead of binning")
        self.interpolate.SetToolTipString('Interpolation avoids gaps in the scan, but takes longer')

        self.elevInput.SetValue(self.scan['elevation'])
        self.regionInput.SetValue(self.scan['region'])
        self.zexag.SetValue(str(self.scan['zexag']))
        self.rotate.SetValue(self.scan['rotation_angle'])
        self.numscans.SetValue(self.scan['numscans'])
        self.interpolate.SetValue(self.scan['interpolate'])
        for i, each in enumerate('nsewtb'):
            self.trim[each].SetValue(self.scan['trim_nsewtb'].split(',')[i])
        self.smooth.SetValue(str(self.scan['smooth']))
        self.resolution.SetValue(str(self.scan['resolution']))
        self.trim_tolerance.SetValue(str(self.scan['trim_tolerance']))

        # layout
        #
        # Geometry box
        #
        # rotation
        hSizer = wx.BoxSizer(wx.HORIZONTAL)
        hSizer.Add(wx.StaticText(self, label="Rotation angle:"), proportion=1, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        hSizer.Add(self.rotate, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        geomSizer.Add(hSizer, flag=wx.EXPAND)
        # trimming
        hSizer = wx.BoxSizer(wx.HORIZONTAL)
        hSizer.Add(wx.StaticText(self, label="Trim vertically [cm]:"), proportion=1, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        for each in 'tb':
            hSizer.Add(wx.StaticText(self, label=each.upper() + ':'), flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=2)
            hSizer.Add(self.trim[each], flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=2)
        hSizer.Add(self.btnCalibrateTilt, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=2)
        geomSizer.Add(hSizer, flag=wx.EXPAND)
        hSizer = wx.BoxSizer(wx.HORIZONTAL)
        hSizer.Add(wx.StaticText(self, label="Trim horizontally [cm]:"), proportion=1, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        for each in 'nsew':
            hSizer.Add(wx.StaticText(self, label=each.upper() + ':'), flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=3)
            hSizer.Add(self.trim[each], flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=2)
        hSizer.Add(self.btnCalibrateExtent, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=2)
        geomSizer.Add(hSizer, flag=wx.EXPAND)
        # automatic trim
        hSizer = wx.BoxSizer(wx.HORIZONTAL)
        hSizer.Add(wx.StaticText(self, label="Trim tolerance [0-1]:"), proportion=1, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        hSizer.Add(self.trim_tolerance, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        geomSizer.Add(hSizer, flag=wx.EXPAND)
        mainSizer.Add(geomSizer, flag=wx.EXPAND|wx.ALL, border=10)

        hSizer2 = wx.BoxSizer(wx.HORIZONTAL)
        #
        # Georeferencing box
        #
        # model parameters
        hSizer = wx.BoxSizer(wx.HORIZONTAL)
        hSizer.Add(wx.StaticText(self, label="Reference DEM:"), flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        hSizer.Add(self.elevInput, proportion=1, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        georefSizer.Add(hSizer, flag=wx.EXPAND)
        # region
        hSizer = wx.BoxSizer(wx.HORIZONTAL)
        hSizer.Add(wx.StaticText(self, label="Reference region:"), flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        hSizer.Add(self.regionInput, proportion=1, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        georefSizer.Add(hSizer, flag=wx.EXPAND)
        hSizer = wx.BoxSizer(wx.HORIZONTAL)
        hSizer.Add(wx.StaticText(self, label="Z-exaggeration:"), proportion=1, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        hSizer.Add(self.zexag, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        georefSizer.Add(hSizer, flag=wx.EXPAND)
        hSizer2.Add(georefSizer, proportion=1, flag=wx.EXPAND|wx.RIGHT, border=10)

        #
        # DEM properties box
        #
        # number of scans
        hSizer = wx.BoxSizer(wx.HORIZONTAL)
        hSizer.Add(wx.StaticText(self, label="Number of scans:"), proportion=1, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        hSizer.Add(self.numscans, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        demSizer.Add(hSizer, flag=wx.EXPAND)

        # smooth
        hSizer = wx.BoxSizer(wx.HORIZONTAL)
        hSizer.Add(wx.StaticText(self, label="Smooth value:"), proportion=1, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        hSizer.Add(self.smooth, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        demSizer.Add(hSizer, flag=wx.EXPAND)
        # resolution
        hSizer = wx.BoxSizer(wx.HORIZONTAL)
        hSizer.Add(wx.StaticText(self, label="Resolution [mm]:"), proportion=1, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        hSizer.Add(self.resolution, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        demSizer.Add(hSizer, flag=wx.EXPAND)

        hSizer = wx.BoxSizer(wx.HORIZONTAL)
        hSizer.Add(self.interpolate, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5)
        demSizer.Add(hSizer, flag=wx.EXPAND)

        hSizer2.Add(demSizer, proportion=1, flag=wx.EXPAND)
        mainSizer.Add(hSizer2, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, border=10)

        self.SetSizer(mainSizer)
        mainSizer.Fit(self)

        self.BindModelProperties()

    def BindModelProperties(self):
        self.btnCalibrateTilt.Bind(wx.EVT_BUTTON, self.scaniface.Calibrate)
        self.btnCalibrateExtent.Bind(wx.EVT_BUTTON, self.scaniface.CalibrateModelBBox)

        # model parameters
        self.elevInput.Bind(wx.EVT_TEXT, self.OnModelProperties)
        self.regionInput.Bind(wx.EVT_TEXT, self.OnModelProperties)
        self.zexag.Bind(wx.EVT_TEXT, self.OnModelProperties)
        self.rotate.Bind(wx.EVT_SPINCTRL, self.OnModelProperties)
        self.rotate.Bind(wx.EVT_TEXT, self.OnModelProperties)
        self.numscans.Bind(wx.EVT_SPINCTRL, self.OnModelProperties)
        self.numscans.Bind(wx.EVT_TEXT, self.OnModelProperties)
        self.interpolate.Bind(wx.EVT_CHECKBOX, self.OnModelProperties)
        self.smooth.Bind(wx.EVT_TEXT, self.OnModelProperties)
        self.resolution.Bind(wx.EVT_TEXT, self.OnModelProperties)
        self.trim_tolerance.Bind(wx.EVT_TEXT, self.OnModelProperties)
        for each in 'nsewtb':
            self.trim[each].Bind(wx.EVT_TEXT, self.OnModelProperties)

    def OnModelProperties(self, event):
        self.scan['elevation'] = self.elevInput.GetValue()
        self.scan['region'] = self.regionInput.GetValue()
        self.scan['rotation_angle'] = self.rotate.GetValue()
        self.scan['numscans'] = self.numscans.GetValue()
        self.scan['interpolate'] = self.interpolate.IsChecked()
        self.scan['smooth'] = self.smooth.GetValue()
        self.scan['resolution'] = self.resolution.GetValue()
        trim_tol = self.trim_tolerance.GetValue()
        self.scan['trim_tolerance'] = float(trim_tol) if trim_tol else trim_tol

        try:
            self.scan['zexag'] = float(self.zexag.GetValue())
            nsewtb_list = []
            for each in 'nsewtb':
                nsewtb_list.append(self.trim[each].GetValue())
            self.scan['trim_nsewtb'] = ','.join(nsewtb_list)
        except ValueError:
            pass
        self.settingsChanged.emit()
Exemple #31
0
class SQLBuilderUpdate(SQLBuilder):
    """Class for building UPDATE SQL statement"""

    def __init__(self, parent, vectmap, id=wx.ID_ANY,
                 layer=1, column=None):

        self.column = column
        # set dialog title
        title = _("GRASS SQL Builder (%(type)s) - <%(map)s>") % \
            {'type': "UPDATE", 'map': vectmap}

        modeChoices = [_("Column to set (SET clause)"),
                       _("Constraint for query (WHERE clause)"),
                       _("Calculate column value to set")]

        SQLBuilder.__init__(self, parent, title, vectmap, id=wx.ID_ANY,
                            modeChoices=modeChoices, layer=layer)

        # signals
        self.sqlApplied = Signal("SQLBuilder.sqlApplied")
        if parent:  # TODO: replace by giface
            self.sqlApplied.connect(parent.Update)

    def _doLayout(self, modeChoices):
        """Do dialog layout"""

        SQLBuilder._doLayout(self, modeChoices)

        self.initText = "UPDATE %s SET" % self.tablename
        if self.column:
            self.initText += " %s = " % self.column

        self.text_sql.SetValue(self.initText)

        self.btn_arithmetic = {'eq': ['=', ],
                               'brac': ['()', ],
                               'plus': ['+', ],
                               'minus': ['-', ],
                               'divide': ['/', ],
                               'multiply': ['*', ]}

        self.btn_arithmeticpanel = wx.Panel(parent=self.panel, id=wx.ID_ANY)

        for key, value in six.iteritems(self.btn_arithmetic):
            btn = Button(parent=self.btn_arithmeticpanel, id=wx.ID_ANY,
                            label=value[0])
            self.btn_arithmetic[key].append(btn.GetId())

        btn_arithmeticsizer = wx.GridBagSizer(hgap=5, vgap=5)

        btn_arithmeticsizer.Add(
            self.FindWindowById(
                self.btn_arithmetic['eq'][1]), pos=(
                0, 0))
        btn_arithmeticsizer.Add(
            self.FindWindowById(
                self.btn_arithmetic['brac'][1]), pos=(
                1, 0))

        btn_arithmeticsizer.Add(
            self.FindWindowById(
                self.btn_arithmetic['plus'][1]), pos=(
                0, 1))
        btn_arithmeticsizer.Add(
            self.FindWindowById(
                self.btn_arithmetic['minus'][1]), pos=(
                1, 1))

        btn_arithmeticsizer.Add(
            self.FindWindowById(
                self.btn_arithmetic['divide'][1]), pos=(
                0, 2))
        btn_arithmeticsizer.Add(
            self.FindWindowById(
                self.btn_arithmetic['multiply'][1]), pos=(
                1, 2))

        self.btn_arithmeticpanel.SetSizer(btn_arithmeticsizer)

        self.pagesizer.Insert(3, self.btn_arithmeticpanel,
                              proportion=0, flag=wx.ALIGN_CENTER_HORIZONTAL)

        self.funcpanel = wx.Panel(parent=self.panel, id=wx.ID_ANY)
        self._initSqlFunctions()
        funcsbox = StaticBox(parent=self.funcpanel, id=wx.ID_ANY,
                             label=" %s " % _("Functions"))
        funcsizer = wx.StaticBoxSizer(funcsbox, wx.VERTICAL)
        self.list_func = wx.ListBox(parent=self.funcpanel, id=wx.ID_ANY,
                                    choices=list(self.sqlFuncs['sqlite'].keys()),
                                    style=wx.LB_SORT)

        funcsizer.Add(self.list_func, proportion=1,
                      flag=wx.EXPAND)

        self.funcpanel.SetSizer(funcsizer)

        self.hsizer.Insert(2, self.funcpanel,
                           proportion=1, flag=wx.EXPAND)

        self.list_func.Bind(wx.EVT_LISTBOX, self.OnAddFunc)
        for key, value in six.iteritems(self.btn_arithmetic):
            self.FindWindowById(value[1]).Bind(wx.EVT_BUTTON, self.OnAddMark)
        self.mode.SetSelection(0)
        self.OnMode(None)
        self.text_sql.SetInsertionPoint(self.text_sql.GetLastPosition())

    def OnApply(self, event):
        """Apply button pressed"""

        ret, msg = RunCommand('db.execute',
                              getErrorMsg=True,
                              parent=self,
                              stdin=self.text_sql.GetValue(),
                              input='-',
                              driver=self.driver,
                              database=self.database)

        if ret != 0 and msg:
            self.statusbar.SetStatusText(_("SQL statement was not applied"), 0)
        else:
            self.statusbar.SetStatusText(_("SQL statement applied"), 0)

        self.sqlApplied.emit()

    def OnClear(self, event):
        """Clear button pressed"""
        self.text_sql.SetValue(self.initText)

    def OnMode(self, event):
        """Adjusts builder for chosen mode"""
        if self.mode.GetSelection() == 0:
            self.valuespanel.Hide()
            self.btn_logicpanel.Hide()
            self.btn_arithmeticpanel.Hide()
            self.funcpanel.Hide()
        elif self.mode.GetSelection() == 1:
            self.valuespanel.Show()
            self.btn_logicpanel.Show()
            self.btn_arithmeticpanel.Hide()
            self.funcpanel.Hide()
        elif self.mode.GetSelection() == 2:
            self.valuespanel.Hide()
            self.btn_logicpanel.Hide()
            self.btn_arithmeticpanel.Show()
            self.funcpanel.Show()
        self.pagesizer.Layout()

    def OnAddFunc(self, event):
        """Add function to the query"""

        if self.driver == 'dbf':
            GMessage(
                parent=self,
                message=_(
                    "Dbf driver does not support usage of SQL functions."))
            return

        idx = self.list_func.GetSelections()
        for i in idx:
            func = self.sqlFuncs['sqlite'][self.list_func.GetString(i)][0]
            self._add(element='func', value=func)

    def _add(self, element, value):
        """Add element to the query

        :param element: element to add (column, value)
        """
        sqlstr = self.text_sql.GetValue()
        curspos = self.text_sql.GetInsertionPoint()
        newsqlstr = ''

        if element in  ['value', 'mark', 'func'] or \
                (element == 'column' and self.mode.GetSelection() == 2):
            addstr = ' ' + value + ' '
            newsqlstr = sqlstr[:curspos] + addstr + sqlstr[curspos:]
            curspos += len(addstr)
        elif element == 'column':
            if self.mode.GetSelection() == 0:  # -> column
                idx1 = sqlstr.lower().find('set') + len('set')
                idx2 = sqlstr.lower().find('where')

                if idx2 >= 0:
                    colstr = sqlstr[idx1:idx2].strip()
                else:
                    colstr = sqlstr[idx1:].strip()

                cols = [col.split('=')[0].strip() for col in colstr.split(',')]
                if value in cols:
                    self.text_sql.SetInsertionPoint(curspos)
                    wx.CallAfter(self.text_sql.SetFocus)
                    return
                if colstr:
                    colstr += ','
                colstr = ' ' + colstr
                colstr += ' ' + value + '= '
                newsqlstr = sqlstr[:idx1] + colstr
                if idx2 >= 0:
                    newsqlstr += sqlstr[idx2:]
                curspos = idx1 + len(colstr)

            elif self.mode.GetSelection() == 1:  # -> where
                newsqlstr = ''
                if sqlstr.lower().find('where') < 0:
                    newsqlstr += ' WHERE'
                newsqlstr += ' ' + value
                curspos = self.text_sql.GetLastPosition() + len(newsqlstr)
                newsqlstr = sqlstr + newsqlstr

        if newsqlstr:
            self.text_sql.SetValue(newsqlstr)

        wx.CallAfter(self.text_sql.SetFocus)
        self.text_sql.SetInsertionPoint(curspos)

    def _initSqlFunctions(self):

        self.sqlFuncs = {}
        # TODO add functions for other drivers
        self.sqlFuncs['sqlite'] = {
            'ABS': ['ABS()'],
            'LENGTH': ['LENGTH()'],
            'LOWER': ['LOWER()'],
            'LTRIM': ['LTRIM(,)'],
            'MAX': ['MAX()'],
            'MIN': ['MIN()'],
            'RTRIM': ['RTRIM(,)'],
            'SUBSTR': ['SUBSTR (,[,])'],
            'TRIM': ['TRIM (,)']
        }
class DrawingPanel(wx.Panel):
    def __init__(self, parent, giface, settings):
        wx.Panel.__init__(self, parent)
        self.giface = giface
        self.settings = settings
        self.settingsChanged = Signal('ScanningPanel.settingsChanged')

        if 'drawing' not in self.settings:
            self.settings['drawing'] = {}
            self.settings['drawing']['active'] = False
            self.settings['drawing']['name'] = ''
            self.settings['drawing']['type'] = 'point'
            self.settings['drawing']['append'] = False
            self.settings['drawing']['appendName'] = ''
            self.settings['drawing']['threshold'] = 760

        mainSizer = wx.BoxSizer(wx.VERTICAL)
        self.ifDraw = wx.CheckBox(self, label=_("Draw vector:"))
        self.ifDraw.SetValue(self.settings['drawing']['active'])
        self.ifDraw.Bind(wx.EVT_CHECKBOX, self.OnDrawChange)
        self.ifDraw.Bind(wx.EVT_CHECKBOX, self.OnEnableDrawing)
        self.draw_vector = Select(self, size=(-1, -1), type='vector')
        self.draw_vector.SetValue(self.settings['drawing']['name'])
        self.draw_vector.Bind(wx.EVT_TEXT, self.OnDrawChange)
        self.draw_type = wx.RadioBox(parent=self, label="Vector type", choices=['point', 'line', 'area'])
        {'point': 0, 'line': 1, 'area': 2}[self.settings['drawing']['type']]
        self.draw_type.SetSelection({'point': 0, 'line': 1, 'area': 2}[self.settings['drawing']['type']])
        self.draw_type.Bind(wx.EVT_RADIOBOX, self.OnDrawChange)
        self.threshold = wx.SpinCtrl(parent=self, min=0, max=765, initial=int(self.settings['drawing']['threshold']))
        self.threshold.SetValue(int(self.settings['drawing']['threshold']))
        self.threshold.Bind(wx.EVT_SPINCTRL, self.OnDrawChange)
        self.append = wx.CheckBox(parent=self, label="Append vector")
        self.append.SetValue(self.settings['drawing']['append'])
        self.append.Bind(wx.EVT_CHECKBOX, self.OnDrawChange)
        self.appendName = Select(self, size=(-1, -1), type='vector')
        self.appendName.SetValue(self.settings['drawing']['appendName'])
        self.appendName.Bind(wx.EVT_TEXT, self.OnDrawChange)
        self.clearBtn = wx.Button(parent=self, label="Clear")
        self.clearBtn.Bind(wx.EVT_BUTTON, lambda evt: self._newAppendedVector(evt))

        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(self.ifDraw, flag=wx.ALIGN_CENTER_VERTICAL, border=5)
        sizer.Add(self.draw_vector, proportion=1, flag=wx.ALIGN_CENTER_VERTICAL, border=5)
        mainSizer.Add(sizer, flag=wx.EXPAND | wx.ALL, border=5)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(self.draw_type, proportion=1, flag=wx.ALIGN_CENTER_VERTICAL, border=5)
        mainSizer.Add(sizer, flag=wx.EXPAND | wx.ALL, border=5)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(wx.StaticText(self, label='Brightness threshold:'), proportion=0, flag=wx.ALIGN_CENTER_VERTICAL, border=5)
        sizer.Add(self.threshold, proportion=1, flag=wx.ALIGN_CENTER_VERTICAL, border=5)
        mainSizer.Add(sizer, flag=wx.EXPAND | wx.ALL, border=5)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(self.append, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL, border=5)
        sizer.Add(self.appendName, proportion=1, flag=wx.ALIGN_CENTER_VERTICAL, border=5)
        sizer.Add(self.clearBtn, flag=wx.ALIGN_CENTER_VERTICAL, border=5)
        mainSizer.Add(sizer, flag=wx.EXPAND | wx.ALL, border=5)
        self.SetSizer(mainSizer)
        mainSizer.Fit(self)
        self.EnableDrawing(self.ifDraw.IsChecked())

    def OnDrawChange(self, event):
        self.settings['drawing']['active'] = self.ifDraw.GetValue()
        self.settings['drawing']['name'] = self.draw_vector.GetValue().split('@')[0]
        self.settings['drawing']['appendName'] = self.appendName.GetValue().split('@')[0]
        self.settings['drawing']['type'] = ['point', 'line', 'area'][self.draw_type.GetSelection()]
        self.settings['drawing']['append'] = self.append.IsChecked()
        self.settings['drawing']['threshold'] = self.threshold.GetValue()
        event.Skip()
        self.settingsChanged.emit()

    def OnEnableDrawing(self, event):
        self.EnableDrawing(self.ifDraw.IsChecked())
        event.Skip()

    def EnableDrawing(self, enable):
        self.draw_vector.Enable(enable)
        self.appendName.Enable(enable)
        self.draw_type.Enable(enable)
        self.append.Enable(enable)
        self.threshold.Enable(enable)
        self.clearBtn.Enable(enable)

    def appendVector(self):
        if not self.settings['drawing']['append']:
            return
        ff = gscript.find_file(self.settings['drawing']['appendName'],
                               element='vector', mapset=gscript.gisenv()['MAPSET'])
        if not(ff and ff['fullname']):
            self._newAppendedVector()
        gscript.run_command('v.patch', input=self.settings['drawing']['name'],
                            output=self.settings['drawing']['appendName'],
                            flags='a', overwrite=True, quiet=True)

    def _newAppendedVector(self, event=None):
        gscript.run_command('v.edit', tool='create', map=self.settings['drawing']['appendName'],
                            overwrite=True, quiet=True)
Exemple #33
0
class LayersList(TreeCtrl):
    def __init__(self, parent, web_service, style, pos=wx.DefaultPosition):
        """List of layers and styles available in capabilities file"""
        self.parent = parent
        self.ws = web_service

        TreeCtrl.__init__(self, parent=parent, id=wx.ID_ANY, style=style)

        self.root = None
        self.Bind(wx.EVT_TREE_SEL_CHANGING, self.OnListSelChanging)

        self.layerSelected = Signal("LayersList.layerSelected")

    def LoadData(self, cap=None):
        """Load data into list"""
        # detete first all items
        self.DeleteAllItems()

        if not cap:
            return

        def AddLayerChildrenToTree(parent_layer, parent_item):
            """Recursive function which adds all capabilities
            layers/styles to the LayersList.
            """

            def gettitle(layer):
                """Helper function"""
                if layer.GetLayerData("title") is not None:
                    layer_title = layer.GetLayerData("title")
                elif layer.GetLayerData("name") is not None:
                    layer_title = layer.GetLayerData("name")
                else:
                    layer_title = str(layer.GetId())

                return layer_title

            def addlayer(layer, item):
                styles = layer.GetLayerData("styles")

                def_st = None
                for st in styles:

                    if st["name"]:
                        style_name = st["name"]
                    else:
                        continue

                    if st["title"]:
                        style_name = st["title"]

                    if st["isDefault"]:
                        def_st = st

                    style_item = self.AppendItem(item, style_name)

                    self.SetItemData(
                        style_item,
                        {
                            "type": "style",
                            "layer": layer,  # it is parent layer of style
                            "style": st,
                        },
                    )

                self.SetItemData(
                    item,
                    {
                        "type": "layer",  # is it layer or style?
                        "layer": layer,  # Layer instance from web_services.cap_interface
                        "style": def_st,
                    },
                )  # layer can have assigned default style

            if parent_layer is None:
                parent_layer = cap.GetRootLayer()
                layer_title = gettitle(parent_layer)
                parent_item = self.AddRoot(layer_title)
                addlayer(parent_layer, parent_item)

            for layer in parent_layer.GetChildren():
                item = self.AppendItem(parent_item, gettitle(layer))
                addlayer(layer, item)
                AddLayerChildrenToTree(layer, item)

        AddLayerChildrenToTree(None, None)
        # self.ExpandAll(self.GetRootItem())

    def GetSelectedLayers(self):
        """Get selected layers/styles in LayersList

        :return: dict with these items:
                 * 'name'  : layer name used for request
                   if it is style, it is name of parent layer
                 * 'title' : layer title
                 * 'style' : {'name' : 'style name', title : 'style title'}
                 * 'cap_intf_l' : \*Layer instance from web_services.cap_interface
        """
        sel_layers = self.GetSelections()
        sel_layers_dict = []
        for s in sel_layers:
            try:
                layer = self.GetItemData(s)["layer"]
            except ValueError:
                continue
            sel_layers_dict.append(
                {
                    "name": layer.GetLayerData("name"),
                    "title": layer.GetLayerData("title"),
                    "style": self.GetItemData(s)["style"],
                    "cap_intf_l": layer,
                }
            )
        return sel_layers_dict

    def OnListSelChanging(self, event):
        """Do not allow selecting items, which cannot be requested from server."""

        def _emitSelected(layer):
            title = layer.GetLayerData("title")
            self.layerSelected.emit(title=title)

        def _selectRequestableChildren(item, list_to_check, items_to_sel):

            self.Expand(item)
            child_item, cookie = self.GetFirstChild(item)
            while child_item and child_item.IsOk():
                if self.GetItemData(child_item)[
                    "layer"
                ].IsRequestable() and not self.IsSelected(child_item):
                    items_to_sel.append(child_item)
                elif not self.GetItemData(child_item)["layer"].IsRequestable():
                    list_to_check.append(child_item)

                child_item, cookie = self.GetNextChild(item, cookie)

        cur_item = event.GetItem()
        if not self.GetItemData(cur_item)["layer"].IsRequestable():
            event.Veto()

            if not self.HasFlag(wx.TR_MULTIPLE):
                return

            _emitSelected(self.GetItemData(cur_item)["layer"])

            items_to_chck = []
            items_to_sel = []
            chck_item = cur_item

            while True:
                _selectRequestableChildren(chck_item, items_to_chck, items_to_sel)
                if items_to_chck:
                    chck_item = items_to_chck.pop()
                else:
                    break

            while items_to_sel:
                self.SelectItem(items_to_sel.pop(), select=True)
        else:
            _emitSelected(self.GetItemData(cur_item)["layer"])

    def GetItemCount(self):
        """Required for listmix.ListCtrlAutoWidthMixin"""
        return 0

    def GetCountPerPage(self):
        """Required for listmix.ListCtrlAutoWidthMixin"""
        return 0

    def SelectLayers(self, l_st_list):
        """Select layers/styles in LayersList

        :param l_st_list: [{style : 'style_name', layer : 'layer_name'}, ...]
        :return: items from l_st_list which were not found
        """

        def checknext(root_item, l_st_list, items_to_sel):
            def compare(item, l_name, st_name):
                it_l_name = self.GetItemData(item)["layer"].GetLayerData("name")
                it_st = self.GetItemData(item)["style"]
                it_type = self.GetItemData(item)["type"]

                if it_l_name == l_name and (
                    (not it_st and not st_name)
                    or (it_st and it_st["name"] == st_name and it_type == "style")
                ):

                    return True

                return False

            (child, cookie) = self.GetFirstChild(root_item)
            while child.IsOk():
                for i, l_st in enumerate(l_st_list):
                    l_name = l_st["layer"]
                    st_name = l_st["style"]

                    if compare(child, l_name, st_name):
                        items_to_sel[i] = [child, l_st]
                        break

                if len(items_to_sel) == len(l_st_list):
                    if self.ItemHasChildren(child):
                        checknext(child, l_st_list, items_to_sel)
                    child = self.GetNextSibling(child)

        self.UnselectAll()

        l_st_list = deepcopy(l_st_list)
        root_item = self.GetRootItem()

        items_to_sel = [None] * len(l_st_list)
        checknext(root_item, l_st_list, items_to_sel)
        self.CollapseAll()

        # items are selected according to position in l_st_list
        # to be added to Layers order list in right order
        for i in items_to_sel:
            if not i:
                continue

            item, l_st = i
            keep = False
            if self.HasFlag(wx.TR_MULTIPLE):
                keep = True

            self.SelectItem(item, select=keep)
            self.SetFocusedItem(item)
            self.Expand(item)
            l_st_list.remove(l_st)

        return l_st_list
Exemple #34
0
class SearchModuleWindow(wx.Panel):
    """Menu tree and search widget for searching modules.

    Signal:
        showNotification - attribute 'message'
    """
    def __init__(self,
                 parent,
                 handlerObj,
                 giface,
                 model,
                 id=wx.ID_ANY,
                 **kwargs):
        self.parent = parent
        self._handlerObj = handlerObj
        self._giface = giface

        self.showNotification = Signal('SearchModuleWindow.showNotification')
        wx.Panel.__init__(self, parent=parent, id=id, **kwargs)

        # tree
        self._tree = CTreeView(model=model, parent=self)
        self._tree.SetToolTip(
            _("Double-click or Ctrl-Enter to run selected module"))

        #        self._dataBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
        #                                     label = " %s " % _("Module tree"))

        # search widget
        self._search = SearchModuleWidget(parent=self,
                                          model=model,
                                          showChoice=False)
        self._search.showSearchResult.connect(
            lambda result: self._tree.Select(result))
        self._search.showNotification.connect(self.showNotification)

        self._helpText = StaticText(
            parent=self,
            id=wx.ID_ANY,
            label="Press Enter for next match, Ctrl+Enter to run command")
        self._helpText.SetForegroundColour(
            wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))

        # buttons
        self._btnRun = Button(self, id=wx.ID_OK, label=_("&Run"))
        self._btnRun.SetToolTip(_("Run selected module from the tree"))
        self._btnHelp = Button(self, id=wx.ID_ANY, label=_("H&elp"))
        self._btnHelp.SetToolTip(
            _("Show manual for selected module from the tree"))
        self._btnAdvancedSearch = Button(self,
                                         id=wx.ID_ANY,
                                         label=_("Adva&nced search..."))
        self._btnAdvancedSearch.SetToolTip(
            _("Do advanced search using %s module") % 'g.search.module')

        # bindings
        self._btnRun.Bind(wx.EVT_BUTTON, lambda evt: self.Run())
        self._btnHelp.Bind(wx.EVT_BUTTON, lambda evt: self.Help())
        self._btnAdvancedSearch.Bind(wx.EVT_BUTTON,
                                     lambda evt: self.AdvancedSearch())
        self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)

        self._tree.selectionChanged.connect(self.OnItemSelected)
        self._tree.itemActivated.connect(lambda node: self.Run(node))

        self._layout()

        self._search.SetFocus()

    def _layout(self):
        """Do dialog layout"""
        sizer = wx.BoxSizer(wx.VERTICAL)

        # body
        dataSizer = wx.BoxSizer(wx.HORIZONTAL)
        dataSizer.Add(self._tree, proportion=1, flag=wx.EXPAND)

        # buttons
        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        btnSizer.Add(self._btnAdvancedSearch, proportion=0)
        btnSizer.AddStretchSpacer()
        btnSizer.Add(self._btnHelp, proportion=0)
        btnSizer.Add(self._btnRun, proportion=0)

        sizer.Add(dataSizer, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)

        sizer.Add(self._search,
                  proportion=0,
                  flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
                  border=5)

        sizer.Add(btnSizer,
                  proportion=0,
                  flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
                  border=5)

        sizer.Add(self._helpText,
                  proportion=0,
                  flag=wx.EXPAND | wx.LEFT,
                  border=5)

        sizer.Fit(self)
        sizer.SetSizeHints(self)

        self.SetSizer(sizer)

        self.Fit()
        self.SetAutoLayout(True)
        self.Layout()

    def _GetSelectedNode(self):
        selection = self._tree.GetSelected()
        if not selection:
            return None
        return selection[0]

    def Run(self, node=None):
        """Run selected command.

        :param node: a tree node associated with the module or other item
        """
        if not node:
            node = self._GetSelectedNode()
        # nothing selected
        if not node:
            return
        data = node.data
        # non-leaf nodes
        if not data:
            return

        # extract name of the handler and create a new call
        handler = 'self._handlerObj.' + data['handler'].lstrip('self.')

        if data['command']:
            eval(handler)(event=None, cmd=data['command'].split())
        else:
            eval(handler)(event=None)

    def Help(self, node=None):
        """Show documentation for a module"""
        if not node:
            node = self._GetSelectedNode()
        # nothing selected
        if not node:
            return
        data = node.data
        # non-leaf nodes
        if not data:
            return

        if not data['command']:
            # showing nothing for non-modules
            return
        # strip parameters from command if present
        name = data['command'].split()[0]
        self._giface.Help(name)
        self.showNotification.emit(
            message=_("Documentation for %s is now open in the web browser") %
            name)

    def AdvancedSearch(self):
        """Show advanced search window"""
        self._handlerObj.RunMenuCmd(cmd=['g.search.modules'])

    def OnKeyUp(self, event):
        """Key or key combination pressed"""
        if event.ControlDown() and \
                event.GetKeyCode() in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER):
            self.Run()

    def OnItemSelected(self, node):
        """Item selected"""
        data = node.data
        if not data or 'command' not in data:
            return

        if data['command']:
            label = data['command']
            if data['description']:
                label += ' -- ' + data['description']
        else:
            label = data['description']

        self.showNotification.emit(message=label)
Exemple #35
0
class SwipeMapDialog(wx.Dialog):
    """Dialog used to select maps.

    There are two modes - simple (only two raster maps),
    or two layer lists.
    """

    def __init__(self, parent, title=_("Select raster maps"),
                 first=None, second=None,
                 firstLayerList=None, secondLayerList=None):

        wx.Dialog.__init__(self, parent=parent, title=title,
                           style=wx.RESIZE_BORDER | wx.DEFAULT_DIALOG_STYLE)

        if firstLayerList is None:
            self._firstLayerList = LayerList()
        else:
            self._firstLayerList = copy.deepcopy(firstLayerList)
        if secondLayerList is None:
            self._secondLayerList = LayerList()
        else:
            self._secondLayerList = copy.deepcopy(secondLayerList)

        self._firstPanel = self._createSimplePanel()
        self._secondPanel = self._createAdvancedPanel()

        self.btnSwitch = Button(self)
        self.btnCancel = Button(self, id=wx.ID_CANCEL)
        self.btnApply = Button(self, id=wx.ID_APPLY)
        self.btnOK = Button(self, id=wx.ID_OK)
        self.btnOK.SetDefault()

        self.btnSwitch.Bind(wx.EVT_BUTTON, self.OnSwitchMode)
        self.btnApply.Bind(wx.EVT_BUTTON, lambda evt: self._apply())
        self.btnOK.Bind(wx.EVT_BUTTON, lambda evt: self._ok())
        self.btnCancel.Bind(wx.EVT_BUTTON, lambda evt: self.Close())
        self.Bind(wx.EVT_CLOSE, lambda evt: self.Hide())

        self.applyChanges = Signal('SwipeMapDialog.applyChanges')

        if first:
            self._firstRaster.SetValue(first)
        if second:
            self._secondRaster.SetValue(second)

        self._layout()

    def UnInit(self):
        self._firstLmgr.UnInit()
        self._secondLmgr.UnInit()

    def _layout(self):
        """Do layout"""
        mainSizer = wx.BoxSizer(wx.VERTICAL)
        self._switchSizer = wx.BoxSizer()
        self._switchSizer.Add(self._firstPanel, proportion=1,
                              flag=wx.EXPAND | wx.ALL, border=5)
        self._switchSizer.Add(self._secondPanel, proportion=1,
                              flag=wx.EXPAND | wx.ALL, border=5)
        mainSizer.Add(self._switchSizer, proportion=1,
                      flag=wx.EXPAND | wx.ALL)

        self.btnSizer = wx.StdDialogButtonSizer()
        self.btnSizer.AddButton(self.btnCancel)
        self.btnSizer.AddButton(self.btnOK)
        self.btnSizer.AddButton(self.btnApply)
        self.btnSizer.Realize()

        mainSizer.Add(self.btnSwitch, proportion=0,
                      flag=wx.ALL | wx.ALIGN_LEFT, border=5)
        mainSizer.Add(self.btnSizer, proportion=0,
                      flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
        self.mainSizer = mainSizer
        self._switchMode(simple=True)
        self.SetSizer(mainSizer)
        mainSizer.Fit(self)

    def _createSimplePanel(self):
        panel = wx.Panel(self)
        sizer = wx.BoxSizer(wx.VERTICAL)

        self._firstRaster = gselect.Select(
            parent=panel,
            type='raster',
            size=globalvar.DIALOG_GSELECT_SIZE,
            validator=SimpleValidator(
                callback=self.ValidatorCallback))

        self._secondRaster = gselect.Select(
            parent=panel,
            type='raster',
            size=globalvar.DIALOG_GSELECT_SIZE,
            validator=SimpleValidator(
                callback=self.ValidatorCallback))
        sizer.Add(
            StaticText(
                panel,
                label=_("Name of top/left raster map:")),
            proportion=0,
            flag=wx.EXPAND | wx.ALL,
            border=5)
        sizer.Add(self._firstRaster, proportion=0,
                  flag=wx.EXPAND | wx.ALL, border=1)
        sizer.Add(
            StaticText(
                panel,
                label=_("Name of bottom/right raster map:")),
            proportion=0,
            flag=wx.EXPAND | wx.ALL,
            border=1)
        sizer.Add(self._secondRaster, proportion=0,
                  flag=wx.EXPAND | wx.ALL, border=1)

        self._firstRaster.SetFocus()

        panel.SetSizer(sizer)
        sizer.Fit(panel)

        return panel

    def _createAdvancedPanel(self):
        panel = wx.Panel(self)
        sizer = wx.BoxSizer(wx.HORIZONTAL)

        self._firstLmgr = SimpleLayerManager(
            parent=panel, layerList=self._firstLayerList,
            lmgrStyle=SIMPLE_LMGR_RASTER | SIMPLE_LMGR_RGB | SIMPLE_LMGR_VECTOR |
            SIMPLE_LMGR_TB_LEFT)
        self._secondLmgr = SimpleLayerManager(
            parent=panel, layerList=self._secondLayerList,
            lmgrStyle=SIMPLE_LMGR_RASTER | SIMPLE_LMGR_RGB | SIMPLE_LMGR_VECTOR |
            SIMPLE_LMGR_TB_RIGHT)
        sizer.Add(
            self._firstLmgr,
            proportion=1,
            flag=wx.EXPAND | wx.ALL,
            border=5)
        sizer.Add(
            self._secondLmgr,
            proportion=1,
            flag=wx.EXPAND | wx.ALL,
            border=5)
        panel.SetSizer(sizer)
        sizer.Fit(panel)

        return panel

    def _switchMode(self, simple):
        if simple:
            self._switchSizer.Show(self._firstPanel, show=True, recursive=True)
            self._switchSizer.Show(
                self._secondPanel, show=False, recursive=True)
            self.btnSwitch.SetLabel(_("Switch to advanced mode"))
            self.btnCancel.SetLabel(_("Cancel"))
        else:
            self._switchSizer.Show(
                self._firstPanel, show=False, recursive=True)
            self._switchSizer.Show(
                self._secondPanel, show=True, recursive=True)
            self.btnSwitch.SetLabel(_("Switch to simple mode"))
            self.btnCancel.SetLabel(_("Close"))

        self.Freeze()  # doesn't do anything (at least on Ubuntu)
        self.btnSizer.Show(self.btnApply, simple)
        self.btnSizer.Show(self.btnOK, simple)
        self.btnSizer.Layout()
        self._switchSizer.Layout()
        self.Fit()
        self.Thaw()

        self.applyChanges.emit()

    def OnSwitchMode(self, event):
        if self._switchSizer.IsShown(self._secondPanel):
            self._switchMode(simple=True)
        else:
            self._switchMode(simple=False)

    def ValidatorCallback(self, win):
        if self._switchSizer.IsShown(self._secondPanel):
            return

        if win == self._firstRaster.GetTextCtrl():
            GMessage(parent=self, message=_(
                "Name of the first map is missing."))
        else:
            GMessage(parent=self, message=_(
                "Name of the second map is missing."))

    def _ok(self):
        self._apply()
        self.Close()

    def _apply(self):
        # TODO check if not empty
        self.applyChanges.emit()

    def GetValues(self):
        """Get raster maps"""
        if self.IsSimpleMode():
            return (self._firstRaster.GetValue(),
                    self._secondRaster.GetValue())
        else:
            return (self._firstLayerList, self._secondLayerList)

    def IsSimpleMode(self):
        if self._switchSizer.IsShown(self._firstPanel):
            return True
        return False

    def GetFirstSimpleLmgr(self):
        return self._firstLmgr

    def GetSecondSimpleLmgr(self):
        return self._secondLmgr
Exemple #36
0
    def __init__(self, parent, samplingType, icon=None, map_=None):
        wx.Panel.__init__(self, parent=parent)

        self.mapWindowProperties = MapWindowProperties()
        self.mapWindowProperties.setValuesFromUserSettings()
        giface = StandaloneGrassInterface()
        self.samplingtype = samplingType
        self.parent = parent

        if map_:
            self.map_ = map_
        else:
            self.map_ = Map()
        self.map_.region = self.map_.GetRegion()

        self._mgr = wx.aui.AuiManager(self)
        self.mapWindow = BufferedMapWindow(
            parent=self,
            giface=giface,
            Map=self.map_,
            properties=self.mapWindowProperties,
        )
        self._mgr.AddPane(
            self.mapWindow,
            wx.aui.AuiPaneInfo().CentrePane().Dockable(True).BestSize(
                (-1, -1)).Name("mapwindow").CloseButton(False).DestroyOnClose(
                    True).Layer(0),
        )
        self._toolSwitcher = ToolSwitcher()
        self._toolSwitcher.toggleToolChanged.connect(self._onToolChanged)
        self.toolbar = RLiSetupToolbar(self, self._toolSwitcher)

        self.catId = 1

        self._mgr.AddPane(
            self.toolbar,
            wx.aui.AuiPaneInfo().Name("maptoolbar").Caption(
                _("Map Toolbar")).ToolbarPane().Left().Name("mapToolbar").
            CloseButton(False).Layer(1).Gripper(False).BestSize(
                (self.toolbar.GetBestSize())),
        )
        self._mgr.Update()

        if self.samplingtype == SamplingType.REGIONS:
            self.afterRegionDrawn = Signal("RLiSetupMapPanel.afterRegionDrawn")
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
                graphicsType="line")
        elif self.samplingtype in [SamplingType.MUNITSR, SamplingType.MMVWINR]:
            self.sampleFrameChanged = Signal(
                "RLiSetupMapPanel.sampleFrameChanged")
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
                graphicsType="rectangle")
        elif self.samplingtype in [SamplingType.MUNITSC, SamplingType.MMVWINC]:
            self.afterCircleDrawn = Signal("RLiSetupMapPanel.afterCircleDrawn")
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
                graphicsType="line")
        else:
            self.sampleFrameChanged = Signal(
                "RLiSetupMapPanel.sampleFrameChanged")
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
                graphicsType="rectangle")

        self._registeredGraphics.AddPen(
            "rlisetup", wx.Pen(wx.GREEN, width=2, style=wx.SOLID))
        self._registeredGraphics.AddItem(coords=[[0, 0], [0, 0]],
                                         penName="rlisetup",
                                         hide=True)

        if self.samplingtype != SamplingType.VECT:
            self.toolbar.SelectDefault()
Exemple #37
0
class GConsoleWindow(wx.SplitterWindow):
    """Create and manage output console for commands run by GUI.
    """
    def __init__(self,
                 parent,
                 gconsole,
                 menuModel=None,
                 margin=False,
                 style=wx.TAB_TRAVERSAL | wx.FULL_REPAINT_ON_RESIZE,
                 gcstyle=GC_EMPTY,
                 **kwargs):
        """
        :param parent: gui parent
        :param gconsole: console logic
        :param menuModel: tree model of modules (from menu)
        :param margin: use margin in output pane (GStc)
        :param style: wx.SplitterWindow style
        :param gcstyle: GConsole style
                        (GC_EMPTY, GC_PROMPT to show command prompt,
                        GC_SEARCH to show search widget)
        """
        wx.SplitterWindow.__init__(self,
                                   parent,
                                   id=wx.ID_ANY,
                                   style=style,
                                   **kwargs)
        self.SetName("GConsole")

        self.panelOutput = wx.Panel(parent=self, id=wx.ID_ANY)
        self.panelProgress = wx.Panel(parent=self.panelOutput,
                                      id=wx.ID_ANY,
                                      name='progressPanel')
        self.panelPrompt = wx.Panel(parent=self, id=wx.ID_ANY)
        # initialize variables
        self.parent = parent  # GMFrame | CmdPanel | ?
        self._gconsole = gconsole
        self._menuModel = menuModel

        self._gcstyle = gcstyle
        self.lineWidth = 80

        # signal which requests showing of a notification
        self.showNotification = Signal("GConsoleWindow.showNotification")
        # signal emitted when text appears in the console
        # parameter 'notification' suggests form of notification (according to
        # core.giface.Notification)
        self.contentChanged = Signal("GConsoleWindow.contentChanged")

        # progress bar
        self.progressbar = wx.Gauge(parent=self.panelProgress,
                                    id=wx.ID_ANY,
                                    range=100,
                                    pos=(110, 50),
                                    size=(-1, 25),
                                    style=wx.GA_HORIZONTAL)
        self._gconsole.Bind(EVT_CMD_PROGRESS, self.OnCmdProgress)
        self._gconsole.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)
        self._gconsole.Bind(EVT_CMD_RUN, self.OnCmdRun)
        self._gconsole.Bind(EVT_CMD_DONE, self.OnCmdDone)

        self._gconsole.writeLog.connect(self.WriteLog)
        self._gconsole.writeCmdLog.connect(self.WriteCmdLog)
        self._gconsole.writeWarning.connect(self.WriteWarning)
        self._gconsole.writeError.connect(self.WriteError)

        # text control for command output
        self.cmdOutput = GStc(parent=self.panelOutput,
                              id=wx.ID_ANY,
                              margin=margin,
                              wrap=None)

        # search & command prompt
        # move to the if below
        # search depends on cmd prompt
        self.cmdPrompt = GPromptSTC(parent=self, menuModel=self._menuModel)
        self.cmdPrompt.promptRunCmd.connect(
            lambda cmd: self._gconsole.RunCmd(command=cmd))
        self.cmdPrompt.showNotification.connect(self.showNotification)

        if not self._gcstyle & GC_PROMPT:
            self.cmdPrompt.Hide()

        if self._gcstyle & GC_SEARCH:
            self.infoCollapseLabelExp = _(
                "Click here to show search module engine")
            self.infoCollapseLabelCol = _(
                "Click here to hide search module engine")
            self.searchPane = wx.CollapsiblePane(
                parent=self.panelOutput,
                label=self.infoCollapseLabelExp,
                style=wx.CP_DEFAULT_STYLE | wx.CP_NO_TLW_RESIZE | wx.EXPAND)
            self.MakeSearchPaneContent(self.searchPane.GetPane(),
                                       self._menuModel)
            self.searchPane.Collapse(True)
            self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnSearchPaneChanged,
                      self.searchPane)
            self.search.moduleSelected.connect(
                lambda name: self.cmdPrompt.SetTextAndFocus(name + ' '))
        else:
            self.search = None

        if self._gcstyle & GC_PROMPT:
            cmdLabel = _("Command prompt")
            self.outputBox = wx.StaticBox(parent=self.panelOutput,
                                          id=wx.ID_ANY,
                                          label=" %s " % _("Output window"))

            self.cmdBox = wx.StaticBox(parent=self.panelOutput,
                                       id=wx.ID_ANY,
                                       label=" %s " % cmdLabel)

        # buttons
        self.btnOutputClear = wx.Button(parent=self.panelOutput,
                                        id=wx.ID_CLEAR)
        self.btnOutputClear.SetToolTipString(_("Clear output window content"))
        self.btnCmdClear = wx.Button(parent=self.panelOutput, id=wx.ID_CLEAR)
        self.btnCmdClear.SetToolTipString(_("Clear command prompt content"))
        self.btnOutputSave = wx.Button(parent=self.panelOutput, id=wx.ID_SAVE)
        self.btnOutputSave.SetToolTipString(
            _("Save output window content to the file"))
        self.btnCmdAbort = wx.Button(parent=self.panelProgress, id=wx.ID_STOP)
        self.btnCmdAbort.SetToolTipString(_("Abort running command"))
        self.btnCmdProtocol = wx.ToggleButton(parent=self.panelOutput,
                                              id=wx.ID_ANY,
                                              label=_("&Log file"),
                                              size=self.btnCmdClear.GetSize())
        self.btnCmdProtocol.SetToolTipString(
            _("Toggle to save list of executed commands into "
              "a file; content saved when switching off."))

        if not self._gcstyle & GC_PROMPT:
            self.btnCmdClear.Hide()
            self.btnCmdProtocol.Hide()

        self.btnCmdClear.Bind(wx.EVT_BUTTON, self.cmdPrompt.OnCmdErase)
        self.btnOutputClear.Bind(wx.EVT_BUTTON, self.OnOutputClear)
        self.btnOutputSave.Bind(wx.EVT_BUTTON, self.OnOutputSave)
        self.btnCmdAbort.Bind(wx.EVT_BUTTON, self._gconsole.OnCmdAbort)
        self.btnCmdProtocol.Bind(wx.EVT_TOGGLEBUTTON, self.OnCmdProtocol)

        self._layout()

    def _layout(self):
        """Do layout"""
        self.outputSizer = wx.BoxSizer(wx.VERTICAL)
        progressSizer = wx.BoxSizer(wx.HORIZONTAL)
        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        if self._gcstyle & GC_PROMPT:
            outBtnSizer = wx.StaticBoxSizer(self.outputBox, wx.HORIZONTAL)
            cmdBtnSizer = wx.StaticBoxSizer(self.cmdBox, wx.HORIZONTAL)
        else:
            outBtnSizer = wx.BoxSizer(wx.HORIZONTAL)
            cmdBtnSizer = wx.BoxSizer(wx.HORIZONTAL)

        if self._gcstyle & GC_PROMPT:
            promptSizer = wx.BoxSizer(wx.VERTICAL)
            promptSizer.Add(item=self.cmdPrompt,
                            proportion=1,
                            flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP,
                            border=3)
            helpText = wx.StaticText(
                self.panelPrompt,
                id=wx.ID_ANY,
                label=
                "Press Tab to display command help, Ctrl+Space to autocomplete"
            )
            helpText.SetForegroundColour(
                wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT))
            promptSizer.Add(item=helpText,
                            proportion=0,
                            flag=wx.EXPAND | wx.LEFT,
                            border=5)

        if self._gcstyle & GC_SEARCH:
            self.outputSizer.Add(item=self.searchPane,
                                 proportion=0,
                                 flag=wx.EXPAND | wx.ALL,
                                 border=3)
        self.outputSizer.Add(item=self.cmdOutput,
                             proportion=1,
                             flag=wx.EXPAND | wx.ALL,
                             border=3)
        if self._gcstyle & GC_PROMPT:
            proportion = 1
        else:
            proportion = 0
            outBtnSizer.AddStretchSpacer()

        outBtnSizer.Add(item=self.btnOutputClear,
                        proportion=proportion,
                        flag=wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT,
                        border=5)

        outBtnSizer.Add(item=self.btnOutputSave,
                        proportion=proportion,
                        flag=wx.ALIGN_RIGHT | wx.RIGHT,
                        border=5)

        cmdBtnSizer.Add(item=self.btnCmdProtocol,
                        proportion=1,
                        flag=wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL
                        | wx.LEFT | wx.RIGHT,
                        border=5)
        cmdBtnSizer.Add(item=self.btnCmdClear,
                        proportion=1,
                        flag=wx.ALIGN_CENTER | wx.RIGHT,
                        border=5)
        progressSizer.Add(item=self.btnCmdAbort,
                          proportion=0,
                          flag=wx.ALL | wx.ALIGN_CENTER,
                          border=5)
        progressSizer.Add(item=self.progressbar,
                          proportion=1,
                          flag=wx.ALIGN_CENTER | wx.RIGHT | wx.TOP | wx.BOTTOM,
                          border=5)

        self.panelProgress.SetSizer(progressSizer)
        progressSizer.Fit(self.panelProgress)

        btnSizer.Add(item=outBtnSizer,
                     proportion=1,
                     flag=wx.ALL | wx.ALIGN_CENTER,
                     border=5)
        btnSizer.Add(item=cmdBtnSizer,
                     proportion=1,
                     flag=wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM | wx.RIGHT,
                     border=5)
        self.outputSizer.Add(item=self.panelProgress,
                             proportion=0,
                             flag=wx.EXPAND)
        self.outputSizer.Add(item=btnSizer, proportion=0, flag=wx.EXPAND)

        self.outputSizer.Fit(self)
        self.outputSizer.SetSizeHints(self)
        self.panelOutput.SetSizer(self.outputSizer)
        # eliminate gtk_widget_size_allocate() warnings
        # avoid to use a deprecated method in wxPython >= 2.9
        getattr(self.outputSizer, 'FitInside',
                self.outputSizer.SetVirtualSizeHints)(self.panelOutput)

        if self._gcstyle & GC_PROMPT:
            promptSizer.Fit(self)
            promptSizer.SetSizeHints(self)
            self.panelPrompt.SetSizer(promptSizer)

        # split window
        if self._gcstyle & GC_PROMPT:
            self.SplitHorizontally(self.panelOutput, self.panelPrompt, -50)
        else:
            self.SplitHorizontally(self.panelOutput, self.panelPrompt, -45)
            self.Unsplit()
        self.SetMinimumPaneSize(self.btnCmdClear.GetSize()[1] + 25)

        self.SetSashGravity(1.0)

        self.outputSizer.Hide(self.panelProgress)
        # layout
        self.SetAutoLayout(True)
        self.Layout()

    def MakeSearchPaneContent(self, pane, model):
        """Create search pane"""
        border = wx.BoxSizer(wx.VERTICAL)

        self.search = SearchModuleWidget(parent=pane, model=model)

        self.search.showNotification.connect(self.showNotification)

        border.Add(item=self.search,
                   proportion=0,
                   flag=wx.EXPAND | wx.ALL,
                   border=1)

        pane.SetSizer(border)
        border.Fit(pane)

    def OnSearchPaneChanged(self, event):
        """Collapse search module box"""
        if self.searchPane.IsExpanded():
            self.searchPane.SetLabel(self.infoCollapseLabelCol)
        else:
            self.searchPane.SetLabel(self.infoCollapseLabelExp)

        self.panelOutput.Layout()
        self.panelOutput.SendSizeEvent()

    def GetPanel(self, prompt=True):
        """Get panel

        :param prompt: get prompt / output panel

        :return: wx.Panel reference
        """
        if prompt:
            return self.panelPrompt

        return self.panelOutput

    def WriteLog(self,
                 text,
                 style=None,
                 wrap=None,
                 notification=Notification.HIGHLIGHT):
        """Generic method for writing log message in 
        given style. 

        Emits contentChanged signal.

        :param line: text line
        :param style: text style (see GStc)
        :param stdout: write to stdout or stderr
        :param notification: form of notification
        """

        self.cmdOutput.SetStyle()

        # documenting old behavior/implementation:
        # switch notebook if required
        # now, let user to bind to the old event

        if not style:
            style = self.cmdOutput.StyleDefault

        # p1 = self.cmdOutput.GetCurrentPos()
        p1 = self.cmdOutput.GetEndStyled()
        # self.cmdOutput.GotoPos(p1)
        self.cmdOutput.DocumentEnd()

        for line in text.splitlines():
            # fill space
            if len(line) < self.lineWidth:
                diff = self.lineWidth - len(line)
                line += diff * ' '

            self.cmdOutput.AddTextWrapped(line, wrap=wrap)  # adds '\n'

            p2 = self.cmdOutput.GetCurrentPos()

            self.cmdOutput.StartStyling(p1, 0xff)
            self.cmdOutput.SetStyling(p2 - p1, style)

        self.cmdOutput.EnsureCaretVisible()

        self.contentChanged.emit(notification=notification)

    def WriteCmdLog(self,
                    text,
                    pid=None,
                    notification=Notification.MAKE_VISIBLE):
        """Write message in selected style
        
        :param text: message to be printed
        :param pid: process pid or None
        :param switchPage: True to switch page
        """
        if pid:
            text = '(' + str(pid) + ') ' + text
        self.WriteLog(text,
                      style=self.cmdOutput.StyleCommand,
                      notification=notification)

    def WriteWarning(self, text):
        """Write message in warning style"""
        self.WriteLog(text,
                      style=self.cmdOutput.StyleWarning,
                      notification=Notification.MAKE_VISIBLE)

    def WriteError(self, text):
        """Write message in error style"""
        self.WriteLog(text,
                      style=self.cmdOutput.StyleError,
                      notification=Notification.MAKE_VISIBLE)

    def OnOutputClear(self, event):
        """Clear content of output window"""
        self.cmdOutput.SetReadOnly(False)
        self.cmdOutput.ClearAll()
        self.cmdOutput.SetReadOnly(True)
        self.progressbar.SetValue(0)

    def GetProgressBar(self):
        """Return progress bar widget"""
        return self.progressbar

    def OnOutputSave(self, event):
        """Save (selected) text from output window to the file"""
        text = self.cmdOutput.GetSelectedText()
        if not text:
            text = self.cmdOutput.GetText()

        # add newline if needed
        if len(text) > 0 and text[-1] != '\n':
            text += '\n'

        dlg = wx.FileDialog(
            self,
            message=_("Save file as..."),
            defaultFile="grass_cmd_output.txt",
            wildcard=_("%(txt)s (*.txt)|*.txt|%(files)s (*)|*") % {
                'txt': _("Text files"),
                'files': _("Files")
            },
            style=wx.SAVE | wx.FD_OVERWRITE_PROMPT)

        # Show the dialog and retrieve the user response. If it is the OK response,
        # process the data.
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()

            try:
                output = open(path, "w")
                output.write(text)
            except IOError as e:
                GError(
                    _("Unable to write file '%(path)s'.\n\nDetails: %(error)s")
                    % {
                        'path': path,
                        'error': e
                    })
            finally:
                output.close()
            message = _("Command output saved into '%s'") % path
            self.showNotification.emit(message=message)

        dlg.Destroy()

    def SetCopyingOfSelectedText(self, copy):
        """Enable or disable copying of selected text in to clipboard.
        Effects prompt and output.
        
        :param bool copy: True for enable, False for disable
        """
        if copy:
            self.cmdPrompt.Bind(stc.EVT_STC_PAINTED,
                                self.cmdPrompt.OnTextSelectionChanged)
            self.cmdOutput.Bind(stc.EVT_STC_PAINTED,
                                self.cmdOutput.OnTextSelectionChanged)
        else:
            self.cmdPrompt.Unbind(stc.EVT_STC_PAINTED)
            self.cmdOutput.Unbind(stc.EVT_STC_PAINTED)

    def OnCmdOutput(self, event):
        """Prints command output.

        Emits contentChanged signal.
        """
        message = event.text
        type = event.type

        self.cmdOutput.AddStyledMessage(message, type)

        if event.type in ('warning', 'error'):
            self.contentChanged.emit(notification=Notification.MAKE_VISIBLE)
        else:
            self.contentChanged.emit(notification=Notification.HIGHLIGHT)

    def OnCmdProgress(self, event):
        """Update progress message info"""
        self.progressbar.SetValue(event.value)
        event.Skip()

    def CmdProtocolSave(self):
        """Save list of manually entered commands into a text log file"""
        if not hasattr(self, 'cmdFileProtocol'):
            return  # it should not happen

        try:
            output = open(self.cmdFileProtocol, "a")
            cmds = self.cmdPrompt.GetCommands()
            output.write('\n'.join(cmds))
            if len(cmds) > 0:
                output.write('\n')
        except IOError as e:
            GError(
                _("Unable to write file '%(filePath)s'.\n\nDetails: %(error)s")
                % {
                    'filePath': self.cmdFileProtocol,
                    'error': e
                })
        finally:
            output.close()

        message = _("Command log saved to '%s'") % self.cmdFileProtocol
        self.showNotification.emit(message=message)
        del self.cmdFileProtocol

    def OnCmdProtocol(self, event=None):
        """Save commands into file"""
        if not event.IsChecked():
            # stop capturing commands, save list of commands to the
            # protocol file
            self.CmdProtocolSave()
        else:
            # start capturing commands
            self.cmdPrompt.ClearCommands()
            # ask for the file
            dlg = wx.FileDialog(
                self,
                message=_("Save file as..."),
                defaultFile="grass_cmd_log.txt",
                wildcard=_("%(txt)s (*.txt)|*.txt|%(files)s (*)|*") % {
                    'txt': _("Text files"),
                    'files': _("Files")
                },
                style=wx.SAVE)
            if dlg.ShowModal() == wx.ID_OK:
                self.cmdFileProtocol = dlg.GetPath()
            else:
                wx.CallAfter(self.btnCmdProtocol.SetValue, False)

            dlg.Destroy()

        event.Skip()

    def OnCmdRun(self, event):
        """Run command"""
        self.outputSizer.Show(self.panelProgress)
        self.outputSizer.Layout()
        event.Skip()

    def OnCmdDone(self, event):
        """Command done (or aborted)
        """
        self.progressbar.SetValue(0)  # reset progress bar on '0%'
        wx.CallLater(100, self._hideProgress)
        event.Skip()

    def _hideProgress(self):
        self.outputSizer.Hide(self.panelProgress)
        self.outputSizer.Layout()

    def ResetFocus(self):
        """Reset focus"""
        self.cmdPrompt.SetFocus()

    def GetPrompt(self):
        """Get prompt"""
        return self.cmdPrompt
Exemple #38
0
class VectorSelectBase():
    """@brief Main class of vector selection function

    It allows selecting vector features from map display and to export
    them as a new vector map. Current version allows selecting
    features one-by-one by single click in map display.

    This class can be initialized with (see CreateDialog()) or without
    (see gselect) dialog (see VectorSelectDialog).
    """
    def __init__(self, parent, giface):
        self.parent = parent
        self._giface = giface
        self.register = False
        self.mapWin = self._giface.GetMapWindow()
        self.mapDisp = giface.GetMapDisplay()
        self.RegisterMapEvtHandler()

        self.selectedFeatures = []
        self.mapName = None  # chosen map for selecting features

        self._dialog = None
        self.onCloseDialog = None

        self.updateLayer = Signal('VectorSelectBase.updateLayer')

        self.painter = VectorSelectHighlighter(self.mapDisp, giface)

    def CreateDialog(self, createButton=True):
        """Create dialog

        :param createButton: True to add 'create new map' button
        """
        if self._dialog:
            return

        self._dialog = VectorSelectDialog(parent=self.parent)
        self._dialog.Bind(wx.EVT_CLOSE, self.OnCloseDialog)
        if createButton:
            createMap = Button(self._dialog, wx.ID_ANY, _("Create a new map"))
            createMap.Bind(wx.EVT_BUTTON, self.OnExportMap)
            self._dialog.AddWidget(createMap, proportion=0.1)
        self.slist = VectorSelectList(self._dialog)
        self.slist.Bind(wx.EVT_LIST_KEY_DOWN, self.OnDelete)
        self.slist.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.OnDeleteRow)
        self._dialog.AddWidget(self.slist)

        self.onCloseDialog = Signal('VectorSelectBase.onCloseDialog')

    def OnDeleteRow(self, event=None):
        """Delete row in widget
        """
        index = self.slist.GetFocusedItem()
        category = self.slist.GetItemText(index)
        for item in self.selectedFeatures:
            if int(item['Category']) == int(category):
                self.selectedFeatures.remove(item)
                break
        self.slist.DeleteItem(index)
        self._draw()

    def OnDelete(self, event):
        """Delete row in widget by press key(delete)
        """
        keycode = event.GetKeyCode()
        if keycode == wx.WXK_DELETE:
            self.OnDeleteRow()

    def RegisterMapEvtHandler(self):
        if not self.register:
            self.mapWin.RegisterMouseEventHandler(wx.EVT_LEFT_DOWN,
                                                  self._onMapClickHandler,
                                                  'cross')
        self.register = True

    def UnregisterMapEvtHandler(self):
        """Unregistrates _onMapClickHandler from mapWin"""
        if self.register:
            self.mapWin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN,
                                                    self._onMapClickHandler)
        self.register = False

    def OnClose(self):
        self.selectedFeatures = []
        self._draw()
        self.UnregisterMapEvtHandler()

    def OnCloseDialog(self, evt=None):
        if not self.onCloseDialog:
            return

        self.onCloseDialog.emit()
        self.selectedFeatures = []
        self.painter.Clear()
        self._dialog.Destroy()
        self.UnregisterMapEvtHandler()

    def Reset(self):
        """Remove items from dialog list"""
        self.selectedFeatures = []
        if self._dialog:
            self.slist.DeleteAllItems()
            self._dialog.Raise()
        self.RegisterMapEvtHandler()

    def _onMapClickHandler(self, event):
        """Registred handler for clicking on grass disp
        """
        if event == "unregistered":
            return
        vWhatDic = self.QuerySelectedMap()
        if 'Category' in vWhatDic:
            self.AddVecInfo(vWhatDic)
            self._draw()
            if self._dialog:
                self._dialog.Raise()

    def AddVecInfo(self, vInfoDictTMP):
        """Update vector in list

        Note: click on features add category
              second click on the same vector remove category from list
        """
        if len(self.selectedFeatures) > 0:
            for sel in self.selectedFeatures:
                if sel['Category'] == vInfoDictTMP[
                        'Category']:  # features is selected=> remove features
                    self.selectedFeatures.remove(sel)
                    if self._dialog:  # if dialog initilized->update dialog
                        self.slist.RemoveItem(vInfoDictTMP)
                    return True

            self.selectedFeatures.append(vInfoDictTMP)
            if self._dialog:
                self.slist.AddItem(vInfoDictTMP)
        else:  # only one is selected
            self.selectedFeatures.append(vInfoDictTMP)
            if self._dialog:
                self.slist.AddItem(vInfoDictTMP)

        if len(self.selectedFeatures) == 0:
            return False

        return True

    def _draw(self):
        """Call class 'VectorSelectHighlighter' to draw selected features"""
        self.updateLayer.emit()
        if len(self.selectedFeatures) > 0:
            self.painter.SetLayer(self.selectedFeatures[0]['Layer'])
            self.painter.SetMap(self.selectedFeatures[0]['Map'] + '@' +
                                self.selectedFeatures[0]['Mapset'])
            tmp = list()
            for i in self.selectedFeatures:
                tmp.append(i['Category'])

            self.painter.SetCats(tmp)
            self.painter.DrawSelected()
        else:
            self.painter.Clear()

    def GetSelectedMap(self):
        """Return name of selected map in layer tree"""
        layerList = self._giface.GetLayerList()
        layerSelected = layerList.GetSelectedLayer()
        if layerSelected is None:
            return None

        if not layerSelected.maplayer.IsActive():
            GWarning(_("Selected map <%s> has been disabled for rendering. "
                       "Operation canceled.") % str(layerSelected),
                     parent=self.mapWin)
            return None

        if layerSelected:
            mapName = str(layerSelected)
            if self.mapName is not None:
                if self.mapName != mapName:
                    self.Reset()
        else:
            mapName = None
            self.UnregisterMapEvtHandler()
            GError(_("No map layer selected. Operation canceled."))
        return mapName

    def QuerySelectedMap(self):
        """Return w.what info from last clicked coords on display

        """
        self.mapName = self.GetSelectedMap()
        if not self.mapName:
            return {}

        mapInfo = self.mapWin.GetMap()
        threshold = 10.0 * (
            (mapInfo.region['e'] - mapInfo.region['w']) / mapInfo.width)
        try:
            query = grass.vector_what(map=[self.mapName],
                                      coord=self.mapWin.GetLastEN(),
                                      distance=threshold,
                                      skip_attributes=True)
        except grass.ScriptError:
            GError(parent=self,
                   message=_("Failed to query vector map(s) <%s>.") % self.map)
            return None

        return query[0]

    def GetLineStringSelectedCats(self):
        """Return line of categories separated by comma"""
        strTMP = ''
        for cat in self.selectedFeatures:
            strTMP += str(cat['Category']) + ','
        return strTMP[:-1]

    def _id_generator(self,
                      size=6,
                      chars=string.ascii_uppercase + string.digits):
        return ''.join(random.choice(chars) for _ in range(size))

    def OnExportMap(self, event):
        """Export selected features to a new map

        Add new map layer to layer tree and checked it

        @todo: set color of map to higlight color
        """

        if len(self.selectedFeatures) == 0:
            GMessage(_('No features selected'))
            return
        lst = ''
        for cat in self.selectedFeatures:  # build text string of categories for v.extract input
            lst += str(cat['Category']) + ','
        lst = lst[:-1]
        outMap = str(self.selectedFeatures[0]['Map']) + '_selection' + str(
            self._id_generator(3))
        ret, err = RunCommand('v.extract',
                              input=self.selectedFeatures[0]['Map'],
                              layer=self.selectedFeatures[0]['Layer'],
                              output=outMap,
                              cats=lst,
                              getErrorMsg=True)
        if ret == 0:
            tree = self._giface.GetLayerTree()
            if tree:
                tree.AddLayer(ltype='vector',
                              lname=outMap,
                              lcmd=['d.vect', 'map=%s' % outMap],
                              lchecked=True)

                # TODO colorize new map
                self.Reset()
            else:
                GMessage(_('Vector map <%s> was created') % outMap)
                self.Reset()
        else:
            GError(_("Unable to create a new vector map.\n\nReason: %s") % err)

    """
Exemple #39
0
    def __init__(self,
                 parent,
                 gconsole,
                 menuModel=None,
                 margin=False,
                 style=wx.TAB_TRAVERSAL | wx.FULL_REPAINT_ON_RESIZE,
                 gcstyle=GC_EMPTY,
                 **kwargs):
        """
        :param parent: gui parent
        :param gconsole: console logic
        :param menuModel: tree model of modules (from menu)
        :param margin: use margin in output pane (GStc)
        :param style: wx.SplitterWindow style
        :param gcstyle: GConsole style
                        (GC_EMPTY, GC_PROMPT to show command prompt,
                        GC_SEARCH to show search widget)
        """
        wx.SplitterWindow.__init__(self,
                                   parent,
                                   id=wx.ID_ANY,
                                   style=style,
                                   **kwargs)
        self.SetName("GConsole")

        self.panelOutput = wx.Panel(parent=self, id=wx.ID_ANY)
        self.panelProgress = wx.Panel(parent=self.panelOutput,
                                      id=wx.ID_ANY,
                                      name='progressPanel')
        self.panelPrompt = wx.Panel(parent=self, id=wx.ID_ANY)
        # initialize variables
        self.parent = parent  # GMFrame | CmdPanel | ?
        self._gconsole = gconsole
        self._menuModel = menuModel

        self._gcstyle = gcstyle
        self.lineWidth = 80

        # signal which requests showing of a notification
        self.showNotification = Signal("GConsoleWindow.showNotification")
        # signal emitted when text appears in the console
        # parameter 'notification' suggests form of notification (according to
        # core.giface.Notification)
        self.contentChanged = Signal("GConsoleWindow.contentChanged")

        # progress bar
        self.progressbar = wx.Gauge(parent=self.panelProgress,
                                    id=wx.ID_ANY,
                                    range=100,
                                    pos=(110, 50),
                                    size=(-1, 25),
                                    style=wx.GA_HORIZONTAL)
        self._gconsole.Bind(EVT_CMD_PROGRESS, self.OnCmdProgress)
        self._gconsole.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)
        self._gconsole.Bind(EVT_CMD_RUN, self.OnCmdRun)
        self._gconsole.Bind(EVT_CMD_DONE, self.OnCmdDone)

        self._gconsole.writeLog.connect(self.WriteLog)
        self._gconsole.writeCmdLog.connect(self.WriteCmdLog)
        self._gconsole.writeWarning.connect(self.WriteWarning)
        self._gconsole.writeError.connect(self.WriteError)

        # text control for command output
        self.cmdOutput = GStc(parent=self.panelOutput,
                              id=wx.ID_ANY,
                              margin=margin,
                              wrap=None)

        # search & command prompt
        # move to the if below
        # search depends on cmd prompt
        self.cmdPrompt = GPromptSTC(parent=self, menuModel=self._menuModel)
        self.cmdPrompt.promptRunCmd.connect(
            lambda cmd: self._gconsole.RunCmd(command=cmd))
        self.cmdPrompt.showNotification.connect(self.showNotification)

        if not self._gcstyle & GC_PROMPT:
            self.cmdPrompt.Hide()

        if self._gcstyle & GC_SEARCH:
            self.infoCollapseLabelExp = _(
                "Click here to show search module engine")
            self.infoCollapseLabelCol = _(
                "Click here to hide search module engine")
            self.searchPane = wx.CollapsiblePane(
                parent=self.panelOutput,
                label=self.infoCollapseLabelExp,
                style=wx.CP_DEFAULT_STYLE | wx.CP_NO_TLW_RESIZE | wx.EXPAND)
            self.MakeSearchPaneContent(self.searchPane.GetPane(),
                                       self._menuModel)
            self.searchPane.Collapse(True)
            self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnSearchPaneChanged,
                      self.searchPane)
            self.search.moduleSelected.connect(
                lambda name: self.cmdPrompt.SetTextAndFocus(name + ' '))
        else:
            self.search = None

        if self._gcstyle & GC_PROMPT:
            cmdLabel = _("Command prompt")
            self.outputBox = wx.StaticBox(parent=self.panelOutput,
                                          id=wx.ID_ANY,
                                          label=" %s " % _("Output window"))

            self.cmdBox = wx.StaticBox(parent=self.panelOutput,
                                       id=wx.ID_ANY,
                                       label=" %s " % cmdLabel)

        # buttons
        self.btnOutputClear = wx.Button(parent=self.panelOutput,
                                        id=wx.ID_CLEAR)
        self.btnOutputClear.SetToolTipString(_("Clear output window content"))
        self.btnCmdClear = wx.Button(parent=self.panelOutput, id=wx.ID_CLEAR)
        self.btnCmdClear.SetToolTipString(_("Clear command prompt content"))
        self.btnOutputSave = wx.Button(parent=self.panelOutput, id=wx.ID_SAVE)
        self.btnOutputSave.SetToolTipString(
            _("Save output window content to the file"))
        self.btnCmdAbort = wx.Button(parent=self.panelProgress, id=wx.ID_STOP)
        self.btnCmdAbort.SetToolTipString(_("Abort running command"))
        self.btnCmdProtocol = wx.ToggleButton(parent=self.panelOutput,
                                              id=wx.ID_ANY,
                                              label=_("&Log file"),
                                              size=self.btnCmdClear.GetSize())
        self.btnCmdProtocol.SetToolTipString(
            _("Toggle to save list of executed commands into "
              "a file; content saved when switching off."))

        if not self._gcstyle & GC_PROMPT:
            self.btnCmdClear.Hide()
            self.btnCmdProtocol.Hide()

        self.btnCmdClear.Bind(wx.EVT_BUTTON, self.cmdPrompt.OnCmdErase)
        self.btnOutputClear.Bind(wx.EVT_BUTTON, self.OnOutputClear)
        self.btnOutputSave.Bind(wx.EVT_BUTTON, self.OnOutputSave)
        self.btnCmdAbort.Bind(wx.EVT_BUTTON, self._gconsole.OnCmdAbort)
        self.btnCmdProtocol.Bind(wx.EVT_TOGGLEBUTTON, self.OnCmdProtocol)

        self._layout()
Exemple #40
0
    def __init__(self, parent, toolSwitcher, MapWindow, digitClass, giface,
                 tools=[]):
        self.MapWindow = MapWindow
        self.Map = MapWindow.GetMap()  # Map class instance
        self.tools = tools
        self.digitClass = digitClass
        BaseToolbar.__init__(self, parent, toolSwitcher)
        self.digit = None
        self._giface = giface
        self.fType = None     # feature type for simple features editing

        self.editingStarted = Signal("VDigitToolbar.editingStarted")
        self.editingStopped = Signal("VDigitToolbar.editingStopped")
        self.editingBgMap = Signal("VDigitToolbar.editingBgMap")
        layerTree = self._giface.GetLayerTree()
        if layerTree:
            self.editingStarted.connect(layerTree.StartEditing)
            self.editingStopped.connect(layerTree.StopEditing)
            self.editingBgMap.connect(layerTree.SetBgMapForEditing)

        # currently selected map layer for editing (reference to MapLayer
        # instance)
        self.mapLayer = None
        # list of vector layers from Layer Manager (only in the current mapset)
        self.layers = []

        self.comboid = self.combo = None
        self.undo = -1
        self.redo = -1

        # only one dialog can be open
        self.settingsDialog = None

        # create toolbars (two rows optionally)
        self.InitToolbar(self._toolbarData())

        self._default = -1
        # default action (digitize new point, line, etc.)
        self.action = {'desc': '',
                       'type': '',
                       'id': -1}
        self._currentAreaActionType = None

        # list of available vector maps
        self.UpdateListOfLayers(updateTool=True)

        for tool in (
                'addPoint', 'addLine', 'addBoundary', 'addCentroid', 'addArea',
                'addVertex', 'deleteLine', 'deleteArea', 'displayAttr',
                'displayCats', 'editLine', 'moveLine', 'moveVertex',
                'removeVertex', 'additionalTools'):
            if hasattr(self, tool):
                tool = getattr(self, tool)
                self.toolSwitcher.AddToolToGroup(
                    group='mouseUse', toolbar=self, tool=tool)
            else:
                Debug.msg(1, '%s skipped' % tool)

        # custom button for digitization of area/boundary/centroid
        # TODO: could this be somehow generalized?
        nAreaTools = 0
        if self.tools and 'addBoundary' in self.tools:
            nAreaTools += 1
        if self.tools and 'addCentroid' in self.tools:
            nAreaTools += 1
        if self.tools and 'addArea' in self.tools:
            nAreaTools += 1
        if nAreaTools != 1:
            self.areaButton = self.CreateSelectionButton(
                _("Select area/boundary/centroid tool"))
            self.areaButtonId = self.InsertControl(5, self.areaButton)
            self.areaButton.Bind(wx.EVT_BUTTON, self.OnAddAreaMenu)

        # realize toolbar
        self.Realize()
        # workaround for Mac bug. May be fixed by 2.8.8, but not before then.
        if self.combo:
            self.combo.Hide()
            self.combo.Show()

        # disable undo/redo
        if self.undo > 0:
            self.EnableTool(self.undo, False)
        if self.redo > 0:
            self.EnableTool(self.redo, False)

        self.FixSize(width=105)
Exemple #41
0
class VDigitWindow(BufferedMapWindow):
    """A Buffered window extended for vector digitizer.
    """

    def __init__(self, parent, giface, Map, properties, tree=None,
                 id=wx.ID_ANY, lmgr=None,
                 style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
        BufferedMapWindow.__init__(self, parent=parent, giface=giface, Map=Map,
                                   properties=properties,
                                   style=style, **kwargs)
        self.lmgr = lmgr
        self.tree = tree
        self.pdcVector = PseudoDC()
        self.toolbar = self.parent.GetToolbar('vdigit')
        self.digit = None  # wxvdigit.IVDigit
        self._digitizingInfo = False  # digitizing with info

        # Emitted when info about digitizing updated
        # Parameter text is a string with information
        # currently used only for coordinates of mouse cursor + segmnt and
        # total feature length
        self.digitizingInfo = Signal('VDigitWindow.digitizingInfo')
        # Emitted when some info about digitizing is or will be availbale
        self.digitizingInfoAvailable = Signal('VDigitWindow.digitizingInfo')
        # Emitted when some info about digitizing is or will be availbale
        # digitizingInfo signal is emmited only between digitizingInfoAvailable
        # and digitizingInfoUnavailable signals
        self.digitizingInfoUnavailable = Signal('VDigitWindow.digitizingInfo')

        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        self.mouseMoving.connect(self._mouseMovingToDigitizingInfo)

    def GetDisplay(self):
        if self.digit:
            return self.digit.GetDisplay()
        return None

    def GetDigit(self):
        """Get digit class"""
        return self.digit

    def SetToolbar(self, toolbar):
        """Set up related toolbar
        """
        self.toolbar = toolbar

    def _mouseMovingToDigitizingInfo(self, x, y):
        e, n = x, y
        precision = int(UserSettings.Get(group='projection', key='format',
                                         subkey='precision'))
        if self.toolbar.GetAction() != 'addLine' or \
                self.toolbar.GetAction('type') not in ('line', 'boundary') or \
                len(self.polycoords) == 0:
            # we cannot provide info, so find out if it is something new
            if self._digitizingInfo:
                self._digitizingInfo = False
                self.digitizingInfoUnavailable.emit()
            return
        # else, we can provide info, so find out if it is first time
        if not self._digitizingInfo:
            self._digitizingInfo = True
            self.digitizingInfoAvailable.emit()

        # for linear feature show segment and total length
        distance_seg = self.Distance(self.polycoords[-1],
                                     (e, n), screen=False)[0]
        distance_tot = distance_seg
        for idx in range(1, len(self.polycoords)):
            distance_tot += self.Distance(self.polycoords[idx - 1],
                                          self.polycoords[idx],
                                          screen=False)[0]
        text = "seg: %.*f; tot: %.*f" % (precision, distance_seg,
                                         precision, distance_tot)
        self.digitizingInfo.emit(text=text)

    def OnKeyDown(self, event):
        """Key pressed"""
        shift = event.ShiftDown()
        kc = event.GetKeyCode()

        event = None
        if not shift:
            if kc == ord('P'):
                event = wx.CommandEvent(winid=self.toolbar.addPoint)
                tool = self.toolbar.OnAddPoint
            elif kc == ord('L'):
                event = wx.CommandEvent(winid=self.toolbar.addLine)
                tool = self.toolbar.OnAddLine
        if event:
            self.toolbar.OnTool(event)
            tool(event)

    def _updateMap(self):
        if not self.toolbar or \
                not self.toolbar.GetLayer():
            return

        # set region
        self.digit.GetDisplay().UpdateRegion()
        # re-calculate threshold for digitization tool
        # self.parent.digit.GetDisplay().GetThreshold()
        # draw map
        # self.pdcVector.Clear()
        self.pdcVector.RemoveAll()

        item = None
        if self.tree:
            try:
                item = self.tree.FindItemByData(
                    'maplayer', self.toolbar.GetLayer())
            except TypeError:
                pass

        if not self.tree or \
                (self.tree and item and
                 self.tree.IsItemChecked(item)):
            self.redrawAll = True
            self.digit.GetDisplay().DrawMap()

        # translate tmp objects (pointer position)
        if self.toolbar.GetAction() == 'moveLine' and \
                hasattr(self, "moveInfo"):
            if 'beginDiff' in self.moveInfo:
                # move line
                for id in self.moveInfo['id']:
                    self.pdcTmp.TranslateId(id,
                                            self.moveInfo['beginDiff'][0],
                                            self.moveInfo['beginDiff'][1])
                del self.moveInfo['beginDiff']

    def OnLeftDownAddLine(self, event):
        """Left mouse button pressed - add new feature
        """
        try:
            mapLayer = self.toolbar.GetLayer().GetName()
        except:
            return

        if self.toolbar.GetAction('type') in ['point', 'centroid']:
            # add new point / centroiud
            east, north = self.Pixel2Cell(self.mouse['begin'])
            nfeat, fids = self.digit.AddFeature(
                self.toolbar.GetAction('type'),
                [(east, north)])
            if nfeat < 1:
                return

            self.UpdateMap(render=False)  # redraw map

            # add new record into atribute table
            if UserSettings.Get(
                    group='vdigit', key="addRecord", subkey='enabled'):
                # select attributes based on layer and category
                cats = {
                    fids[0]: {
                        UserSettings.Get(
                            group='vdigit',
                            key="layer",
                            subkey='value'): (
                            UserSettings.Get(
                                group='vdigit',
                                key="category",
                                subkey='value'),
                        )}}

                posWindow = self.ClientToScreen(
                    (self.mouse['end'][0] + self.dialogOffset,
                     self.mouse['end'][1] + self.dialogOffset))

                addRecordDlg = DisplayAttributesDialog(
                    parent=self, map=mapLayer, cats=cats, pos=posWindow,
                    action="add", ignoreError=True)

                if self.toolbar.GetAction('type') == 'centroid':
                    for fid in fids:
                        self._geomAttrb(fid, addRecordDlg, 'area')
                        self._geomAttrb(fid, addRecordDlg, 'perimeter')

                if addRecordDlg.IsFound():
                    addRecordDlg.ShowModal()
                addRecordDlg.Destroy()

        elif self.toolbar.GetAction('type') in ["line", "boundary", "area"]:
            # add new point to the line
            self.polycoords.append(
                self.Pixel2Cell(
                    event.GetPosition()))
            self.DrawLines(pdc=self.pdcTmp)

    def _geomAttrb(self, fid, dialog, attrb):
        """Define geometry attributes
        """
        mapLayer = self.toolbar.GetLayer()
        if self.tree:
            item = self.tree.FindItemByData('maplayer', mapLayer)
            vdigit = self.tree.GetLayerInfo(item, key='vdigit')
        else:
            item = vdigit = None

        if not vdigit or \
                'geomAttr' not in vdigit or \
                attrb not in vdigit['geomAttr']:
            return

        val = -1
        if attrb == 'length':
            val = self.digit.GetLineLength(fid)
            type = attrb
        elif attrb == 'area':
            val = self.digit.GetAreaSize(fid)
            type = attrb
        elif attrb == 'perimeter':
            val = self.digit.GetAreaPerimeter(fid)
            type = 'length'

        if val > 0:
            layer = int(
                UserSettings.Get(
                    group='vdigit',
                    key="layer",
                    subkey='value'))
            column = vdigit['geomAttr'][attrb]['column']
            val = UnitsConvertValue(
                val, type, vdigit['geomAttr'][attrb]['units'])
            dialog.SetColumnValue(layer, column, val)
            dialog.OnReset()

    def _geomAttrbUpdate(self, fids):
        """Update geometry atrributes of currently selected features

        :param fid: list feature id
        """
        mapLayer = self.parent.toolbars['vdigit'].GetLayer()
        vectorName = mapLayer.GetName()
        if self.tree:
            item = self.tree.FindItemByData('maplayer', mapLayer)
            vdigit = self.tree.GetLayerInfo(item, key='vdigit')
        else:
            item = vdigit = None

        if not vdigit or 'geomAttr' not in vdigit:
            return

        dbInfo = gselect.VectorDBInfo(vectorName)
        sqlfile = tempfile.NamedTemporaryFile(mode="w")
        for fid in fids:
            for layer, cats in six.iteritems(self.digit.GetLineCats(fid)):
                table = dbInfo.GetTable(layer)
                for attrb, item in six.iteritems(vdigit['geomAttr']):
                    val = -1
                    if attrb == 'length':
                        val = self.digit.GetLineLength(fid)
                        type = attrb
                    elif attrb == 'area':
                        val = self.digit.GetAreaSize(fid)
                        type = attrb
                    elif attrb == 'perimeter':
                        val = self.digit.GetAreaPerimeter(fid)
                        type = 'length'

                    if val < 0:
                        continue
                    val = UnitsConvertValue(val, type, item['units'])

                    for cat in cats:
                        sqlfile.write(
                            'UPDATE %s SET %s = %f WHERE %s = %d;\n' %
                            (table, item['column'], val, dbInfo.GetKeyColumn(layer), cat))

            sqlfile.file.flush()
            RunCommand('db.execute',
                       parent=True,
                       quiet=True,
                       input=sqlfile.name)

    def _updateATM(self):
        """Update open Attribute Table Manager

        .. todo::
            use AddDataRow() instead
        """
        if not self.lmgr:
            return

        # update ATM
        digitVector = self.toolbar.GetLayer().GetName()

        for atm in self.lmgr.dialogs['atm']:
            atmVector = atm.GetVectorName()
            if atmVector == digitVector:
                layer = UserSettings.Get(
                    group='vdigit', key="layer", subkey='value')
                # TODO: use AddDataRow instead
                atm.LoadData(layer)

    def OnLeftDownEditLine(self, event):
        """Left mouse button pressed - edit linear feature - add new
        vertex.
        """
        self.polycoords.append(self.Pixel2Cell(self.mouse['begin']))
        self.moveInfo['id'].append(wx.NewId())
        self.DrawLines(pdc=self.pdcTmp)

    def OnLeftDownMoveLine(self, event):
        """Left mouse button pressed - vector digitizer move
        feature/vertex, edit linear feature
        """
        self.moveInfo = dict()
        # geographic coordinates of initial position (left-down)
        self.moveInfo['begin'] = None
        # list of ids to modify
        self.moveInfo['id'] = list()

        # set pen
        if self.toolbar.GetAction() in ["moveVertex", "editLine"]:
            pcolor = UserSettings.Get(group='vdigit', key="symbol",
                                      subkey=["highlight", "color"])
            self.pen = self.polypen = wx.Pen(colour=pcolor,
                                             width=2, style=wx.SHORT_DASH)
            self.pdcTmp.SetPen(self.polypen)

    def OnLeftDownDisplayCA(self, event):
        """Left mouse button pressed - vector digitizer display categories
        or attributes action
        """
        try:
            mapLayer = self.toolbar.GetLayer().GetName()
        except:
            return

        coords = self.Pixel2Cell(self.mouse['begin'])

        # unselect
        self.digit.GetDisplay().SetSelected([])

        # select feature by point
        cats = {}
        self.digit.GetDisplay().SelectLineByPoint(coords)

        if not self.digit.GetDisplay().GetSelected():
            for key in ('attributes', 'category'):
                if self.parent.dialogs[key] and \
                        self.parent.dialogs[key].IsShown():
                    self.parent.dialogs[key].Hide()
            self.UpdateMap(render=False, renderVector=True)
            return

        if UserSettings.Get(group='vdigit', key='checkForDupl',
                            subkey='enabled'):
            lines = self.digit.GetDisplay().GetSelected()
        else:
            lines = (
                self.digit.GetDisplay().GetSelected()[0],
            )  # only first found

        for line in lines:
            cats[line] = self.digit.GetLineCats(line)

        posWindow = self.ClientToScreen(
            (self.mouse['end'][0] + self.dialogOffset,
             self.mouse['end'][1] + self.dialogOffset))

        if self.toolbar.GetAction() == "displayAttrs":
            # select attributes based on coordinates (all layers)
            if self.parent.dialogs['attributes'] is None:
                self.parent.dialogs['attributes'] = \
                    DisplayAttributesDialog(parent=self, map=mapLayer,
                                            cats=cats,
                                            action="update")
            else:
                # upgrade dialog
                self.parent.dialogs['attributes'].UpdateDialog(cats=cats)

            if self.parent.dialogs['attributes'] and \
                    self.parent.dialogs['attributes'].mapDBInfo:
                if len(cats.keys()) > 0:
                    # highlight feature & re-draw map
                    if not self.parent.dialogs['attributes'].IsShown():
                        self.parent.dialogs['attributes'].Show()
                else:
                    if self.parent.dialogs['attributes'] and \
                            self.parent.dialogs['attributes'].IsShown():
                        self.parent.dialogs['attributes'].Hide()

        else:  # displayCats
            if self.parent.dialogs['category'] is None:
                # open new dialog
                dlg = VDigitCategoryDialog(parent=self,
                                           vectorName=mapLayer,
                                           cats=cats,
                                           pos=posWindow,
                                           title=_("Update categories"))
                self.parent.dialogs['category'] = dlg
            else:
                # update currently open dialog
                self.parent.dialogs['category'].UpdateDialog(cats=cats)

            if self.parent.dialogs['category']:
                if len(cats.keys()) > 0:
                    # highlight feature & re-draw map
                    if not self.parent.dialogs['category'].IsShown():
                        self.parent.dialogs['category'].Show()
                else:
                    if self.parent.dialogs['category'].IsShown():
                        self.parent.dialogs['category'].Hide()

        self.UpdateMap(render=False, renderVector=True)

    def OnLeftDownCopyCA(self, event):
        """Left mouse button pressed - vector digitizer copy
        categories or attributes action
        """
        if not hasattr(self, "copyCatsList"):
            self.copyCatsList = []
        else:
            self.copyCatsIds = []
            self.mouse['box'] = 'box'

    def OnLeftDownCopyLine(self, event):
        """Left mouse button pressed - vector digitizer copy lines
        action
        """
        if not hasattr(self, "copyIds"):
            self.copyIds = []
            self.layerTmp = None

    def OnLeftDownBulkLine(self, event):
        """Left mouse button pressed - vector digitizer label 3D
        vector lines
        """
        if len(self.polycoords) > 1:  # start new line
            self.polycoords = []
            self.ClearLines(pdc=self.pdcTmp)
        self.polycoords.append(self.Pixel2Cell(event.GetPosition()))
        if len(self.polycoords) == 1:
            begin = self.Pixel2Cell(self.polycoords[-1])
            end = self.Pixel2Cell(self.mouse['end'])
        else:
            end = self.Pixel2Cell(self.polycoords[-1])
            begin = self.Pixel2Cell(self.mouse['begin'])

            self.DrawLines(self.pdcTmp, polycoords=(begin, end))

    def OnLeftDownUndo(self, event):
        """Left mouse button pressed with control key - vector
        digitizer undo functionality
        """
        if self.mouse["use"] != "pointer" or not self.toolbar:
            return

        action = self.toolbar.GetAction()
        if (action == "addLine" and self.toolbar.GetAction('type')
                in ["line", "boundary", "area"]) or action == "editLine":
            # add line or boundary -> remove last point from the line
            try:
                removed = self.polycoords.pop()
                Debug.msg(
                    4, "VDigitWindow.OnMiddleDown(): polycoords_poped=%s" %
                    [removed, ])
                # self.mouse['begin'] = self.Cell2Pixel(self.polycoords[-1])
            except:
                pass

        if action == "editLine":
            # remove last vertex & line
            if len(self.moveInfo['id']) > 1:
                self.moveInfo['id'].pop()

            self.UpdateMap(render=False, renderVector=False)

        elif action in ["deleteLine", "deleteArea", "moveLine", "splitLine",
                        "addVertex", "removeVertex", "moveVertex",
                        "copyCats", "flipLine", "mergeLine",
                        "snapLine", "connectLine", "copyLine",
                        "queryLine", "breakLine", "typeConv"]:
            # various tools -> unselected selected features
            self.digit.GetDisplay().SetSelected([])

            if action in ["moveLine", "moveVertex", "editLine"] and \
                    hasattr(self, "moveInfo"):
                del self.moveInfo

            elif action == "copyCats":
                try:
                    del self.copyCatsList
                    del self.copyCatsIds
                except AttributeError:
                    pass

            elif action == "copyLine":
                del self.copyIds
                if self.layerTmp:
                    self.Map.DeleteLayer(self.layerTmp)
                    self.UpdateMap(render=True, renderVector=False)
                del self.layerTmp

            self.polycoords = []
            self.UpdateMap(render=False)  # render vector

        elif action == "zbulkLine":
            # reset polyline
            self.polycoords = []
            self.digit.GetDisplay().SetSelected([])
            self.UpdateMap(render=False)

        self.redrawAll = True
        self.UpdateMap(render=False, renderVector=False)

    def _onLeftDown(self, event):
        """Left mouse button donw - vector digitizer various actions
        """
        try:
            mapLayer = self.toolbar.GetLayer().GetName()
        except:
            GMessage(parent=self,
                     message=_("No vector map selected for editing."))
            event.Skip()
            return

        action = self.toolbar.GetAction()

        if not action:
            GMessage(
                parent=self, message=_(
                    "Nothing to do. "
                    "Choose appropriate tool from digitizer toolbar."))
            event.Skip()
            return

        if action not in ("moveVertex",
                          "addVertex",
                          "removeVertex",
                          "editLine"):
            # set pen
            self.pen = wx.Pen(
                colour=UserSettings.Get(
                    group='vdigit',
                    key='symbol',
                    subkey=[
                        'newSegment',
                        'color']),
                width=2,
                style=wx.SHORT_DASH)
            self.polypen = wx.Pen(
                colour=UserSettings.Get(
                    group='vdigit',
                    key='symbol',
                    subkey=[
                        'newLine',
                        'color']),
                width=2,
                style=wx.SOLID)

        if action in ("addVertex",
                      "removeVertex",
                      "splitLines"):
            # unselect
            self.digit.GetDisplay().SetSelected([])

        if action == "addLine":
            self.OnLeftDownAddLine(event)

        elif action == "editLine" and \
                hasattr(self, "moveInfo"):
            self.OnLeftDownEditLine(event)

        elif action in ("moveLine", "moveVertex", "editLine") and \
                not hasattr(self, "moveInfo"):
            self.OnLeftDownMoveLine(event)

        elif action in ("displayAttrs"
                        "displayCats"):
            self.OnLeftDownDisplayCA(event)

        elif action in ("copyCats",
                        "copyAttrs"):
            self.OnLeftDownCopyCA(event)

        elif action == "copyLine":
            self.OnLeftDownCopyLine(event)

        elif action == "zbulkLine":
            self.OnLeftDownBulkLine(event)

    def OnLeftUpVarious(self, event):
        """Left mouse button released - vector digitizer various
        actions
        """
        pos1 = self.Pixel2Cell(self.mouse['begin'])
        pos2 = self.Pixel2Cell(self.mouse['end'])

        nselected = 0
        action = self.toolbar.GetAction()
        # -> delete line || move line || move vertex
        if action in ("moveVertex",
                      "editLine"):
            if len(self.digit.GetDisplay().GetSelected()) == 0:
                nselected = int(
                    self.digit.GetDisplay().SelectLineByPoint(pos1)['line'] != -1)

                if action == "editLine":
                    try:
                        selVertex = self.digit.GetDisplay(
                        ).GetSelectedVertex(pos1)[0]
                    except IndexError:
                        selVertex = None

                    if selVertex:
                        # self.UpdateMap(render=False)
                        ids = self.digit.GetDisplay().GetSelected(grassId=False)
                        # move this line to tmp layer
                        self.polycoords = []
                        for id in ids:
                            if id % 2:  # register only vertices
                                e, n = self.Pixel2Cell(
                                    self.pdcVector.GetIdBounds(id)[0:2])
                                self.polycoords.append((e, n))
                        self.digit.GetDisplay().DrawSelected(False)

                        if selVertex < ids[-1] / 2:
                            # choose first or last node of line
                            self.moveInfo['id'].reverse()
                            self.polycoords.reverse()
                    else:
                        # unselect
                        self.digit.GetDisplay().SetSelected([])
                        del self.moveInfo

                    self.UpdateMap(render=False)

        elif action in ("copyCats",
                        "copyAttrs"):
            if not hasattr(self, "copyCatsIds"):
                # 'from' -> select by point
                nselected = int(
                    self.digit.GetDisplay().SelectLineByPoint(pos1)['line'] != -1)
                if nselected:
                    self.copyCatsList = self.digit.GetDisplay().GetSelected()
            else:
                # -> 'to' -> select by bbox
                self.digit.GetDisplay().SetSelected([])
                # return number of selected features (by box/point)
                nselected = self.digit.GetDisplay().SelectLinesByBox((pos1, pos2))
                if nselected == 0:
                    nselected = int(
                        self.digit.GetDisplay().SelectLineByPoint(pos1)['line'] != -1)

                if nselected > 0:
                    self.copyCatsIds = self.digit.GetDisplay().GetSelected()

        elif action == "queryLine":
            selected = self.digit.SelectLinesByQuery(bbox=(pos1, pos2))
            nselected = len(selected)
            if nselected > 0:
                self.digit.GetDisplay().SetSelected(selected)

        else:
            # -> moveLine || deleteLine, etc. (select by point/box)
            if action == 'moveLine' and \
                    len(self.digit.GetDisplay().GetSelected()) > 0:
                nselected = 0
            else:
                if action == 'deleteArea':
                    nselected = int(
                        self.digit.GetDisplay().SelectAreaByPoint(pos1)['area'] != -1)
                else:
                    if action == 'moveLine':
                        drawSeg = True
                    else:
                        drawSeg = False

                    nselected = self.digit.GetDisplay().SelectLinesByBox(
                        bbox=(pos1, pos2), drawSeg=drawSeg)
                    if nselected == 0:
                        nselected = int(
                            self.digit.GetDisplay().SelectLineByPoint(pos1)['line'] != -1)

        if nselected > 0:
            if action in ("moveLine", "moveVertex") and \
                    hasattr(self, "moveInfo"):
                # get pseudoDC id of objects which should be redrawn
                if action == "moveLine":
                    # -> move line
                    self.moveInfo['id'] = self.digit.GetDisplay(
                    ).GetSelected(grassId=False)
                else:  # moveVertex
                    self.moveInfo['id'] = self.digit.GetDisplay(
                    ).GetSelectedVertex(pos1)
                    if len(self.moveInfo['id']) == 0:  # no vertex found
                        self.digit.GetDisplay().SetSelected([])

            #
            # check for duplicates
            #
            if UserSettings.Get(
                    group='vdigit', key='checkForDupl', subkey='enabled'):
                dupl = self.digit.GetDisplay().GetDuplicates()
                self.UpdateMap(render=False)

                if dupl:
                    posWindow = self.ClientToScreen(
                        (self.mouse['end'][0] + self.dialogOffset,
                         self.mouse['end'][1] + self.dialogOffset))

                    dlg = VDigitDuplicatesDialog(
                        parent=self, data=dupl, pos=posWindow)

                    if dlg.ShowModal() == wx.ID_OK:
                        self.digit.GetDisplay().UnSelect(dlg.GetUnSelected())
                        # update selected
                        self.UpdateMap(render=False)

            if action != "editLine":
                # -> move line || move vertex
                self.UpdateMap(render=False)

        else:  # no vector object found
            if not (action in ("moveLine",
                               "moveVertex") and
                    hasattr(self, "moveInfo") and
                    len(self.moveInfo['id']) > 0):
                # avoid left-click when features are already selected
                self.UpdateMap(render=False, renderVector=False)

    def OnLeftUpModifyLine(self, event):
        """Left mouse button released - vector digitizer split line,
        add/remove vertex action
        """
        pos1 = self.Pixel2Cell(self.mouse['begin'])

        pointOnLine = self.digit.GetDisplay().SelectLineByPoint(pos1)['point']
        if not pointOnLine:
            return

        if self.toolbar.GetAction() in ["splitLine", "addVertex"]:
            self.UpdateMap(render=False)  # highlight object
            self.DrawCross(
                pdc=self.pdcTmp, coords=self.Cell2Pixel(
                    (pointOnLine[0], pointOnLine[1])), size=5)
        else:  # removeVertex
            # get only id of vertex
            try:
                id = self.digit.GetDisplay().GetSelectedVertex(pos1)[0]
            except IndexError:
                id = None

            if id:
                x, y = self.pdcVector.GetIdBounds(id)[0:2]
                self.pdcVector.RemoveId(id)
                self.UpdateMap(render=False)  # highlight object
                self.DrawCross(pdc=self.pdcTmp, coords=(x, y),
                               size=5)
            else:
                # unselect
                self.digit.GetDisplay().SetSelected([])
                self.UpdateMap(render=False)

    def OnLeftUpCopyLine(self, event):
        """Left mouse button released - vector digitizer copy feature
        action
        """
        pos1 = self.Pixel2Cell(self.mouse['begin'])
        pos2 = self.Pixel2Cell(self.mouse['end'])

        if UserSettings.Get(group='vdigit', key='bgmap',
                            subkey='value', settings_type='internal') == '':
            # no background map -> copy from current vector map layer
            nselected = self.digit.GetDisplay().SelectLinesByBox((pos1, pos2))

            if nselected > 0:
                # highlight selected features
                self.UpdateMap(render=False)
            else:
                self.UpdateMap(render=False, renderVector=False)
        else:
            # copy features from background map
            self.copyIds = self.digit.SelectLinesFromBackgroundMap(
                bbox=(pos1,
                      pos2))
            if len(self.copyIds) > 0:
                color = UserSettings.Get(group='vdigit', key='symbol',
                                         subkey=['highlight', 'color'])
                colorStr = str(color[0]) + ":" + str(color[1]
                                                     ) + ":" + str(color[2])
                dVectTmp = [
                    'd.vect',
                    'map=%s' %
                    UserSettings.Get(
                        group='vdigit',
                        key='bgmap',
                        subkey='value',
                        settings_type='internal'),
                    'cats=%s' %
                    ListOfCatsToRange(
                        self.copyIds),
                    '-i',
                    'color=%s' %
                    colorStr,
                    'fill_color=%s' %
                    colorStr,
                    'type=point,line,boundary,centroid',
                    'width=2']

                if not self.layerTmp:
                    self.layerTmp = self.Map.AddLayer(ltype='vector',
                                                      name=QUERYLAYER,
                                                      command=dVectTmp)
                else:
                    self.layerTmp.SetCmd(dVectTmp)
            else:
                if self.layerTmp:
                    self.Map.DeleteLayer(self.layerTmp)
                    self.layerTmp = None

            self.UpdateMap(render=True, renderVector=True)

    def OnLeftUpBulkLine(self, event):
        """Left mouse button released - vector digitizer z-bulk line
        action
        """
        # select lines to be labeled
        pos1 = self.polycoords[0]
        pos2 = self.polycoords[1]
        nselected = self.digit.GetDisplay().SelectLinesByBox((pos1, pos2))

        if nselected > 0:
            # highlight selected features
            self.UpdateMap(render=False)
            self.DrawLines(pdc=self.pdcTmp)  # redraw temp line
        else:
            self.UpdateMap(render=False, renderVector=False)

    def OnLeftUpConnectLine(self, event):
        """Left mouse button released - vector digitizer connect line
        action
        """
        if len(self.digit.GetDisplay().GetSelected()) > 0:
            self.UpdateMap(render=False)

    def _onLeftUp(self, event):
        """Left mouse button released"""
        if event.ControlDown():
            return

        if hasattr(self, "moveInfo"):
            if len(self.digit.GetDisplay().GetSelected()) == 0:
                self.moveInfo['begin'] = self.Pixel2Cell(
                    self.mouse['begin'])  # left down

            # eliminate initial mouse moving efect
            self.mouse['begin'] = self.mouse['end']

        action = self.toolbar.GetAction()
        if action in ("deleteLine",
                      "deleteArea",
                      "moveLine",
                      "moveVertex",
                      "copyCats",
                      "copyAttrs",
                      "editLine",
                      "flipLine",
                      "mergeLine",
                      "snapLine",
                      "queryLine",
                      "breakLine",
                      "typeConv",
                      "connectLine"):
            self.OnLeftUpVarious(event)

        elif action in ("splitLine",
                        "addVertex",
                        "removeVertex"):
            self.OnLeftUpModifyLine(event)

        elif action == "copyLine":
            self.OnLeftUpCopyLine(event)

        elif action == "zbulkLine" and \
                len(self.polycoords) == 2:
            self.OnLeftUpBulkLine(event)

        elif action == "connectLine":
            self.OnLeftUpConnectLine(event)

        if len(self.digit.GetDisplay().GetSelected()) > 0:
            self.redrawAll = None

    def _onRightDown(self, event):
        # digitization tool (confirm action)
        action = self.toolbar.GetAction()
        if action in ("moveLine", "moveVertex") and \
                hasattr(self, "moveInfo"):
            pFrom = self.moveInfo['begin']
            pTo = self.Pixel2Cell(event.GetPosition())

            move = (pTo[0] - pFrom[0],
                    pTo[1] - pFrom[1])

            if action == "moveLine":
                # move line
                if self.digit.MoveSelectedLines(move) < 0:
                    return
            elif action == "moveVertex":
                # move vertex
                fid = self.digit.MoveSelectedVertex(pFrom, move)
                if fid < 0:
                    return

                self._geomAttrbUpdate([fid, ])

            del self.moveInfo

    def _onRightUp(self, event):
        """Right mouse button released (confirm action)
        """
        action = self.toolbar.GetAction()
        if action == "addLine" and \
                self.toolbar.GetAction('type') in ["line", "boundary", "area"]:
            # -> add new line / boundary
            try:
                mapName = self.toolbar.GetLayer().GetName()
            except:
                mapName = None
                GError(parent=self,
                       message=_("No vector map selected for editing."))

            if mapName:
                if self.toolbar.GetAction('type') == 'line':
                    line = True
                else:
                    line = False

                if len(self.polycoords) < 2:  # ignore 'one-point' lines
                    return

                nfeat, fids = self.digit.AddFeature(
                    self.toolbar.GetAction('type'), self.polycoords)
                if nfeat < 0:
                    return

                position = self.Cell2Pixel(self.polycoords[-1])
                self.polycoords = []
                self.UpdateMap(render=False)
                self.redrawAll = True
                self.Refresh()

                # add new record into atribute table
                if self._addRecord() and (line is True or (not line and nfeat > 0)):
                    posWindow = self.ClientToScreen(
                        (position[0] + self.dialogOffset, position[1] + self.dialogOffset))

                    # select attributes based on layer and category
                    cats = {
                        fids[0]: {
                            UserSettings.Get(
                                group='vdigit',
                                key="layer",
                                subkey='value'): (
                                UserSettings.Get(
                                    group='vdigit',
                                    key="category",
                                    subkey='value'),
                            )}}

                    addRecordDlg = DisplayAttributesDialog(
                        parent=self, map=mapName, cats=cats, pos=posWindow,
                        action="add", ignoreError=True)

                    for fid in fids:
                        self._geomAttrb(fid, addRecordDlg, 'length')
                        # auto-placing centroid
                        self._geomAttrb(fid, addRecordDlg, 'area')
                        self._geomAttrb(fid, addRecordDlg, 'perimeter')

                    if addRecordDlg.IsFound():
                        addRecordDlg.ShowModal()
                    addRecordDlg.Destroy()

        elif action == "deleteLine":
            # -> delete selected vector features
            if self.digit.DeleteSelectedLines() < 0:
                return
            self._updateATM()
        elif action == "deleteArea":
            # -> delete selected vector areas
            if self.digit.DeleteSelectedAreas() < 0:
                return
            self._updateATM()
        elif action == "splitLine":
            # split line
            if self.digit.SplitLine(self.Pixel2Cell(self.mouse['begin'])) < 0:
                return
        elif action == "addVertex":
            # add vertex
            fid = self.digit.AddVertex(self.Pixel2Cell(self.mouse['begin']))
            if fid < 0:
                return
        elif action == "removeVertex":
            # remove vertex
            fid = self.digit.RemoveVertex(self.Pixel2Cell(self.mouse['begin']))
            if fid < 0:
                return
            self._geomAttrbUpdate([fid, ])
        elif action in ("copyCats", "copyAttrs"):
            if action == 'copyCats':
                if self.digit.CopyCats(self.copyCatsList,
                                       self.copyCatsIds, copyAttrb=False) < 0:
                    return
            else:
                if self.digit.CopyCats(self.copyCatsList,
                                       self.copyCatsIds, copyAttrb=True) < 0:
                    return

            del self.copyCatsList
            del self.copyCatsIds

            self._updateATM()

        elif action == "editLine" and \
                hasattr(self, "moveInfo"):
            line = self.digit.GetDisplay().GetSelected()[0]
            if self.digit.EditLine(line, self.polycoords) < 0:
                return

            del self.moveInfo

        elif action == "flipLine":
            if self.digit.FlipLine() < 0:
                return
        elif action == "mergeLine":
            if self.digit.MergeLine() < 0:
                return
        elif action == "breakLine":
            if self.digit.BreakLine() < 0:
                return
        elif action == "snapLine":
            if self.digit.SnapLine() < 0:
                return
        elif action == "connectLine":
            if len(self.digit.GetDisplay().GetSelected()) > 1:
                if self.digit.ConnectLine() < 0:
                    return
        elif action == "copyLine":
            if self.digit.CopyLine(self.copyIds) < 0:
                return
            del self.copyIds
            if self.layerTmp:
                self.Map.DeleteLayer(self.layerTmp)
                self.UpdateMap(render=True, renderVector=False)
            del self.layerTmp

        elif action == "zbulkLine" and len(self.polycoords) == 2:
            pos1 = self.polycoords[0]
            pos2 = self.polycoords[1]

            selected = self.digit.GetDisplay().GetSelected()
            dlg = VDigitZBulkDialog(
                parent=self,
                title=_("Z bulk-labeling dialog"),
                nselected=len(selected))
            if dlg.ShowModal() == wx.ID_OK:
                if self.digit.ZBulkLines(pos1, pos2, dlg.value.GetValue(),
                                         dlg.step.GetValue()) < 0:
                    return
            self.UpdateMap(render=False)
        elif action == "typeConv":
            # -> feature type conversion
            # - point <-> centroid
            # - line <-> boundary
            if self.digit.TypeConvForSelectedLines() < 0:
                return

        if action != "addLine":
            # unselect and re-render
            self.digit.GetDisplay().SetSelected([])
            self.polycoords = []
            self.UpdateMap(render=False)

    def _onMouseMoving(self, event):
        self.mouse['end'] = event.GetPosition()

        Debug.msg(5, "VDigitWindow.OnMouseMoving(): coords=%f,%f" %
                  (self.mouse['end'][0], self.mouse['end'][1]))

        action = self.toolbar.GetAction()
        if action == "addLine" and \
                self.toolbar.GetAction('type') in ["line", "boundary", "area"]:
            if len(self.polycoords) > 0:
                self.MouseDraw(pdc=self.pdcTmp,
                               begin=self.Cell2Pixel(self.polycoords[-1]))

        elif action in ["moveLine", "moveVertex", "editLine"] \
                and hasattr(self, "moveInfo"):
            dx = self.mouse['end'][0] - self.mouse['begin'][0]
            dy = self.mouse['end'][1] - self.mouse['begin'][1]

            # draw lines on new position
            if action == "moveLine" and \
                    len(self.moveInfo['id']) > 0:
                # move line
                for id in self.moveInfo['id']:
                    self.pdcTmp.TranslateId(id, dx, dy)
            elif action in ["moveVertex", "editLine"]:
                # move vertex ->
                # (vertex, left vertex, left line,
                # right vertex, right line)

                # do not draw static lines
                if action == "moveVertex" and \
                        len(self.moveInfo['id']) > 0:
                    self.polycoords = []
                    self.pdcTmp.RemoveId(self.moveInfo['id'][0])
                    if self.moveInfo['id'][1] > 0:  # previous vertex
                        x, y = self.Pixel2Cell(
                            self.pdcTmp.GetIdBounds(
                                self.moveInfo['id'][1])[
                                0:2])
                        self.pdcTmp.RemoveId(self.moveInfo['id'][1] + 1)
                        self.polycoords.append((x, y))
                    self.polycoords.append(self.Pixel2Cell(self.mouse['end']))

                    if self.moveInfo['id'][2] > 0:  # next vertex
                        x, y = self.Pixel2Cell(
                            self.pdcTmp.GetIdBounds(
                                self.moveInfo['id'][2])[
                                0:2])
                        self.pdcTmp.RemoveId(self.moveInfo['id'][2] - 1)
                        self.polycoords.append((x, y))

                    self.ClearLines(pdc=self.pdcTmp)
                    self.DrawLines(pdc=self.pdcTmp)

                if action == "editLine":
                    self.MouseDraw(pdc=self.pdcTmp,
                                   begin=self.Cell2Pixel(self.polycoords[-1]))

            self.Refresh()  # TODO: use RefreshRect()
            self.mouse['begin'] = self.mouse['end']

        elif action == "zbulkLine":
            if len(self.polycoords) == 1:
                # draw mouse moving
                self.MouseDraw(self.pdcTmp)

    def _zoom(self, event):
        tmp1 = self.mouse['end']
        tmp2 = self.Cell2Pixel(self.moveInfo['begin'])
        dx = tmp1[0] - tmp2[0]
        dy = tmp1[1] - tmp2[1]
        self.moveInfo['beginDiff'] = (dx, dy)
        for id in self.moveInfo['id']:
            self.pdcTmp.RemoveId(id)

    def _addRecord(self):
        return UserSettings.Get(
            group='vdigit', key="addRecord", subkey='enabled')
Exemple #42
0
class VDigitToolbar(BaseToolbar):
    """Toolbar for digitization
    """

    def __init__(self, parent, toolSwitcher, MapWindow, digitClass, giface,
                 tools=[]):
        self.MapWindow = MapWindow
        self.Map = MapWindow.GetMap()  # Map class instance
        self.tools = tools
        self.digitClass = digitClass
        BaseToolbar.__init__(self, parent, toolSwitcher)
        self.digit = None
        self._giface = giface
        self.fType = None     # feature type for simple features editing

        self.editingStarted = Signal("VDigitToolbar.editingStarted")
        self.editingStopped = Signal("VDigitToolbar.editingStopped")
        self.editingBgMap = Signal("VDigitToolbar.editingBgMap")
        layerTree = self._giface.GetLayerTree()
        if layerTree:
            self.editingStarted.connect(layerTree.StartEditing)
            self.editingStopped.connect(layerTree.StopEditing)
            self.editingBgMap.connect(layerTree.SetBgMapForEditing)

        # currently selected map layer for editing (reference to MapLayer
        # instance)
        self.mapLayer = None
        # list of vector layers from Layer Manager (only in the current mapset)
        self.layers = []

        self.comboid = self.combo = None
        self.undo = -1
        self.redo = -1

        # only one dialog can be open
        self.settingsDialog = None

        # create toolbars (two rows optionally)
        self.InitToolbar(self._toolbarData())

        self._default = -1
        # default action (digitize new point, line, etc.)
        self.action = {'desc': '',
                       'type': '',
                       'id': -1}
        self._currentAreaActionType = None

        # list of available vector maps
        self.UpdateListOfLayers(updateTool=True)

        for tool in (
                'addPoint', 'addLine', 'addBoundary', 'addCentroid', 'addArea',
                'addVertex', 'deleteLine', 'deleteArea', 'displayAttr',
                'displayCats', 'editLine', 'moveLine', 'moveVertex',
                'removeVertex', 'additionalTools'):
            if hasattr(self, tool):
                tool = getattr(self, tool)
                self.toolSwitcher.AddToolToGroup(
                    group='mouseUse', toolbar=self, tool=tool)
            else:
                Debug.msg(1, '%s skipped' % tool)

        # custom button for digitization of area/boundary/centroid
        # TODO: could this be somehow generalized?
        nAreaTools = 0
        if self.tools and 'addBoundary' in self.tools:
            nAreaTools += 1
        if self.tools and 'addCentroid' in self.tools:
            nAreaTools += 1
        if self.tools and 'addArea' in self.tools:
            nAreaTools += 1
        if nAreaTools != 1:
            self.areaButton = self.CreateSelectionButton(
                _("Select area/boundary/centroid tool"))
            self.areaButtonId = self.InsertControl(5, self.areaButton)
            self.areaButton.Bind(wx.EVT_BUTTON, self.OnAddAreaMenu)

        # realize toolbar
        self.Realize()
        # workaround for Mac bug. May be fixed by 2.8.8, but not before then.
        if self.combo:
            self.combo.Hide()
            self.combo.Show()

        # disable undo/redo
        if self.undo > 0:
            self.EnableTool(self.undo, False)
        if self.redo > 0:
            self.EnableTool(self.redo, False)

        self.FixSize(width=105)

    def _toolbarData(self):
        """Toolbar data
        """
        data = []

        self.icons = {
            'addPoint': MetaIcon(img='point-create',
                                 label=_('Digitize new point'),
                                 desc=_('Left: new point')),
            'addLine': MetaIcon(img='line-create',
                                label=_('Digitize new line'),
                                desc=_('Left: new point; Ctrl+Left: undo last point; Right: close line')),
            'addBoundary': MetaIcon(img='boundary-create',
                                    label=_('Digitize new boundary'),
                                    desc=_('Left: new point; Ctrl+Left: undo last point; Right: close line')),
            'addCentroid': MetaIcon(img='centroid-create',
                                    label=_('Digitize new centroid'),
                                    desc=_('Left: new point')),
            'addArea': MetaIcon(img='polygon-create',
                                label=_('Digitize new area (boundary without category)'),
                                desc=_('Left: new point')),
            'addVertex': MetaIcon(img='vertex-create',
                                  label=_('Add new vertex to line or boundary'),
                                  desc=_('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
            'deleteLine': MetaIcon(img='line-delete',
                                   label=_('Delete selected point(s), line(s), boundary(ies) or centroid(s)'),
                                   desc=_('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
            'deleteArea': MetaIcon(img='polygon-delete',
                                   label=_('Delete selected area(s)'),
                                   desc=_('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
            'displayAttr': MetaIcon(img='attributes-display',
                                    label=_('Display/update attributes'),
                                    desc=_('Left: Select')),
            'displayCats': MetaIcon(img='cats-display',
                                    label=_('Display/update categories'),
                                    desc=_('Left: Select')),
            'editLine': MetaIcon(img='line-edit',
                                 label=_('Edit selected line/boundary'),
                                 desc=_('Left: new point; Ctrl+Left: undo last point; Right: close line')),
            'moveLine': MetaIcon(img='line-move',
                                 label=_('Move selected point(s), line(s), boundary(ies) or centroid(s)'),
                                 desc=_('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
            'moveVertex': MetaIcon(img='vertex-move',
                                   label=_('Move selected vertex'),
                                   desc=_('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
            'removeVertex': MetaIcon(img='vertex-delete',
                                     label=_('Remove selected vertex'),
                                     desc=_('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
            'settings': BaseIcons['settings'].SetLabel(_('Digitization settings')),
            'quit': BaseIcons['quit'].SetLabel(label=_('Quit digitizer'),
                                               desc=_('Quit digitizer and save changes')),
            'help': BaseIcons['help'].SetLabel(label=_('Vector Digitizer manual'),
                                               desc=_('Show Vector Digitizer manual')),
            'additionalTools': MetaIcon(img='tools',
                                        label=_('Additional tools '
                                                '(copy, flip, connect, etc.)'),
                                        desc=_('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
            'undo': MetaIcon(img='undo',
                             label=_('Undo'),
                             desc=_('Undo previous changes')),
            'redo': MetaIcon(img='redo',
                             label=_('Redo'),
                             desc=_('Redo previous changes')),
        }

        if not self.tools or 'selector' in self.tools:
            data.append((None, ))
        if not self.tools or 'addPoint' in self.tools:
            data.append(("addPoint", self.icons["addPoint"],
                         self.OnAddPoint,
                         wx.ITEM_CHECK))
        if not self.tools or 'addLine' in self.tools:
            data.append(("addLine", self.icons["addLine"],
                         self.OnAddLine,
                         wx.ITEM_CHECK))
        if not self.tools or 'addArea' in self.tools:
            data.append(("addArea", self.icons["addArea"],
                         self.OnAddAreaTool,
                         wx.ITEM_CHECK))
        if not self.tools or 'deleteLine' in self.tools:
            data.append(("deleteLine", self.icons["deleteLine"],
                         self.OnDeleteLine,
                         wx.ITEM_CHECK))
        if not self.tools or 'deleteArea' in self.tools:
            data.append(("deleteArea", self.icons["deleteArea"],
                         self.OnDeleteArea,
                         wx.ITEM_CHECK))
        if not self.tools or 'moveVertex' in self.tools:
            data.append(("moveVertex", self.icons["moveVertex"],
                         self.OnMoveVertex,
                         wx.ITEM_CHECK))
        if not self.tools or 'addVertex' in self.tools:
            data.append(("addVertex", self.icons["addVertex"],
                         self.OnAddVertex,
                         wx.ITEM_CHECK))
        if not self.tools or 'removeVertex' in self.tools:
            data.append(("removeVertex", self.icons["removeVertex"],
                         self.OnRemoveVertex,
                         wx.ITEM_CHECK))
        if not self.tools or 'editLine' in self.tools:
            data.append(("editLine", self.icons["editLine"],
                         self.OnEditLine,
                         wx.ITEM_CHECK))
        if not self.tools or 'moveLine' in self.tools:
            data.append(("moveLine", self.icons["moveLine"],
                         self.OnMoveLine,
                         wx.ITEM_CHECK))
        if not self.tools or 'displayCats' in self.tools:
            data.append(("displayCats", self.icons["displayCats"],
                         self.OnDisplayCats,
                         wx.ITEM_CHECK))
        if not self.tools or 'displayAttr' in self.tools:
            data.append(("displayAttr", self.icons["displayAttr"],
                         self.OnDisplayAttr,
                         wx.ITEM_CHECK))
        if not self.tools or 'additionalSelf.Tools' in self.tools:
            data.append(("additionalTools", self.icons["additionalTools"],
                         self.OnAdditionalToolMenu,
                         wx.ITEM_CHECK))
        if not self.tools or 'undo' in self.tools or \
                'redo' in self.tools:
            data.append((None, ))
        if not self.tools or 'undo' in self.tools:
            data.append(("undo", self.icons["undo"],
                         self.OnUndo))
        if not self.tools or 'redo' in self.tools:
            data.append(("redo", self.icons["redo"],
                         self.OnRedo))
        if not self.tools or 'settings' in self.tools or \
                'help' in self.tools or \
                'quit' in self.tools:
            data.append((None, ))
        if not self.tools or 'settings' in self.tools:
            data.append(("settings", self.icons["settings"],
                         self.OnSettings))
        if not self.tools or 'help' in self.tools:
            data.append(("help", self.icons["help"],
                         self.OnHelp))
        if not self.tools or 'quit' in self.tools:
            data.append(("quit", self.icons["quit"],
                         self.OnExit))

        return self._getToolbarData(data)

    def OnTool(self, event):
        """Tool selected -> untoggles previusly selected tool in
        toolbar"""
        Debug.msg(3, "VDigitToolbar.OnTool(): id = %s" % event.GetId())
        # set cursor
        self.MapWindow.SetNamedCursor('cross')
        self.MapWindow.mouse['box'] = 'point'
        self.MapWindow.mouse['use'] = 'pointer'

        aId = self.action.get('id', -1)
        BaseToolbar.OnTool(self, event)

        # clear tmp canvas
        if self.action['id'] != aId or aId == -1:
            self.MapWindow.polycoords = []
            self.MapWindow.ClearLines(pdc=self.MapWindow.pdcTmp)
            if self.digit and \
                    len(self.MapWindow.digit.GetDisplay().GetSelected()) > 0:
                # cancel action
                self.MapWindow.OnMiddleDown(None)

        # set no action
        if self.action['id'] == -1:
            self.action = {'desc': '',
                           'type': '',
                           'id': -1}

        # set focus
        self.MapWindow.SetFocus()

    def OnAddPoint(self, event):
        """Add point to the vector map Laier"""
        Debug.msg(2, "VDigitToolbar.OnAddPoint()")
        self.action = {'desc': "addLine",
                       'type': "point",
                       'id': self.addPoint}
        self.MapWindow.mouse['box'] = 'point'

    def OnAddLine(self, event):
        """Add line to the vector map layer"""
        Debug.msg(2, "VDigitToolbar.OnAddLine()")
        self.action = {'desc': "addLine",
                       'type': "line",
                       'id': self.addLine}
        self.MapWindow.mouse['box'] = 'line'
        # self.MapWindow.polycoords = [] # reset temp line

    def OnAddBoundary(self, event):
        """Add boundary to the vector map layer"""
        Debug.msg(2, "VDigitToolbar.OnAddBoundary()")

        self._toggleAreaIfNeeded()

        # reset temp line
        if self.action['desc'] != 'addLine' or \
                self.action['type'] != 'boundary':
            self.MapWindow.polycoords = []

        # update icon and tooltip
        self.SetToolNormalBitmap(self.addArea, self.icons[
                                 'addBoundary'].GetBitmap())
        self.SetToolShortHelp(self.addArea,
                              self.icons['addBoundary'].GetLabel())

        # set action
        self.action = {'desc': "addLine",
                       'type': "boundary",
                       'id': self.addArea}
        self.MapWindow.mouse['box'] = 'line'
        self._currentAreaActionType = 'boundary'

    def OnAddCentroid(self, event):
        """Add centroid to the vector map layer"""
        Debug.msg(2, "VDigitToolbar.OnAddCentroid()")

        self._toggleAreaIfNeeded()

        # update icon and tooltip
        self.SetToolNormalBitmap(self.addArea, self.icons[
                                 'addCentroid'].GetBitmap())
        self.SetToolShortHelp(self.addArea,
                              self.icons['addCentroid'].GetLabel())

        # set action
        self.action = {'desc': "addLine",
                       'type': "centroid",
                       'id': self.addArea}
        self.MapWindow.mouse['box'] = 'point'
        self._currentAreaActionType = 'centroid'

    def OnAddArea(self, event):
        """Add area to the vector map layer"""

        Debug.msg(2, "VDigitToolbar.OnAddArea()")

        self._toggleAreaIfNeeded()

        # update icon and tooltip
        self.SetToolNormalBitmap(
            self.addArea, self.icons['addArea'].GetBitmap())
        self.SetToolShortHelp(self.addArea, self.icons['addArea'].GetLabel())

        # set action
        self.action = {'desc': "addLine",
                       'type': "area",
                       'id': self.addArea}
        self.MapWindow.mouse['box'] = 'line'
        self._currentAreaActionType = 'area'

    def _toggleAreaIfNeeded(self):
        """In some cases, the area tool is not toggled, we have to do it manually."""
        if not self.GetToolState(self.addArea):
            self.ToggleTool(self.addArea, True)
            self.toolSwitcher.ToolChanged(self.addArea)

    def OnAddAreaTool(self, event):
        """Area tool activated."""
        Debug.msg(2, "VDigitToolbar.OnAddAreaTool()")

        # we need the previous id
        if not self._currentAreaActionType or self._currentAreaActionType == 'area':  # default action
            self.OnAddArea(event)
        elif self._currentAreaActionType == 'boundary':
            self.OnAddBoundary(event)
        elif self._currentAreaActionType == 'centroid':
            self.OnAddCentroid(event)

    def OnAddAreaMenu(self, event):
        """Digitize area menu (add area/boundary/centroid)"""
        menuItems = []
        if not self.tools or 'addArea' in self.tools:
            menuItems.append((self.icons["addArea"], self.OnAddArea))
        if not self.fType and not self.tools or 'addBoundary' in self.tools:
            menuItems.append((self.icons["addBoundary"], self.OnAddBoundary))
        if not self.fType and not self.tools or 'addCentroid' in self.tools:
            menuItems.append((self.icons["addCentroid"], self.OnAddCentroid))

        self._onMenu(menuItems)

    def OnExit(self, event=None):
        """Quit digitization tool"""
        # stop editing of the currently selected map layer
        if self.mapLayer:
            self.StopEditing()

        # close dialogs if still open
        if self.settingsDialog:
            self.settingsDialog.OnCancel(None)

        # set default mouse settings
        self.parent.GetMapToolbar().SelectDefault()
        self.MapWindow.polycoords = []

        # TODO: replace this by binding wx event in parent (or use signals...)
        if not self.parent.IsStandalone():
            # disable the toolbar
            self.parent.RemoveToolbar("vdigit")
        else:
            self.parent.Close()

    def OnMoveVertex(self, event):
        """Move line vertex"""
        Debug.msg(2, "Digittoolbar.OnMoveVertex():")
        self.action = {'desc': "moveVertex",
                       'id': self.moveVertex}
        self.MapWindow.mouse['box'] = 'point'

    def OnAddVertex(self, event):
        """Add line vertex"""
        Debug.msg(2, "Digittoolbar.OnAddVertex():")
        self.action = {'desc': "addVertex",
                       'id': self.addVertex}
        self.MapWindow.mouse['box'] = 'point'

    def OnRemoveVertex(self, event):
        """Remove line vertex"""
        Debug.msg(2, "Digittoolbar.OnRemoveVertex():")
        self.action = {'desc': "removeVertex",
                       'id': self.removeVertex}
        self.MapWindow.mouse['box'] = 'point'

    def OnEditLine(self, event):
        """Edit line"""
        Debug.msg(2, "Digittoolbar.OnEditLine():")
        self.action = {'desc': "editLine",
                       'id': self.editLine}
        self.MapWindow.mouse['box'] = 'line'

    def OnMoveLine(self, event):
        """Move line"""
        Debug.msg(2, "Digittoolbar.OnMoveLine():")
        self.action = {'desc': "moveLine",
                       'id': self.moveLine}
        self.MapWindow.mouse['box'] = 'box'

    def OnDeleteLine(self, event):
        """Delete line"""
        Debug.msg(2, "Digittoolbar.OnDeleteLine():")
        self.action = {'desc': "deleteLine",
                       'id': self.deleteLine}
        self.MapWindow.mouse['box'] = 'box'

    def OnDeleteArea(self, event):
        """Delete Area"""
        Debug.msg(2, "Digittoolbar.OnDeleteArea():")
        self.action = {'desc': "deleteArea",
                       'id': self.deleteArea}
        self.MapWindow.mouse['box'] = 'box'

    def OnDisplayCats(self, event):
        """Display/update categories"""
        Debug.msg(2, "Digittoolbar.OnDisplayCats():")
        self.action = {'desc': "displayCats",
                       'id': self.displayCats}
        self.MapWindow.mouse['box'] = 'point'

    def OnDisplayAttr(self, event):
        """Display/update attributes"""
        Debug.msg(2, "Digittoolbar.OnDisplayAttr():")
        self.action = {'desc': "displayAttrs",
                       'id': self.displayAttr}
        self.MapWindow.mouse['box'] = 'point'

    def OnUndo(self, event):
        """Undo previous changes"""
        self.digit.Undo()

        event.Skip()

    def OnRedo(self, event):
        """Undo previous changes"""
        self.digit.Undo(level=1)

        event.Skip()

    def EnableUndo(self, enable=True):
        """Enable 'Undo' in toolbar

        :param enable: False for disable
        """
        self._enableTool(self.undo, enable)

    def EnableRedo(self, enable=True):
        """Enable 'Redo' in toolbar

        :param enable: False for disable
        """
        self._enableTool(self.redo, enable)

    def _enableTool(self, tool, enable):
        if not self.FindById(tool):
            return

        if enable:
            if self.GetToolEnabled(tool) is False:
                self.EnableTool(tool, True)
        else:
            if self.GetToolEnabled(tool) is True:
                self.EnableTool(tool, False)

    def GetAction(self, type='desc'):
        """Get current action info"""
        return self.action.get(type, '')

    def OnSettings(self, event):
        """Show settings dialog"""
        if self.digit is None:
            try:
                self.digit = self.MapWindow.digit = self.digitClass(
                    mapwindow=self.MapWindow)
            except SystemExit:
                self.digit = self.MapWindow.digit = None

        if not self.settingsDialog:
            self.settingsDialog = VDigitSettingsDialog(
                parent=self.parent, giface=self._giface)
            self.settingsDialog.Show()

    def OnHelp(self, event):
        """Show digitizer help page in web browser"""
        self._giface.Help('wxGUI.vdigit')

    def OnAdditionalToolMenu(self, event):
        """Menu for additional tools"""
        point = wx.GetMousePosition()
        toolMenu = wx.Menu()

        for label, itype, handler, desc in (
            (_('Break selected lines/boundaries at intersection'),
             wx.ITEM_CHECK, self.OnBreak, "breakLine"),
            (_('Connect selected lines/boundaries'),
             wx.ITEM_CHECK, self.OnConnect, "connectLine"),
            (_('Copy categories'),
             wx.ITEM_CHECK, self.OnCopyCats, "copyCats"),
            (_('Copy features from (background) vector map'),
             wx.ITEM_CHECK, self.OnCopy, "copyLine"),
            (_('Copy attributes'),
             wx.ITEM_CHECK, self.OnCopyAttrb, "copyAttrs"),
            (_('Feature type conversion'),
             wx.ITEM_CHECK, self.OnTypeConversion, "typeConv"),
            (_('Flip selected lines/boundaries'),
             wx.ITEM_CHECK, self.OnFlip, "flipLine"),
            (_('Merge selected lines/boundaries'),
             wx.ITEM_CHECK, self.OnMerge, "mergeLine"),
            (_('Snap selected lines/boundaries (only to nodes)'),
             wx.ITEM_CHECK, self.OnSnap, "snapLine"),
            (_('Split line/boundary'),
             wx.ITEM_CHECK, self.OnSplitLine, "splitLine"),
            (_('Query features'),
             wx.ITEM_CHECK, self.OnQuery, "queryLine"),
            (_('Z bulk-labeling of 3D lines'),
             wx.ITEM_CHECK, self.OnZBulk, "zbulkLine")):
            # Add items to the menu
            item = wx.MenuItem(parentMenu=toolMenu, id=wx.ID_ANY,
                               text=label,
                               kind=itype)
            toolMenu.AppendItem(item)
            self.MapWindow.Bind(wx.EVT_MENU, handler, item)
            if self.action['desc'] == desc:
                item.Check(True)

        # Popup the menu.  If an item is selected then its handler
        # will be called before PopupMenu returns.
        self.MapWindow.PopupMenu(toolMenu)
        toolMenu.Destroy()

        if self.action['desc'] == 'addPoint':
            self.ToggleTool(self.additionalTools, False)

    def OnCopy(self, event):
        """Copy selected features from (background) vector map"""
        if not self.digit:
            GError(_("No vector map open for editing."), self.parent)
            return

        # select background map
        dlg = VectorDialog(self.parent,
                           title=_("Select background vector map"),
                           layerTree=self._giface.GetLayerTree())
        if dlg.ShowModal() != wx.ID_OK:
            dlg.Destroy()
            return

        mapName = dlg.GetName(full=True)
        dlg.Destroy()

        # close open background map if any
        bgMap = UserSettings.Get(group='vdigit', key='bgmap', subkey='value',
                                 settings_type='internal')
        if bgMap:
            self.digit.CloseBackgroundMap()
            self.editingBgMap.emit(mapName=bgMap, unset=True)

        # open background map for reading
        UserSettings.Set(group='vdigit', key='bgmap', subkey='value',
                         value=str(mapName), settings_type='internal')
        self.digit.OpenBackgroundMap(mapName)
        self.editingBgMap.emit(mapName=mapName)

        if self.action['desc'] == 'copyLine':  # select previous action
            self.ToggleTool(self.addPoint, True)
            self.ToggleTool(self.additionalTools, False)
            self.OnAddPoint(event)
            return

        Debug.msg(2, "Digittoolbar.OnCopy():")
        self.action = {'desc': "copyLine",
                       'id': self.additionalTools}
        self.MapWindow.mouse['box'] = 'box'

    def OnSplitLine(self, event):
        """Split line"""
        if self.action['desc'] == 'splitLine':  # select previous action
            self.ToggleTool(self.addPoint, True)
            self.ToggleTool(self.additionalTools, False)
            self.OnAddPoint(event)
            return

        Debug.msg(2, "Digittoolbar.OnSplitLine():")
        self.action = {'desc': "splitLine",
                       'id': self.additionalTools}
        self.MapWindow.mouse['box'] = 'point'

    def OnCopyCats(self, event):
        """Copy categories"""
        if self.action['desc'] == 'copyCats':  # select previous action
            self.ToggleTool(self.addPoint, True)
            self.ToggleTool(self.copyCats, False)
            self.OnAddPoint(event)
            return

        Debug.msg(2, "Digittoolbar.OnCopyCats():")
        self.action = {'desc': "copyCats",
                       'id': self.additionalTools}
        self.MapWindow.mouse['box'] = 'point'

    def OnCopyAttrb(self, event):
        """Copy attributes"""
        if self.action['desc'] == 'copyAttrs':  # select previous action
            self.ToggleTool(self.addPoint, True)
            self.ToggleTool(self.copyCats, False)
            self.OnAddPoint(event)
            return

        Debug.msg(2, "Digittoolbar.OnCopyAttrb():")
        self.action = {'desc': "copyAttrs",
                       'id': self.additionalTools}
        self.MapWindow.mouse['box'] = 'point'

    def OnFlip(self, event):
        """Flip selected lines/boundaries"""
        if self.action['desc'] == 'flipLine':  # select previous action
            self.ToggleTool(self.addPoint, True)
            self.ToggleTool(self.additionalTools, False)
            self.OnAddPoint(event)
            return

        Debug.msg(2, "Digittoolbar.OnFlip():")
        self.action = {'desc': "flipLine",
                       'id': self.additionalTools}
        self.MapWindow.mouse['box'] = 'box'

    def OnMerge(self, event):
        """Merge selected lines/boundaries"""
        if self.action['desc'] == 'mergeLine':  # select previous action
            self.ToggleTool(self.addPoint, True)
            self.ToggleTool(self.additionalTools, False)
            self.OnAddPoint(event)
            return

        Debug.msg(2, "Digittoolbar.OnMerge():")
        self.action = {'desc': "mergeLine",
                       'id': self.additionalTools}
        self.MapWindow.mouse['box'] = 'box'

    def OnBreak(self, event):
        """Break selected lines/boundaries"""
        if self.action['desc'] == 'breakLine':  # select previous action
            self.ToggleTool(self.addPoint, True)
            self.ToggleTool(self.additionalTools, False)
            self.OnAddPoint(event)
            return

        Debug.msg(2, "Digittoolbar.OnBreak():")
        self.action = {'desc': "breakLine",
                       'id': self.additionalTools}
        self.MapWindow.mouse['box'] = 'box'

    def OnSnap(self, event):
        """Snap selected features"""
        if self.action['desc'] == 'snapLine':  # select previous action
            self.ToggleTool(self.addPoint, True)
            self.ToggleTool(self.additionalTools, False)
            self.OnAddPoint(event)
            return

        Debug.msg(2, "Digittoolbar.OnSnap():")
        self.action = {'desc': "snapLine",
                       'id': self.additionalTools}
        self.MapWindow.mouse['box'] = 'box'

    def OnConnect(self, event):
        """Connect selected lines/boundaries"""
        if self.action['desc'] == 'connectLine':  # select previous action
            self.ToggleTool(self.addPoint, True)
            self.ToggleTool(self.additionalTools, False)
            self.OnAddPoint(event)
            return

        Debug.msg(2, "Digittoolbar.OnConnect():")
        self.action = {'desc': "connectLine",
                       'id': self.additionalTools}
        self.MapWindow.mouse['box'] = 'box'

    def OnQuery(self, event):
        """Query selected lines/boundaries"""
        if self.action['desc'] == 'queryLine':  # select previous action
            self.ToggleTool(self.addPoint, True)
            self.ToggleTool(self.additionalTools, False)
            self.OnAddPoint(event)
            return

        Debug.msg(
            2,
            "Digittoolbar.OnQuery(): %s" %
            UserSettings.Get(
                group='vdigit',
                key='query',
                subkey='selection'))
        self.action = {'desc': "queryLine",
                       'id': self.additionalTools}
        self.MapWindow.mouse['box'] = 'box'

    def OnZBulk(self, event):
        """Z bulk-labeling selected lines/boundaries"""
        if not self.digit.IsVector3D():
            GError(parent=self.parent,
                   message=_("Vector map is not 3D. Operation canceled."))
            return

        if self.action['desc'] == 'zbulkLine':  # select previous action
            self.ToggleTool(self.addPoint, True)
            self.ToggleTool(self.additionalTools, False)
            self.OnAddPoint(event)
            return

        Debug.msg(2, "Digittoolbar.OnZBulk():")
        self.action = {'desc': "zbulkLine",
                       'id': self.additionalTools}
        self.MapWindow.mouse['box'] = 'line'

    def OnTypeConversion(self, event):
        """Feature type conversion

        Supported conversions:
         - point <-> centroid
         - line <-> boundary
        """
        if self.action['desc'] == 'typeConv':  # select previous action
            self.ToggleTool(self.addPoint, True)
            self.ToggleTool(self.additionalTools, False)
            self.OnAddPoint(event)
            return

        Debug.msg(2, "Digittoolbar.OnTypeConversion():")
        self.action = {'desc': "typeConv",
                       'id': self.additionalTools}
        self.MapWindow.mouse['box'] = 'box'

    def OnSelectMap(self, event):
        """Select vector map layer for editing

        If there is a vector map layer already edited, this action is
        firstly terminated. The map layer is closed. After this the
        selected map layer activated for editing.
        """
        if event.GetSelection() == 0:  # create new vector map layer
            if self.mapLayer:
                openVectorMap = self.mapLayer.GetName(
                    fullyQualified=False)['name']
            else:
                openVectorMap = None
            dlg = CreateNewVector(self.parent,
                                  exceptMap=openVectorMap, giface=self._giface,
                                  cmd=(('v.edit',
                                        {'tool': 'create'},
                                        'map')),
                                  disableAdd=True)

            if dlg and dlg.GetName():
                # add layer to map layer tree/map display
                mapName = dlg.GetName() + '@' + grass.gisenv()['MAPSET']
                self._giface.GetLayerList().AddLayer(
                        ltype='vector', name=mapName, checked=True,
                        cmd=['d.vect', 'map=%s' % mapName])

                vectLayers = self.UpdateListOfLayers(updateTool=True)
                selection = vectLayers.index(mapName)

                # create table ?
                if dlg.IsChecked('table'):
                    # TODO: replace this by signal
                    # also note that starting of tools such as atm, iclass,
                    # plots etc. should be handled in some better way
                    # than starting randomly from mapdisp and lmgr
                    lmgr = self.parent.GetLayerManager()
                    if lmgr:
                        lmgr.OnShowAttributeTable(None, selection='table')
                dlg.Destroy()
            else:
                self.combo.SetValue(_('Select vector map'))
                if dlg:
                    dlg.Destroy()
                return
        else:
            selection = event.GetSelection() - 1  # first option is 'New vector map'

        # skip currently selected map
        if self.layers[selection] == self.mapLayer:
            return

        if self.mapLayer:
            # deactive map layer for editing
            self.StopEditing()

        # select the given map layer for editing
        self.StartEditing(self.layers[selection])

        event.Skip()

    def StartEditing(self, mapLayer):
        """Start editing selected vector map layer.

        :param mapLayer: MapLayer to be edited
        """
        # check if topology is available (skip for hidden - temporary
        # maps, see iclass for details)
        if not mapLayer.IsHidden() and grass.vector_info(
                mapLayer.GetName())['level'] != 2:
            dlg = wx.MessageDialog(
                parent=self.MapWindow,
                message=_(
                    "Topology for vector map <%s> is not available. "
                    "Topology is required by digitizer.\nDo you want to "
                    "rebuild topology (takes some time) and open the vector map "
                    "for editing?") %
                mapLayer.GetName(),
                caption=_("Digitizer error"),
                style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)
            if dlg.ShowModal() == wx.ID_YES:
                RunCommand('v.build', map=mapLayer.GetName())
            else:
                return

        # deactive layer
        self.Map.ChangeLayerActive(mapLayer, False)

        # clean map canvas
        self.MapWindow.EraseMap()

        # unset background map if needed
        if mapLayer:
            if UserSettings.Get(
                    group='vdigit', key='bgmap', subkey='value',
                    settings_type='internal') == mapLayer.GetName():
                UserSettings.Set(
                    group='vdigit',
                    key='bgmap',
                    subkey='value',
                    value='',
                    settings_type='internal')

            self.parent.SetStatusText(_("Please wait, "
                                        "opening vector map <%s> for editing...") %
                                      mapLayer.GetName(), 0)

        self.MapWindow.pdcVector = wx.PseudoDC()
        self.digit = self.MapWindow.digit = self.digitClass(
            mapwindow=self.MapWindow)

        self.mapLayer = mapLayer
        # open vector map (assume that 'hidden' map layer is temporary vector
        # map)
        if self.digit.OpenMap(
                mapLayer.GetName(),
                tmp=mapLayer.IsHidden()) is None:
            self.mapLayer = None
            self.StopEditing()
            return False

        # check feature type (only for OGR layers)
        self.fType = self.digit.GetFeatureType()
        self.EnableAll()
        self.EnableUndo(False)
        self.EnableRedo(False)

        if self.fType == 'point':
            for tool in (self.addLine, self.addArea, self.moveVertex,
                         self.addVertex, self.removeVertex, self.editLine):
                self.EnableTool(tool, False)
        elif self.fType == 'linestring':
            for tool in (self.addPoint, self.addArea):
                self.EnableTool(tool, False)
        elif self.fType == 'polygon':
            for tool in (self.addPoint, self.addLine):
                self.EnableTool(tool, False)
        elif self.fType:
            GError(
                parent=self,
                message=_(
                    "Unsupported feature type '%(type)s'. Unable to edit "
                    "OGR layer <%(layer)s>.") %
                {'type': self.fType, 'layer': mapLayer.GetName()})
            self.digit.CloseMap()
            self.mapLayer = None
            self.StopEditing()
            return False

        # update toolbar
        if self.combo:
            self.combo.SetValue(mapLayer.GetName())
        if 'map' in self.parent.toolbars:
            self.parent.toolbars['map'].combo.SetValue(_('Vector digitizer'))

        # here was dead code to enable vdigit button in toolbar
        # with if to ignore iclass
        # some signal (DigitizerStarted) can be emitted here

        Debug.msg(
            4, "VDigitToolbar.StartEditing(): layer=%s" %
            mapLayer.GetName())

        # change cursor
        if self.MapWindow.mouse['use'] == 'pointer':
            self.MapWindow.SetNamedCursor('cross')

        if not self.MapWindow.resize:
            self.MapWindow.UpdateMap(render=True)

        # respect opacity
        opacity = mapLayer.GetOpacity()

        if opacity < 1.0:
            alpha = int(opacity * 255)
            self.digit.GetDisplay().UpdateSettings(alpha=alpha)

        # emit signal
        layerTree = self._giface.GetLayerTree()
        if layerTree:
            item = layerTree.FindItemByData('maplayer', self.mapLayer)
        else:
            item = None
        self.editingStarted.emit(
            vectMap=mapLayer.GetName(),
            digit=self.digit, layerItem=item)

        return True

    def StopEditing(self):
        """Stop editing of selected vector map layer.

        :return: True on success
        :return: False on failure
        """
        item = None

        if self.combo:
            self.combo.SetValue(_('Select vector map'))

        # save changes
        if self.mapLayer:
            Debug.msg(
                4, "VDigitToolbar.StopEditing(): layer=%s" %
                self.mapLayer.GetName())
            if UserSettings.Get(group='vdigit', key='saveOnExit',
                                subkey='enabled') is False:
                if self.digit.GetUndoLevel() > -1:
                    dlg = wx.MessageDialog(
                        parent=self.parent,
                        message=_(
                            "Do you want to save changes "
                            "in vector map <%s>?") %
                        self.mapLayer.GetName(),
                        caption=_("Save changes?"),
                        style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
                    if dlg.ShowModal() == wx.ID_NO:
                        # revert changes
                        self.digit.Undo(0)
                    dlg.Destroy()

            self.parent.SetStatusText(_("Please wait, "
                                        "closing and rebuilding topology of "
                                        "vector map <%s>...") %
                                      self.mapLayer.GetName(), 0)
            self.digit.CloseMap()

            # close open background map if any
            bgMap = UserSettings.Get(
                group='vdigit',
                key='bgmap',
                subkey='value',
                settings_type='internal')
            if bgMap:
                self.digit.CloseBackgroundMap()
                self.editingBgMap.emit(mapName=bgMap, unset=True)

            self._giface.GetProgress().SetValue(0)
            self._giface.WriteCmdLog(
                _("Editing of vector map <%s> successfully finished") %
                self.mapLayer.GetName(),
                notification=Notification.HIGHLIGHT)
            # re-active layer
            layerTree = self._giface.GetLayerTree()
            if layerTree:
                item = layerTree.FindItemByData('maplayer', self.mapLayer)
                if item and layerTree.IsItemChecked(item):
                    self.Map.ChangeLayerActive(self.mapLayer, True)

        # change cursor
        self.MapWindow.SetNamedCursor('default')
        self.MapWindow.pdcVector = None

        # close dialogs
        for dialog in ('attributes', 'category'):
            if self.parent.dialogs[dialog]:
                self.parent.dialogs[dialog].Close()
                self.parent.dialogs[dialog] = None

        self.digit = None
        self.MapWindow.digit = None

        self.editingStopped.emit(layerItem=item)

        self.mapLayer = None

        self.MapWindow.redrawAll = True

        return True

    def UpdateListOfLayers(self, updateTool=False):
        """Update list of available vector map layers.
        This list consists only editable layers (in the current mapset)

        :param updateTool: True to update also toolbar
        :type updateTool: bool
        """
        Debug.msg(4, "VDigitToolbar.UpdateListOfLayers(): updateTool=%d" %
                  updateTool)

        layerNameSelected = None
        # name of currently selected layer
        if self.mapLayer:
            layerNameSelected = self.mapLayer.GetName()

        # select vector map layer in the current mapset
        layerNameList = []
        self.layers = self.Map.GetListOfLayers(ltype="vector",
                                               mapset=grass.gisenv()['MAPSET'])

        for layer in self.layers:
            if not layer.name in layerNameList:  # do not duplicate layer
                layerNameList.append(layer.GetName())

        if updateTool:  # update toolbar
            if not self.mapLayer:
                value = _('Select vector map')
            else:
                value = layerNameSelected

            if not self.comboid:
                if not self.tools or 'selector' in self.tools:
                    self.combo = wx.ComboBox(
                        self, id=wx.ID_ANY, value=value,
                        choices=[_('New vector map'), ] + layerNameList,
                        size=(80, -1),
                        style=wx.CB_READONLY)
                    self.comboid = self.InsertControl(0, self.combo)
                    self.parent.Bind(
                        wx.EVT_COMBOBOX, self.OnSelectMap, self.comboid)
            else:
                self.combo.SetItems([_('New vector map'), ] + layerNameList)

            self.Realize()

        return layerNameList

    def GetLayer(self):
        """Get selected layer for editing -- MapLayer instance"""
        return self.mapLayer
Exemple #43
0
class Statistics:
    """Statistis connected to one class (category).

    It is Python counterpart of similar C structure.
    But it adds some attributes or features used in wxIClass.
    It is not interface to C structure (it copies values).
    """

    def __init__(self):
        self.category = -1
        self.name = ""
        self.rasterName = ""
        self.color = "0:0:0"
        self.nbands = 0
        self.ncells = 0
        self.nstd = 1.5
        self.bands = []
        self.ready = False

        self.statisticsSet = Signal("Statistics.statisticsSet")

    def SetReady(self, ready=True):
        self.ready = ready

    def IsReady(self):
        return self.ready

    def SetBaseStatistics(self, cat, name, color):
        """Sets basic (non-statistical) values.

        .. todo::
            Later self.name is changed but self.rasterName is not.
            self.rasterName should not be set by user. It can remains
            the same. But it should be done more explicitly. Currently
            it looks like unintentional feature or bug.
        """
        self.category = cat
        self.name = name
        self.color = color

        rasterPath = grass.tempfile(create=False)
        name = name.replace(' ', '_')
        self.rasterName = name + '_' + os.path.basename(rasterPath)

    def SetFromcStatistics(self, cStatistics):
        """Sets all statistical values.

        Copies all statistic values from \a cStattistics.

        :param cStatistics: pointer to C statistics structure
        """
        cat = c_int()

        set_stats = {}
        I_iclass_statistics_get_cat(cStatistics, byref(cat))
        if self.category != cat.value:
            set_stats["category"] = cat.value

        name = c_char_p()
        I_iclass_statistics_get_name(cStatistics, byref(name))
        if self.name != name.value:
            set_stats["name"] = grass.decode(name.value)

        color = c_char_p()
        I_iclass_statistics_get_color(cStatistics, byref(color))
        if self.color != color.value:
            set_stats["color"] = grass.decode(color.value)

        nbands = c_int()
        I_iclass_statistics_get_nbands(cStatistics, byref(nbands))
        if self.nbands != nbands.value:
            set_stats["nbands"] = nbands.value

        ncells = c_int()
        I_iclass_statistics_get_ncells(cStatistics, byref(ncells))
        if self.ncells != ncells.value:
            set_stats["ncells"] = ncells.value

        nstd = c_float()
        I_iclass_statistics_get_nstd(cStatistics, byref(nstd))
        if self.nstd != nstd.value:
            set_stats["nstd"] = nstd.value

        self.SetStatistics(set_stats)
        self.SetBandStatistics(cStatistics)

    def SetBandStatistics(self, cStatistics):
        """Sets all band statistics.

        :param cStatistics: pointer to C statistics structure
        """
        self.bands = []
        for i in range(self.nbands):
            band = BandStatistics()
            band.SetFromcStatistics(cStatistics, index=i)
            self.bands.append(band)

    def SetStatistics(self, stats):

        for st, val in six.iteritems(stats):
            setattr(self, st, val)

        self.statisticsSet.emit(stats=stats)
Exemple #44
0
class WSPanel(wx.Panel):
    def __init__(self, parent, web_service, **kwargs):
        """Show data from capabilities file.

        Signal: capParsed - this signal is emitted when capabilities file is downloaded
                            (after ConnectToServer method was called)

        :param parent:  parent widget
        :param web_service:  web service to be panel generated for
        """
        wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY)

        self.parent = parent
        self.ws = web_service

        self.capParsed = Signal("WSPanel.capParsed")

        # stores widgets, which represents parameters/flags of d.wms
        self.params = {}
        self.flags = {}

        self.o_layer_name = ""

        # stores err output from r.in.wms during getting capabilities
        self.cmd_err_str = ""

        # stores selected layer from layer list
        self.sel_layers = []

        # downloaded and parsed data from server successfully?
        self.is_connected = False

        # common part of command for r.in.wms -c and d.wms
        self.ws_cmdl = None

        # provides information about driver parameters
        self.drv_info = WMSDriversInfo()
        self.drv_props = self.drv_info.GetDrvProperties(self.ws)

        self.ws_drvs = {
            "WMS_1.1.1": {
                "cmd": ["wms_version=1.1.1", "driver=WMS_GRASS"],
                "cap_parser": lambda temp_file: WMSCapabilities(temp_file, "1.1.1"),
            },
            "WMS_1.3.0": {
                "cmd": ["wms_version=1.3.0", "driver=WMS_GRASS"],
                "cap_parser": lambda temp_file: WMSCapabilities(temp_file, "1.3.0"),
            },
            "WMTS": {
                "cmd": ["driver=WMTS_GRASS"],
                "cap_parser": WMTSCapabilities,
            },
            "OnEarth": {
                "cmd": ["driver=OnEarth_GRASS"],
                "cap_parser": OnEarthCapabilities,
            },
        }

        self.cmdStdErr = GStderr(self)
        self.cmd_thread = CmdThread(self)
        self.cap_file = grass.tempfile()

        reqDataBox = StaticBox(parent=self, label=_(" Requested data settings "))
        self._nb_sizer = wx.StaticBoxSizer(reqDataBox, wx.VERTICAL)
        self.notebook = GNotebook(
            parent=self, style=FN.FNB_FANCY_TABS | FN.FNB_NO_X_BUTTON | FN.FNB_NODRAG
        )

        self._requestPage()
        self._advancedSettsPage()

        self._layout()

        self.layerSelected = self.list.layerSelected

        self.Bind(EVT_CMD_DONE, self.OnCapDownloadDone)
        self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)

        self.SetMinSize((-1, 300))

    def __del__(self):
        self.cmd_thread.abort(abortall=True)
        grass.try_remove(self.cap_file)

    def _layout(self):
        self._nb_sizer.Add(self.notebook, proportion=1, flag=wx.EXPAND)
        self.SetSizer(self._nb_sizer)

    def _requestPage(self):
        """Create request page"""
        self.req_page_panel = wx.Panel(parent=self, id=wx.ID_ANY)
        self.notebook.AddPage(
            page=self.req_page_panel, text=_("Request"), name="request"
        )

        # list of layers
        self.layersBox = StaticBox(
            parent=self.req_page_panel, id=wx.ID_ANY, label=_("List of layers ")
        )

        style = wx.TR_DEFAULT_STYLE | wx.TR_HAS_BUTTONS | wx.TR_FULL_ROW_HIGHLIGHT
        if self.drv_props["req_multiple_layers"]:
            style = style | wx.TR_MULTIPLE
        if "WMS" not in self.ws:
            style = style | wx.TR_HIDE_ROOT

        self.list = LayersList(
            parent=self.req_page_panel, web_service=self.ws, style=style
        )

        self.params["format"] = None

        self.params["srs"] = None
        if "srs" not in self.drv_props["ignored_params"]:
            projText = StaticText(
                parent=self.req_page_panel, id=wx.ID_ANY, label=_("Source projection:")
            )
            self.params["srs"] = wx.Choice(parent=self.req_page_panel, id=wx.ID_ANY)

        self.list.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnListSelChanged)

        # layout
        self.req_page_sizer = wx.BoxSizer(wx.VERTICAL)

        layersSizer = wx.StaticBoxSizer(self.layersBox, wx.HORIZONTAL)

        layersSizer.Add(
            self.list,
            proportion=1,
            flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
            border=5,
        )

        self.req_page_sizer.Add(
            layersSizer,
            proportion=1,
            flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
            border=5,
        )

        self.source_sizer = wx.BoxSizer(wx.HORIZONTAL)

        if self.params["format"] is not None:
            self.source_sizer.Add(
                self.params["format"], flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5
            )

        if self.params["srs"] is not None:
            self.source_sizer.Add(
                projText, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5
            )
            self.source_sizer.Add(
                self.params["srs"],
                flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.TOP | wx.BOTTOM,
                border=5,
            )

        self.req_page_sizer.Add(
            self.source_sizer, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5
        )

        self.req_page_panel.SetSizer(self.req_page_sizer)

    def enableButtons(self, enable=True):
        """Enable/disable up, down, buttons"""
        self.btnUp.Enable(enable)
        self.btnDown.Enable(enable)

    def _advancedSettsPage(self):
        """Create advanced settings page"""
        # TODO parse maxcol, maxrow, settings from d.wms module?
        # TODO OnEarth driver - add selection of time
        adv_setts_panel = ScrolledPanel(
            parent=self, id=wx.ID_ANY, style=wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER
        )
        self.notebook.AddPage(
            page=adv_setts_panel,
            text=_("Advanced request settings"),
            name="adv_req_setts",
        )

        labels = {}
        self.l_odrder_list = None
        if "WMS" in self.ws:
            labels["l_order"] = StaticBox(
                parent=adv_setts_panel,
                id=wx.ID_ANY,
                label=_("Order of layers in raster"),
            )
            self.l_odrder_list = wx.ListBox(
                adv_setts_panel,
                id=wx.ID_ANY,
                choices=[],
                style=wx.LB_SINGLE | wx.LB_NEEDED_SB,
            )
            self.btnUp = Button(adv_setts_panel, id=wx.ID_ANY, label=_("Up"))
            self.btnDown = Button(adv_setts_panel, id=wx.ID_ANY, label=_("Down"))

            self.btnUp.Bind(wx.EVT_BUTTON, self.OnUp)
            self.btnDown.Bind(wx.EVT_BUTTON, self.OnDown)

        labels["method"] = StaticText(
            parent=adv_setts_panel, id=wx.ID_ANY, label=_("Reprojection method:")
        )

        self.reproj_methods = ["nearest", "linear", "cubic", "cubicspline"]
        self.params["method"] = wx.Choice(
            parent=adv_setts_panel,
            id=wx.ID_ANY,
            choices=[
                _("Nearest neighbor"),
                _("Linear interpolation"),
                _("Cubic interpolation"),
                _("Cubic spline interpolation"),
            ],
        )

        labels["maxcols"] = StaticText(
            parent=adv_setts_panel,
            id=wx.ID_ANY,
            label=_("Maximum columns to request from server at time:"),
        )
        self.params["maxcols"] = SpinCtrl(
            parent=adv_setts_panel, id=wx.ID_ANY, size=(100, -1)
        )

        labels["maxrows"] = StaticText(
            parent=adv_setts_panel,
            id=wx.ID_ANY,
            label=_("Maximum rows to request from server at time:"),
        )
        self.params["maxrows"] = SpinCtrl(
            parent=adv_setts_panel, id=wx.ID_ANY, size=(100, -1)
        )

        min = 100
        max = 10000
        self.params["maxcols"].SetRange(min, max)
        self.params["maxrows"].SetRange(min, max)

        val = 500
        self.params["maxcols"].SetValue(val)
        self.params["maxrows"].SetValue(val)

        self.flags["o"] = self.params["bgcolor"] = None
        if "o" not in self.drv_props["ignored_flags"]:
            self.flags["o"] = wx.CheckBox(
                parent=adv_setts_panel,
                id=wx.ID_ANY,
                label=_("Do not request transparent data"),
            )

            self.flags["o"].Bind(wx.EVT_CHECKBOX, self.OnTransparent)
            labels["bgcolor"] = StaticText(
                parent=adv_setts_panel, id=wx.ID_ANY, label=_("Background color:")
            )
            self.params["bgcolor"] = csel.ColourSelect(
                parent=adv_setts_panel,
                id=wx.ID_ANY,
                colour=(255, 255, 255),
                size=globalvar.DIALOG_COLOR_SIZE,
            )
            self.params["bgcolor"].Enable(False)

        self.params["urlparams"] = None
        if self.params["urlparams"] not in self.drv_props["ignored_params"]:
            labels["urlparams"] = StaticText(
                parent=adv_setts_panel,
                id=wx.ID_ANY,
                label=_("Additional query parameters for server:"),
            )
            self.params["urlparams"] = TextCtrl(parent=adv_setts_panel, id=wx.ID_ANY)

        # layout

        border = wx.BoxSizer(wx.VERTICAL)

        if "WMS" in self.ws:

            boxSizer = wx.StaticBoxSizer(labels["l_order"], wx.VERTICAL)
            gridSizer = wx.GridBagSizer(hgap=3, vgap=3)

            gridSizer.Add(
                self.l_odrder_list,
                pos=(0, 0),
                span=(4, 1),
                flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
                border=0,
            )

            gridSizer.Add(
                self.btnUp, pos=(0, 1), flag=wx.ALIGN_CENTER_VERTICAL, border=0
            )

            gridSizer.Add(
                self.btnDown, pos=(1, 1), flag=wx.ALIGN_CENTER_VERTICAL, border=0
            )

            gridSizer.AddGrowableCol(0)
            boxSizer.Add(gridSizer, flag=wx.EXPAND | wx.ALL, border=5)

            border.Add(boxSizer, flag=wx.LEFT | wx.RIGHT | wx.UP | wx.EXPAND, border=5)

        gridSizer = wx.GridBagSizer(hgap=3, vgap=3)

        row = 0
        for k in ["method", "maxcols", "maxrows", "o", "bgcolor"]:

            if k in self.params:
                param = self.params[k]
            elif k in self.flags:
                param = self.flags[k]

            if param is None:
                continue

            if k in labels or k == "o":
                if k != "o":
                    label = labels[k]
                else:
                    label = param

                gridSizer.Add(
                    label, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 0)
                )

            if k != "o":
                gridSizer.Add(
                    param, flag=wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 1)
                )
            row += 1

        gridSizer.AddGrowableCol(0)
        border.Add(gridSizer, flag=wx.LEFT | wx.RIGHT | wx.TOP | wx.EXPAND, border=5)

        if self.params["urlparams"]:
            gridSizer = wx.GridBagSizer(hgap=3, vgap=3)

            row = 0
            gridSizer.Add(
                labels["urlparams"],
                flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL,
                pos=(row, 0),
            )

            gridSizer.Add(
                self.params["urlparams"],
                flag=wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
                pos=(row, 1),
            )

            gridSizer.AddGrowableCol(1)

            border.Add(
                gridSizer, flag=wx.LEFT | wx.RIGHT | wx.TOP | wx.EXPAND, border=5
            )

        adv_setts_panel.SetSizer(border)
        adv_setts_panel.SetAutoLayout(True)
        adv_setts_panel.SetupScrolling()

    def OnUp(self, event):
        """Move selected layer up"""
        if self.l_odrder_list.GetSelections():
            pos = self.l_odrder_list.GetSelection()
            if pos:
                self.sel_layers.insert(pos - 1, self.sel_layers.pop(pos))
            if pos > 0:
                self._updateLayerOrderList(selected=(pos - 1))
            else:
                self._updateLayerOrderList(selected=0)

    def OnDown(self, event):
        """Move selected to down"""
        if self.l_odrder_list.GetSelections():
            pos = self.l_odrder_list.GetSelection()
            if pos != len(self.sel_layers) - 1:
                self.sel_layers.insert(pos + 1, self.sel_layers.pop(pos))
            if pos < len(self.sel_layers) - 1:
                self._updateLayerOrderList(selected=(pos + 1))
            else:
                self._updateLayerOrderList(selected=len(self.sel_layers) - 1)

    def _updateLayerOrderList(self, selected=None):
        """Update order in list."""

        def getlayercaption(l):
            if l["title"]:
                cap = l["title"]
            else:
                cap = l["name"]

            if l["style"]:
                if l["style"]["title"]:
                    cap += " / " + l["style"]["title"]
                else:
                    cap += " / " + l["style"]["name"]
            return cap

        layer_capts = [getlayercaption(l) for l in self.sel_layers]
        self.l_odrder_list.Set(layer_capts)
        if self.l_odrder_list.IsEmpty():
            self.enableButtons(False)
        else:
            self.enableButtons(True)
            if selected is not None:
                self.l_odrder_list.SetSelection(selected)
                self.l_odrder_list.EnsureVisible(selected)

    def OnTransparent(self, event):
        checked = event.IsChecked()
        if checked:
            self.params["bgcolor"].Enable(True)
        else:
            self.params["bgcolor"].Enable(False)

    def ConnectToServer(self, url, username, password):
        """Download and parse data from capabilities file.

        :param url: server url
        :type url: str
        :param username: username for connection
        :type username: str
        :param password: password for connection
        :type password: str
        """
        self._prepareForNewConn(url, username, password)
        cap_cmd = [
            "r.in.wms",
            "-c",
            ("capfile_output=%s" % self.cap_file),
            "--overwrite",
        ] + self.ws_cmdl

        self.currentPid = self.cmd_thread.GetId()
        self.cmd_thread.RunCmd(cap_cmd, stderr=self.cmdStdErr)

    def OnCmdOutput(self, event):
        """Manage cmd output."""
        if Debug.GetLevel() != 0:
            Debug.msg(1, event.text)
        elif event.type != "message" and event.type != "warning":
            self.cmd_err_str += event.text + os.linesep

    def _prepareForNewConn(self, url, username, password):
        """Prepare panel for new connection"""
        self.is_connected = False

        self.sel_layers = []
        self.formats_list = []
        self.projs_list = []

        self.conn = {"url": url, "password": password, "username": username}

        conn_cmd = []
        for k, v in six.iteritems(self.conn):
            if v:
                conn_cmd.append("%s=%s" % (k, v))

        self.ws_cmdl = self.ws_drvs[self.ws]["cmd"] + conn_cmd

    def OnCapDownloadDone(self, event):
        """Process downloaded capabilities file and emits capParsed
        signal (see class constructor).
        """
        if event.pid != self.currentPid:
            return

        if event.returncode != 0:
            if self.cmd_err_str:
                self.cmd_err_str = (
                    _(
                        "Unable to download %s capabilities file\nfrom <%s>:\n"
                        % (self.ws.replace("_", " "), self.conn["url"])
                    )
                    + self.cmd_err_str
                )
            self._postCapParsedEvt(error_msg=self.cmd_err_str)
            self.cmd_err_str = ""
            return

        self._parseCapFile(self.cap_file)

    def _parseCapFile(self, cap_file):
        """Parse capabilities data and emits capParsed signal
        (see class constructor).
        """
        try:
            self.cap = self.ws_drvs[self.ws]["cap_parser"](cap_file)
        except (IOError, ParseError) as error:
            error_msg = _(
                "%s web service was not found in fetched capabilities file from <%s>:\n%s\n"
                % (self.ws, self.conn["url"], str(error))
            )
            if Debug.GetLevel() != 0:
                Debug.msg(1, error_msg)
                self._postCapParsedEvt(None)
            else:
                self._postCapParsedEvt(error_msg=error_msg)
            return

        self.is_connected = True

        # WMS standard has formats defined for all layers
        if "WMS" in self.ws:
            self.formats_list = sorted(self._getFormats())
            self._updateFormatRadioBox(self.formats_list)
            self._setDefaultFormatVal()

        self.list.LoadData(self.cap)
        self.OnListSelChanged(event=None)

        self._postCapParsedEvt(None)

    def ParseCapFile(
        self,
        url,
        username,
        password,
        cap_file=None,
    ):
        """Parse capabilities data and emits capParsed signal
        (see class constructor).
        """
        self._prepareForNewConn(url, username, password)

        if cap_file is None or not url:
            self._postCapParsedEvt(None)
            return

        shutil.copyfile(cap_file, self.cap_file)

        self._parseCapFile(self.cap_file)

    def UpdateWidgetsByCmd(self, cmd):
        """Update panel widgets accordnig to passed cmd tuple

        :param cmd: cmd in tuple
        """

        dcmd = cmd[1]

        layers = []

        if "layers" in dcmd:
            layers = dcmd["layers"]

        styles = []
        if "styles" in dcmd:
            styles = dcmd["styles"]

        if "WMS" in self.ws:
            layers = layers.split(",")
            styles = styles.split(",")
        else:
            layers = [layers]
            styles = [styles]

        if len(layers) != len(styles):
            styles = [""] * len(layers)

        l_st_list = []
        for i in range(len(layers)):
            l_st_list.append({"style": styles[i], "layer": layers[i]})

        # WMS standard - first layer in params is most bottom...
        # therefore layers order need to be reversed
        l_st_list = [l for l in reversed(l_st_list)]
        self.list.SelectLayers(l_st_list)

        params = {}
        if "format" in dcmd:
            params["format"] = dcmd["format"]
        if "srs" in dcmd:
            params["srs"] = "EPSG:" + dcmd["srs"]
        if "method" in dcmd:
            params["method"] = dcmd["method"]

        for p, v in six.iteritems(params):
            if self.params[p]:
                self.params[p].SetStringSelection(v)

        for p, conv_f in [("urlparams", None), ("maxcols", int), ("maxrows", int)]:
            if p in dcmd:
                v = dcmd[p]
                if conv_f:
                    v = conv_f(v)
                self.params[p].SetValue(v)

        if "flags" in dcmd and "o" in dcmd["flags"]:
            self.flags["o"].SetValue(1)
            self.params["bgcolor"].Enable(True)

        if "bgcolor" in dcmd and self.params["bgcolor"]:
            bgcolor = dcmd["bgcolor"].strip().lower()
            if len(bgcolor) == 8 and "0x" == bgcolor[:2]:

                colour = "#" + bgcolor[2:]
                self.params["bgcolor"].SetColour(colour)

    def IsConnected(self):
        """Was successful in downloading and parsing capabilities data?"""
        return self.is_connected

    def _postCapParsedEvt(self, error_msg):
        """Helper function"""
        self.capParsed.emit(error_msg=error_msg)

    def CreateCmd(self):
        """Create d.wms cmd from values of panels widgets

        :return: cmd list
        :return: None if required widgets do not have selected/filled values.
        """

        # check required widgets
        if not self._checkImportValues():
            return None

        # create d.wms command
        lcmd = self.ws_cmdl
        lcmd = ["d.wms"] + lcmd

        layers = "layers="
        styles = "styles="
        first = True

        # WMS standard - first layer in params is most bottom...
        # therefore layers order need to be reversed
        for layer in reversed(self.sel_layers):
            if not first:
                layers += ","
                styles += ","
            first = False
            layers += layer["name"]
            if layer["style"] is not None:
                styles += layer["style"]["name"]

        lcmd.append(layers)
        lcmd.append(styles)

        if "format" not in self.drv_props["ignored_params"]:
            i_format = self.params["format"].GetSelection()
            lcmd.append("format=%s" % self.formats_list[i_format])

        if "srs" not in self.drv_props["ignored_params"]:
            i_srs = self.params["srs"].GetSelection()
            srs = self.projs_list[i_srs].split(":")[-1]
            epsg_num = int("".join(re.findall(r"\d+", srs)))

            lcmd.append("srs=%s" % epsg_num)

        for k in ["maxcols", "maxrows", "urlparams"]:
            lcmd.append(k + "=" + str(self.params[k].GetValue()))

        i_method = self.params["method"].GetSelection()
        lcmd.append("method=" + self.reproj_methods[i_method])

        if "o" not in self.drv_props["ignored_flags"] and self.flags["o"].IsChecked():
            lcmd.append("-o")

            c = self.params["bgcolor"].GetColour()
            hex_color = wx.Colour(c[0], c[1], c[2]).GetAsString(wx.C2S_HTML_SYNTAX)
            lcmd.append("bgcolor=" + "0x" + hex_color[1:])

        lcmd.append("map=" + self.o_layer_name)

        return lcmd

    def OnListSelChanged(self, event):
        """Update widgets according to selected layer in list."""
        curr_sel_ls = self.list.GetSelectedLayers()
        # update self.sel_layers (selected layer list)
        if "WMS" in self.ws:
            for sel_l in self.sel_layers[:]:
                if sel_l not in curr_sel_ls:
                    self.sel_layers.remove(sel_l)

            for l in curr_sel_ls:
                if l not in self.sel_layers:
                    self.sel_layers.append(l)

            self._updateLayerOrderList()
        else:
            self.sel_layers = curr_sel_ls

        # update projection

        self.projs_list = []
        projs_list = []

        intersect_proj = []
        first = True
        for l in curr_sel_ls:
            layer_projs = l["cap_intf_l"].GetLayerData("srs")
            if first:
                projs_list = layer_projs
                first = False
                continue

            projs_list = set(projs_list).intersection(layer_projs)

        if "srs" not in self.drv_props["ignored_params"]:

            for proj in projs_list:
                proj_code = Srs(proj.strip()).getcode()
                proj_spl = proj_code.split(":")
                if proj_spl[0].strip().lower() in self.drv_info.GetSrs():
                    # accept ogc:crs code
                    self.projs_list.append(proj_code)

            cur_sel = self.params["srs"].GetStringSelection()

            self.projs_list = sorted(self.projs_list)
            self.params["srs"].SetItems(self.projs_list)

            if cur_sel:
                self.params["srs"].SetStringSelection(cur_sel)
            else:
                try:
                    i = self.projs_list.index("EPSG:4326")
                    self.params["srs"].SetSelection(i)
                except ValueError:
                    if len(self.projs_list) > 0:
                        self.params["srs"].SetSelection(0)

        # update format

        if "WMS" not in self.ws and "format" not in self.drv_props["ignored_params"]:
            self.formats_list = []
            cur_sel = None

            if self.params["format"]:
                cur_sel = self.params["format"].GetStringSelection()

            if len(curr_sel_ls) > 0:
                self.formats_list = sorted(
                    self._getFormats(curr_sel_ls[0]["cap_intf_l"])
                )
                self._updateFormatRadioBox(self.formats_list)

                if cur_sel:
                    if self.params["format"]:
                        self.params["format"].SetStringSelection(cur_sel)
                else:
                    self._setDefaultFormatVal()

        self.Layout()

    def _setDefaultFormatVal(self):
        """Set default format value."""
        try:
            i = self.formats_list.index("png")
            self.params["format"].SetSelection(i)
        except ValueError:
            pass

    def _updateFormatRadioBox(self, formats_list):
        """Helper function"""
        if self.params["format"]:
            self.req_page_sizer.Detach(self.params["format"])
            self.params["format"].Destroy()
        if len(self.formats_list) > 0:
            self.params["format"] = wx.RadioBox(
                parent=self.req_page_panel,
                id=wx.ID_ANY,
                label=_("Source image format"),
                pos=wx.DefaultPosition,
                choices=formats_list,
                majorDimension=4,
                style=wx.RA_SPECIFY_COLS,
            )
            self.source_sizer.Insert(
                2,
                window=self.params["format"],
                flag=wx.LEFT | wx.RIGHT | wx.BOTTOM,
                border=5,
            )

    def _getFormats(self, layer=None):
        """Get formats

        WMS has formats defined generally for whole cap.
        In WMTS and NASA OnEarh formats are defined for layer.
        """
        formats_label = []
        if layer is None:
            formats_list = self.cap.GetFormats()
        else:
            formats_list = layer.GetLayerData("format")

        for frmt in formats_list:
            frmt = frmt.strip()
            label = self.drv_info.GetFormatLabel(frmt)

            if label:
                formats_label.append(label)

        return formats_label

    def _checkImportValues(
        self,
    ):
        """Check if required widgets are selected/filled"""
        warning_str = ""
        show_war = False
        if not self.list or not self.list.GetSelectedLayers():
            warning_str += _("Select layer in layer list.\n")
            show_war = True

        if (
            self.params["format"] is not None
            and self.params["format"].GetSelection() == -1
        ):
            warning_str += _("Select source image format.\n")
            show_war = True

        if self.params["srs"] is not None and self.params["srs"].GetSelection() == -1:
            warning_str += _("Select source projection.\n")
            show_war = True

        if not self.o_layer_name:
            warning_str += _("Choose output layer name.\n")
            show_war = True

        if show_war:
            GMessage(parent=self.parent, message=warning_str)
            return False

        return True

    def SetOutputLayerName(self, name):
        """Set name of layer to be added to layer tree"""
        self.o_layer_name = name

    def GetOutputLayerName(self):
        return self.o_layer_name

    def GetCapFile(self):
        """Get path to file where capabilities are saved"""
        return self.cap_file

    def GetWebService(self):
        """Get web service"""
        return self.ws
Exemple #45
0
class GPromptSTC(GPrompt, wx.stc.StyledTextCtrl):
    """Styled wxGUI prompt with autocomplete and calltips"""
    def __init__(self, parent, giface, menuModel, margin=False):
        GPrompt.__init__(self,
                         parent=parent,
                         giface=giface,
                         menuModel=menuModel)
        wx.stc.StyledTextCtrl.__init__(self, self.panel, id=wx.ID_ANY)

        #
        # styles
        #
        self.SetWrapMode(True)
        self.SetUndoCollection(True)

        #
        # create command and map lists for autocompletion
        #
        self.AutoCompSetIgnoreCase(False)

        #
        # line margins
        #
        # TODO print number only from cmdlog
        self.SetMarginWidth(1, 0)
        self.SetMarginWidth(2, 0)
        if margin:
            self.SetMarginType(0, wx.stc.STC_MARGIN_NUMBER)
            self.SetMarginWidth(0, 30)
        else:
            self.SetMarginWidth(0, 0)

        #
        # miscellaneous
        #
        self.SetViewWhiteSpace(False)
        self.SetUseTabs(False)
        self.UsePopUp(True)
        self.SetUseHorizontalScrollBar(True)

        # support light and dark mode
        bg_color = wx.SystemSettings().GetColour(wx.SYS_COLOUR_WINDOW)
        fg_color = wx.SystemSettings().GetColour(wx.SYS_COLOUR_WINDOWTEXT)
        selection_color = wx.SystemSettings().GetColour(
            wx.SYS_COLOUR_HIGHLIGHT)
        self.StyleSetBackground(wx.stc.STC_STYLE_DEFAULT, bg_color)
        self.StyleSetForeground(wx.stc.STC_STYLE_DEFAULT, fg_color)
        self.SetCaretForeground(fg_color)
        self.SetSelBackground(True, selection_color)
        self.StyleClearAll()

        #
        # bindings
        #
        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
        self.Bind(wx.EVT_CHAR, self.OnChar)
        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
        self.Bind(wx.stc.EVT_STC_AUTOCOMP_SELECTION, self.OnItemSelected)
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemChanged)
        if sys.platform != "darwin":  # unstable on Mac with wxPython 3
            self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)

        # signal which requests showing of a notification
        self.showNotification = Signal("GPromptSTC.showNotification")

        # signal to notify selected command
        self.commandSelected = Signal("GPromptSTC.commandSelected")

    def OnTextSelectionChanged(self, event):
        """Copy selected text to clipboard and skip event.
        The same function is in GStc class (goutput.py).
        """
        wx.CallAfter(self.Copy)
        event.Skip()

    def OnItemChanged(self, event):
        """Change text in statusbar
        if the item selection in the auto-completion list is changed"""
        # list of commands
        if self.toComplete["entity"] == "command":
            item = (self.toComplete["cmd"].rpartition(".")[0] + "." +
                    self.autoCompList[event.GetIndex()])
            try:
                nodes = self._menuModel.SearchNodes(key="command", value=item)
                desc = ""
                if nodes:
                    self.commandSelected.emit(command=item)
                    desc = nodes[0].data["description"]
            except KeyError:
                desc = ""
            self.ShowStatusText(desc)
        # list of flags
        elif self.toComplete["entity"] == "flags":
            desc = self.cmdDesc.get_flag(
                self.autoCompList[event.GetIndex()])["description"]
            self.ShowStatusText(desc)
        # list of parameters
        elif self.toComplete["entity"] == "params":
            item = self.cmdDesc.get_param(self.autoCompList[event.GetIndex()])
            desc = item["name"] + "=" + item["type"]
            if not item["required"]:
                desc = "[" + desc + "]"
            desc += ": " + item["description"]
            self.ShowStatusText(desc)
        # list of flags and commands
        elif self.toComplete["entity"] == "params+flags":
            if self.autoCompList[event.GetIndex()][0] == "-":
                desc = self.cmdDesc.get_flag(self.autoCompList[
                    event.GetIndex()].strip("-"))["description"]
            else:
                item = self.cmdDesc.get_param(
                    self.autoCompList[event.GetIndex()])
                desc = item["name"] + "=" + item["type"]
                if not item["required"]:
                    desc = "[" + desc + "]"
                desc += ": " + item["description"]
            self.ShowStatusText(desc)
        else:
            self.ShowStatusText("")

    def OnItemSelected(self, event):
        """Item selected from the list"""
        lastWord = self.GetWordLeft()
        # to insert selection correctly if selected word partly matches written
        # text
        match = difflib.SequenceMatcher(None, event.GetText(), lastWord)
        matchTuple = match.find_longest_match(0, len(event.GetText()), 0,
                                              len(lastWord))

        compl = event.GetText()[matchTuple[2]:]
        text = self.GetTextLeft() + compl
        # add space or '=' at the end
        end = "="
        for char in (".", "-", "="):
            if text.split(" ")[-1].find(char) >= 0:
                end = " "

        compl += end
        text += end

        self.AddText(compl)
        pos = len(text)
        self.SetCurrentPos(pos)

        cmd = text.strip().split(" ")[0]

        if not self.cmdDesc or cmd != self.cmdDesc.get_name():
            try:
                self.cmdDesc = gtask.parse_interface(cmd)
            except IOError:
                self.cmdDesc = None

    def OnKillFocus(self, event):
        """Hides autocomplete"""
        # hide autocomplete
        if self.AutoCompActive():
            self.AutoCompCancel()
        event.Skip()

    def SetTextAndFocus(self, text):
        pos = len(text)
        self.commandSelected.emit(command=text)
        self.SetText(text)
        self.SetSelectionStart(pos)
        self.SetCurrentPos(pos)
        self.SetFocus()

    def UpdateCmdHistory(self, cmd):
        """Update command history

        :param cmd: command given as a string
        """
        # add command to history
        self.cmdbuffer.append(cmd)
        # update also traced commands
        self.commands.append(cmd)

        # keep command history to a manageable size
        if len(self.cmdbuffer) > 200:
            del self.cmdbuffer[0]
        self.cmdindex = len(self.cmdbuffer)

    def EntityToComplete(self):
        """Determines which part of command (flags, parameters) should
        be completed at current cursor position"""
        entry = self.GetTextLeft()
        toComplete = dict(cmd=None, entity=None)
        try:
            cmd = entry.split()[0].strip()
        except IndexError:
            return toComplete

        try:
            splitted = utils.split(str(entry))
        except ValueError:  # No closing quotation error
            return toComplete
        if len(splitted) > 0 and cmd in globalvar.grassCmd:
            toComplete["cmd"] = cmd
            if entry[-1] == " ":
                words = entry.split(" ")
                if any(word.startswith("-") for word in words):
                    toComplete["entity"] = "params"
                else:
                    toComplete["entity"] = "params+flags"
            else:
                # get word left from current position
                word = self.GetWordLeft(withDelimiter=True)

                if word[0] == "=" and word[-1] == "@":
                    toComplete["entity"] = "mapsets"
                elif word[0] == "=":
                    # get name of parameter
                    paramName = self.GetWordLeft(
                        withDelimiter=False, ignoredDelimiter="=").strip("=")
                    if paramName:
                        try:
                            param = self.cmdDesc.get_param(paramName)
                        except (ValueError, AttributeError):
                            return toComplete
                    else:
                        return toComplete

                    if param["values"]:
                        toComplete["entity"] = "param values"
                    elif param["prompt"] == "raster" and param[
                            "element"] == "cell":
                        toComplete["entity"] = "raster map"
                    elif param["prompt"] == "vector" and param[
                            "element"] == "vector":
                        toComplete["entity"] = "vector map"
                elif word[0] == "-":
                    toComplete["entity"] = "flags"
                elif word[0] == " ":
                    toComplete["entity"] = "params"
        else:
            toComplete["entity"] = "command"
            toComplete["cmd"] = cmd

        return toComplete

    def GetWordLeft(self, withDelimiter=False, ignoredDelimiter=None):
        """Get word left from current cursor position. The beginning
        of the word is given by space or chars: .,-=

        :param withDelimiter: returns the word with the initial delimeter
        :param ignoredDelimiter: finds the word ignoring certain delimeter
        """
        textLeft = self.GetTextLeft()

        parts = list()
        if ignoredDelimiter is None:
            ignoredDelimiter = ""

        for char in set(" .,-=") - set(ignoredDelimiter):
            if not withDelimiter:
                delimiter = ""
            else:
                delimiter = char
            parts.append(delimiter + textLeft.rpartition(char)[2])
        return min(parts, key=lambda x: len(x))

    def ShowList(self):
        """Show sorted auto-completion list if it is not empty"""
        if len(self.autoCompList) > 0:
            self.autoCompList.sort()
            self.AutoCompShow(0, itemList=" ".join(self.autoCompList))

    def OnKeyPressed(self, event):
        """Key pressed capture special treatment for tabulator to show help"""
        pos = self.GetCurrentPos()
        if event.GetKeyCode() == wx.WXK_TAB:
            # show GRASS command calltips (to hide press 'ESC')
            entry = self.GetTextLeft()
            try:
                cmd = entry.split()[0].strip()
            except IndexError:
                cmd = ""

            if cmd not in globalvar.grassCmd:
                return

            info = gtask.command_info(cmd)

            self.CallTipSetBackground("#f4f4d1")
            self.CallTipSetForeground("BLACK")
            self.CallTipShow(pos, info["usage"] + "\n\n" + info["description"])
        elif (event.GetKeyCode() in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER)
              and not self.AutoCompActive()):
            # run command on line when <return> is pressed
            self._runCmd(self.GetCurLine()[0].strip())
        elif (event.GetKeyCode() in [wx.WXK_UP, wx.WXK_DOWN]
              and not self.AutoCompActive()):
            # Command history using up and down
            if len(self.cmdbuffer) < 1:
                return

            self.DocumentEnd()

            # move through command history list index values
            if event.GetKeyCode() == wx.WXK_UP:
                self.cmdindex = self.cmdindex - 1
            if event.GetKeyCode() == wx.WXK_DOWN:
                self.cmdindex = self.cmdindex + 1
            if self.cmdindex < 0:
                self.cmdindex = 0
            if self.cmdindex > len(self.cmdbuffer) - 1:
                self.cmdindex = len(self.cmdbuffer) - 1

            try:
                # without strip causes problem on windows
                txt = self.cmdbuffer[self.cmdindex].strip()
            except KeyError:
                txt = ""

            # clear current line and insert command history
            self.DelLineLeft()
            self.DelLineRight()
            pos = self.GetCurrentPos()
            self.InsertText(pos, txt)
            self.LineEnd()

            self.ShowStatusText("")
        else:
            event.Skip()

    def OnChar(self, event):
        """Key char capture for autocompletion, calltips, and command history

        .. todo::
            event.ControlDown() for manual autocomplete
        """
        # keycodes used: "." = 46, "=" = 61, "-" = 45
        pos = self.GetCurrentPos()
        # complete command after pressing '.'
        if event.GetKeyCode() == 46:
            self.autoCompList = list()
            entry = self.GetTextLeft()
            self.InsertText(pos, ".")
            self.CharRight()
            self.toComplete = self.EntityToComplete()
            try:
                if self.toComplete["entity"] == "command":
                    for command in globalvar.grassCmd:
                        try:
                            if command.find(self.toComplete["cmd"]) == 0:
                                dotNumber = list(
                                    self.toComplete["cmd"]).count(".")
                                self.autoCompList.append(
                                    command.split(".", dotNumber)[-1])
                        except UnicodeDecodeError as error:
                            sys.stderr.write(
                                DecodeString(command) + ": " + str(error))

            except (KeyError, TypeError):
                return
            self.ShowList()

        # complete flags after pressing '-'
        elif ((event.GetKeyCode() == 45)
              or event.GetKeyCode() == wx.WXK_NUMPAD_SUBTRACT
              or event.GetKeyCode() == wx.WXK_SUBTRACT):
            self.autoCompList = list()
            entry = self.GetTextLeft()
            self.InsertText(pos, "-")
            self.CharRight()
            self.toComplete = self.EntityToComplete()
            if self.toComplete["entity"] == "flags" and self.cmdDesc:
                if self.GetTextLeft()[-2:] == " -":  # complete e.g. --quite
                    for flag in self.cmdDesc.get_options()["flags"]:
                        if len(flag["name"]) == 1:
                            self.autoCompList.append(flag["name"])
                else:
                    for flag in self.cmdDesc.get_options()["flags"]:
                        if len(flag["name"]) > 1:
                            self.autoCompList.append(flag["name"])
            self.ShowList()

        # complete map or values after parameter
        elif event.GetKeyCode() == 61:
            self.autoCompList = list()
            self.InsertText(pos, "=")
            self.CharRight()
            self.toComplete = self.EntityToComplete()
            if self.toComplete["entity"] == "raster map":
                self.autoCompList = self.mapList["raster"]
            elif self.toComplete["entity"] == "vector map":
                self.autoCompList = self.mapList["vector"]
            elif self.toComplete["entity"] == "param values":
                param = self.GetWordLeft(withDelimiter=False,
                                         ignoredDelimiter="=").strip(" =")
                self.autoCompList = self.cmdDesc.get_param(param)["values"]
            self.ShowList()

        # complete mapset ('@')
        elif event.GetKeyCode() == 64:
            self.autoCompList = list()
            self.InsertText(pos, "@")
            self.CharRight()
            self.toComplete = self.EntityToComplete()

            if self.toComplete["entity"] == "mapsets":
                self.autoCompList = self.mapsetList
            self.ShowList()

        # complete after pressing CTRL + Space
        elif event.GetKeyCode() == wx.WXK_SPACE and event.ControlDown():
            self.autoCompList = list()
            self.toComplete = self.EntityToComplete()

            # complete command
            if self.toComplete["entity"] == "command":
                for command in globalvar.grassCmd:
                    if command.find(self.toComplete["cmd"]) == 0:
                        dotNumber = list(self.toComplete["cmd"]).count(".")
                        self.autoCompList.append(
                            command.split(".", dotNumber)[-1])

            # complete flags in such situations (| is cursor):
            # r.colors -| ...w, q, l
            # r.colors -w| ...w, q, l
            elif self.toComplete["entity"] == "flags" and self.cmdDesc:
                for flag in self.cmdDesc.get_options()["flags"]:
                    if len(flag["name"]) == 1:
                        self.autoCompList.append(flag["name"])

            # complete parameters in such situations (| is cursor):
            # r.colors -w | ...color, map, rast, rules
            # r.colors col| ...color
            elif self.toComplete["entity"] == "params" and self.cmdDesc:
                for param in self.cmdDesc.get_options()["params"]:
                    if param["name"].find(
                            self.GetWordLeft(withDelimiter=False)) == 0:
                        self.autoCompList.append(param["name"])

            # complete flags or parameters in such situations (| is cursor):
            # r.colors | ...-w, -q, -l, color, map, rast, rules
            # r.colors color=grey | ...-w, -q, -l, color, map, rast, rules
            elif self.toComplete["entity"] == "params+flags" and self.cmdDesc:
                self.autoCompList = list()

                for param in self.cmdDesc.get_options()["params"]:
                    self.autoCompList.append(param["name"])
                for flag in self.cmdDesc.get_options()["flags"]:
                    if len(flag["name"]) == 1:
                        self.autoCompList.append("-" + flag["name"])
                    else:
                        self.autoCompList.append("--" + flag["name"])

                self.ShowList()

            # complete map or values after parameter
            # r.buffer input=| ...list of raster maps
            # r.buffer units=| ... feet, kilometers, ...
            elif self.toComplete["entity"] == "raster map":
                self.autoCompList = list()
                self.autoCompList = self.mapList["raster"]
            elif self.toComplete["entity"] == "vector map":
                self.autoCompList = list()
                self.autoCompList = self.mapList["vector"]
            elif self.toComplete["entity"] == "param values":
                self.autoCompList = list()
                param = self.GetWordLeft(withDelimiter=False,
                                         ignoredDelimiter="=").strip(" =")
                self.autoCompList = self.cmdDesc.get_param(param)["values"]

            self.ShowList()

        elif event.GetKeyCode() == wx.WXK_SPACE:
            items = self.GetTextLeft().split()
            if len(items) == 1:
                cmd = items[0].strip()
                if cmd in globalvar.grassCmd and (
                        not self.cmdDesc or cmd != self.cmdDesc.get_name()):
                    try:
                        self.cmdDesc = gtask.parse_interface(cmd)
                    except IOError:
                        self.cmdDesc = None
            event.Skip()

        else:
            event.Skip()

    def ShowStatusText(self, text):
        """Requests showing of notification, e.g. showing in a statusbar."""
        self.showNotification.emit(message=text)

    def GetTextLeft(self):
        """Returns all text left of the caret"""
        pos = self.GetCurrentPos()
        self.HomeExtend()
        entry = self.GetSelectedText()
        self.SetCurrentPos(pos)

        return entry

    def OnDestroy(self, event):
        """The clipboard contents can be preserved after
        the app has exited"""
        if wx.TheClipboard.IsOpened():
            wx.TheClipboard.Flush()
        event.Skip()

    def OnCmdErase(self, event):
        """Erase command prompt"""
        self.Home()
        self.DelLineRight()
Exemple #46
0
    def __init__(self, parent, web_service, **kwargs):
        """Show data from capabilities file.

        Signal: capParsed - this signal is emitted when capabilities file is downloaded
                            (after ConnectToServer method was called)

        :param parent:  parent widget
        :param web_service:  web service to be panel generated for
        """
        wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY)

        self.parent = parent
        self.ws = web_service

        self.capParsed = Signal("WSPanel.capParsed")

        # stores widgets, which represents parameters/flags of d.wms
        self.params = {}
        self.flags = {}

        self.o_layer_name = ""

        # stores err output from r.in.wms during getting capabilities
        self.cmd_err_str = ""

        # stores selected layer from layer list
        self.sel_layers = []

        # downloaded and parsed data from server successfully?
        self.is_connected = False

        # common part of command for r.in.wms -c and d.wms
        self.ws_cmdl = None

        # provides information about driver parameters
        self.drv_info = WMSDriversInfo()
        self.drv_props = self.drv_info.GetDrvProperties(self.ws)

        self.ws_drvs = {
            "WMS_1.1.1": {
                "cmd": ["wms_version=1.1.1", "driver=WMS_GRASS"],
                "cap_parser": lambda temp_file: WMSCapabilities(temp_file, "1.1.1"),
            },
            "WMS_1.3.0": {
                "cmd": ["wms_version=1.3.0", "driver=WMS_GRASS"],
                "cap_parser": lambda temp_file: WMSCapabilities(temp_file, "1.3.0"),
            },
            "WMTS": {
                "cmd": ["driver=WMTS_GRASS"],
                "cap_parser": WMTSCapabilities,
            },
            "OnEarth": {
                "cmd": ["driver=OnEarth_GRASS"],
                "cap_parser": OnEarthCapabilities,
            },
        }

        self.cmdStdErr = GStderr(self)
        self.cmd_thread = CmdThread(self)
        self.cap_file = grass.tempfile()

        reqDataBox = StaticBox(parent=self, label=_(" Requested data settings "))
        self._nb_sizer = wx.StaticBoxSizer(reqDataBox, wx.VERTICAL)
        self.notebook = GNotebook(
            parent=self, style=FN.FNB_FANCY_TABS | FN.FNB_NO_X_BUTTON | FN.FNB_NODRAG
        )

        self._requestPage()
        self._advancedSettsPage()

        self._layout()

        self.layerSelected = self.list.layerSelected

        self.Bind(EVT_CMD_DONE, self.OnCapDownloadDone)
        self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)

        self.SetMinSize((-1, 300))
Exemple #47
0
class ScatterPlotWidget(wx.Panel, ManageBusyCursorMixin):
    def __init__(self, parent, scatt_id, scatt_mgr, transpose, id=wx.ID_ANY):
        # TODO should not be transpose and scatt_id but x, y
        wx.Panel.__init__(self, parent, id)
        # bacause of aui (if floatable it can not take cursor from parent)
        ManageBusyCursorMixin.__init__(self, window=self)

        self.parent = parent
        self.full_extend = None
        self.mode = None

        self._createWidgets()
        self._doLayout()
        self.scatt_id = scatt_id
        self.scatt_mgr = scatt_mgr

        self.cidpress = None
        self.cidrelease = None

        self.rend_dt = {}

        self.transpose = transpose

        self.inverse = False

        self.SetSize((200, 100))
        self.Layout()

        self.base_scale = 1.2
        self.Bind(wx.EVT_CLOSE, lambda event: self.CleanUp())

        self.plotClosed = Signal("ScatterPlotWidget.plotClosed")
        self.cursorMove = Signal("ScatterPlotWidget.cursorMove")

        self.contex_menu = ScatterPlotContextMenu(plot=self)

        self.ciddscroll = None

        self.canvas.mpl_connect("motion_notify_event", self.Motion)
        self.canvas.mpl_connect("button_press_event", self.OnPress)
        self.canvas.mpl_connect("button_release_event", self.OnRelease)
        self.canvas.mpl_connect("draw_event", self.DrawCallback)
        self.canvas.mpl_connect("figure_leave_event", self.OnCanvasLeave)

    def DrawCallback(self, event):
        self.polygon_drawer.DrawCallback(event)
        self.axes.draw_artist(self.zoom_rect)

    def _createWidgets(self):

        # Create the mpl Figure and FigCanvas objects.
        # 5x4 inches, 100 dots-per-inch
        #
        self.dpi = 100
        self.fig = Figure((1.0, 1.0), dpi=self.dpi)
        self.fig.autolayout = True

        self.canvas = FigCanvas(self, -1, self.fig)

        self.axes = self.fig.add_axes([0.0, 0.0, 1, 1])

        pol = Polygon(list(zip([0], [0])), animated=True)
        self.axes.add_patch(pol)
        self.polygon_drawer = PolygonDrawer(self.axes, pol=pol, empty_pol=True)

        self.zoom_wheel_coords = None
        self.zoom_rect_coords = None
        self.zoom_rect = Polygon(list(zip([0], [0])), facecolor="none")
        self.zoom_rect.set_visible(False)
        self.axes.add_patch(self.zoom_rect)

    def ZoomToExtend(self):
        if self.full_extend:
            self.axes.axis(self.full_extend)
            self.canvas.draw()

    def SetMode(self, mode):
        self._deactivateMode()
        if mode == "zoom":
            self.ciddscroll = self.canvas.mpl_connect("scroll_event",
                                                      self.ZoomWheel)
            self.mode = "zoom"
        elif mode == "zoom_extend":
            self.mode = "zoom_extend"
        elif mode == "pan":
            self.mode = "pan"
        elif mode:
            self.polygon_drawer.SetMode(mode)

    def SetSelectionPolygonMode(self, activate):
        self.polygon_drawer.SetSelectionPolygonMode(activate)

    def _deactivateMode(self):
        self.mode = None
        self.polygon_drawer.SetMode(None)

        if self.ciddscroll:
            self.canvas.mpl_disconnect(self.ciddscroll)

        self.zoom_rect.set_visible(False)
        self._stopCategoryEdit()

    def GetCoords(self):

        coords = self.polygon_drawer.GetCoords()
        if coords is None:
            return

        if self.transpose:
            for c in coords:
                tmp = c[0]
                c[0] = c[1]
                c[1] = tmp

        return coords

    def SetEmpty(self):
        return self.polygon_drawer.SetEmpty()

    def OnRelease(self, event):
        if not self.mode == "zoom":
            return
        self.zoom_rect.set_visible(False)
        self.ZoomRectangle(event)
        self.canvas.draw()

    def OnPress(self, event):
        "on button press we will see if the mouse is over us and store some data"
        if not event.inaxes:
            return
        if self.mode == "zoom_extend":
            self.ZoomToExtend()

        if event.xdata and event.ydata:
            self.zoom_wheel_coords = {"x": event.xdata, "y": event.ydata}
            self.zoom_rect_coords = {"x": event.xdata, "y": event.ydata}
        else:
            self.zoom_wheel_coords = None
            self.zoom_rect_coords = None

    def _stopCategoryEdit(self):
        "disconnect all the stored connection ids"

        if self.cidpress:
            self.canvas.mpl_disconnect(self.cidpress)
        if self.cidrelease:
            self.canvas.mpl_disconnect(self.cidrelease)
        # self.canvas.mpl_disconnect(self.cidmotion)

    def _doLayout(self):

        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
        self.main_sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        self.SetSizer(self.main_sizer)
        self.main_sizer.Fit(self)

    def Plot(self, cats_order, scatts, ellipses, styles):
        """Redraws the figure"""

        callafter_list = []

        if self.full_extend:
            cx = self.axes.get_xlim()
            cy = self.axes.get_ylim()
            c = cx + cy
        else:
            c = None

        q = Queue()
        _rendDtMemmapsToFiles(self.rend_dt)
        p = Process(target=MergeImg,
                    args=(cats_order, scatts, styles, self.rend_dt, q))
        p.start()
        merged_img, self.full_extend, self.rend_dt = q.get()
        p.join()

        _rendDtFilesToMemmaps(self.rend_dt)
        merged_img = np.memmap(filename=merged_img["dt"],
                               shape=merged_img["sh"])

        # merged_img, self.full_extend = MergeImg(cats_order, scatts, styles, None)
        self.axes.clear()
        self.axes.axis("equal")

        if self.transpose:
            merged_img = np.transpose(merged_img, (1, 0, 2))

        img = imshow(
            self.axes,
            merged_img,
            extent=[int(ceil(x)) for x in self.full_extend],
            origin="lower",
            interpolation="nearest",
            aspect="equal",
        )

        callafter_list.append([self.axes.draw_artist, [img]])
        callafter_list.append([grass.try_remove, [merged_img.filename]])

        for cat_id in cats_order:
            if cat_id == 0:
                continue
            if cat_id not in ellipses:
                continue

            e = ellipses[cat_id]
            if not e:
                continue

            colors = styles[cat_id]["color"].split(":")
            if self.transpose:
                e["theta"] = 360 - e["theta"] + 90
                if e["theta"] >= 360:
                    e["theta"] = abs(360 - e["theta"])

                e["pos"] = [e["pos"][1], e["pos"][0]]

            ellip = Ellipse(
                xy=e["pos"],
                width=e["width"],
                height=e["height"],
                angle=e["theta"],
                edgecolor="w",
                linewidth=1.5,
                facecolor="None",
            )
            self.axes.add_artist(ellip)
            callafter_list.append([self.axes.draw_artist, [ellip]])

            color = [
                int(v) / 255.0 for v in styles[cat_id]["color"].split(":")[:3]
            ]

            ellip = Ellipse(
                xy=e["pos"],
                width=e["width"],
                height=e["height"],
                angle=e["theta"],
                edgecolor=color,
                linewidth=1,
                facecolor="None",
            )

            self.axes.add_artist(ellip)
            callafter_list.append([self.axes.draw_artist, [ellip]])

            center = Line2D(
                [e["pos"][0]],
                [e["pos"][1]],
                marker="x",
                markeredgecolor="w",
                # markerfacecolor=color,
                markersize=2,
            )
            self.axes.add_artist(center)
            callafter_list.append([self.axes.draw_artist, [center]])

        callafter_list.append([self.fig.canvas.blit, []])

        if c:
            self.axes.axis(c)
        wx.CallAfter(lambda: self.CallAfter(callafter_list))

    def CallAfter(self, funcs_list):
        while funcs_list:
            fcn, args = funcs_list.pop(0)
            fcn(*args)

        self.canvas.draw()

    def CleanUp(self):
        self.plotClosed.emit(scatt_id=self.scatt_id)
        self.Destroy()

    def ZoomWheel(self, event):
        # get the current x and y limits
        if not event.inaxes:
            return
        # tcaswell
        # http://stackoverflow.com/questions/11551049/matplotlib-plot-zooming-with-scroll-wheel
        cur_xlim = self.axes.get_xlim()
        cur_ylim = self.axes.get_ylim()

        xdata = event.xdata
        ydata = event.ydata
        if event.button == "up":
            scale_factor = 1 / self.base_scale
        elif event.button == "down":
            scale_factor = self.base_scale
        else:
            scale_factor = 1

        extend = (
            xdata - (xdata - cur_xlim[0]) * scale_factor,
            xdata + (cur_xlim[1] - xdata) * scale_factor,
            ydata - (ydata - cur_ylim[0]) * scale_factor,
            ydata + (cur_ylim[1] - ydata) * scale_factor,
        )

        self.axes.axis(extend)

        self.canvas.draw()

    def ZoomRectangle(self, event):
        # get the current x and y limits
        if not self.mode == "zoom":
            return
        if event.inaxes is None:
            return
        if event.button != 1:
            return

        cur_xlim = self.axes.get_xlim()
        cur_ylim = self.axes.get_ylim()

        x1, y1 = event.xdata, event.ydata
        x2 = deepcopy(self.zoom_rect_coords["x"])
        y2 = deepcopy(self.zoom_rect_coords["y"])

        if x1 == x2 or y1 == y2:
            return

        if x1 > x2:
            tmp = x1
            x1 = x2
            x2 = tmp

        if y1 > y2:
            tmp = y1
            y1 = y2
            y2 = tmp

        self.axes.axis((x1, x2, y1, y2))
        # self.axes.set_xlim(x1, x2)#, auto = True)
        # self.axes.set_ylim(y1, y2)#, auto = True)
        self.canvas.draw()

    def Motion(self, event):
        self.PanMotion(event)
        self.ZoomRectMotion(event)

        if event.inaxes is None:
            return

        self.cursorMove.emit(x=event.xdata,
                             y=event.ydata,
                             scatt_id=self.scatt_id)

    def OnCanvasLeave(self, event):
        self.cursorMove.emit(x=None, y=None, scatt_id=self.scatt_id)

    def PanMotion(self, event):
        "on mouse movement"
        if not self.mode == "pan":
            return
        if event.inaxes is None:
            return
        if event.button != 1:
            return

        cur_xlim = self.axes.get_xlim()
        cur_ylim = self.axes.get_ylim()

        x, y = event.xdata, event.ydata

        mx = (x - self.zoom_wheel_coords["x"]) * 0.6
        my = (y - self.zoom_wheel_coords["y"]) * 0.6

        extend = (
            cur_xlim[0] - mx,
            cur_xlim[1] - mx,
            cur_ylim[0] - my,
            cur_ylim[1] - my,
        )

        self.zoom_wheel_coords["x"] = x
        self.zoom_wheel_coords["y"] = y

        self.axes.axis(extend)

        # self.canvas.copy_from_bbox(self.axes.bbox)
        # self.canvas.restore_region(self.background)
        self.canvas.draw()

    def ZoomRectMotion(self, event):
        if not self.mode == "zoom":
            return
        if event.inaxes is None:
            return
        if event.button != 1:
            return

        x1, y1 = event.xdata, event.ydata
        self.zoom_rect.set_visible(True)
        x2 = self.zoom_rect_coords["x"]
        y2 = self.zoom_rect_coords["y"]

        self.zoom_rect.xy = ((x1, y1), (x1, y2), (x2, y2), (x2, y1), (x1, y1))

        # self.axes.draw_artist(self.zoom_rect)
        self.canvas.draw()