From landa at grass.itc.it Thu Nov 1 17:20:31 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Thu Nov 1 17:20:32 2007 Subject: [grass-addons] r1173 - trunk/grassaddons/gui Message-ID: <200711011620.lA1GKVrh014715@grass.itc.it> Author: landa Date: 2007-11-01 17:20:27 +0100 (Thu, 01 Nov 2007) New Revision: 1173 Modified: trunk/grassaddons/gui/README Log: grass 6.3 required Modified: trunk/grassaddons/gui/README =================================================================== --- trunk/grassaddons/gui/README 2007-10-31 08:01:57 UTC (rev 1172) +++ trunk/grassaddons/gui/README 2007-11-01 16:20:27 UTC (rev 1173) @@ -3,7 +3,9 @@ 0 - REQUIREMENTS - Python >= 2.4 and wxPython >= 2.8.1.1 + GRASS GIS >= 6.3 + Python >= 2.4 + wxPython >= 2.8.1.1 Get wxPython 2.8.x packages from: * Source: http://www.wxpython.org/download.php From landa at grass.itc.it Sun Nov 4 13:39:17 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Sun Nov 4 13:39:19 2007 Subject: [grass-addons] r1174 - trunk/grassaddons/gui/gui_modules Message-ID: <200711041239.lA4CdHe8011006@grass.itc.it> Author: landa Date: 2007-11-04 13:39:13 +0100 (Sun, 04 Nov 2007) New Revision: 1174 Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py Log: Minor bugfix in overlay Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-11-01 16:20:27 UTC (rev 1173) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-11-04 12:39:13 UTC (rev 1174) @@ -3112,7 +3112,7 @@ """ # display properties dialog (modal mode) - menuform.GUI().ParseCommand(self.ovlcmd, gmpath, + menuform.GUI().ParseCommand([self.ovlcmd], gmpath, completed=(self.parent.GetOptData, self.ovltype, self.params), parentframe=self, modal=True) From neteler at grass.itc.it Sun Nov 4 13:58:33 2007 From: neteler at grass.itc.it (neteler@grass.itc.it) Date: Sun Nov 4 13:58:35 2007 Subject: [grass-addons] r1175 - trunk/grassaddons Message-ID: <200711041258.lA4CwXrA012031@grass.itc.it> Author: neteler Date: 2007-11-04 13:58:31 +0100 (Sun, 04 Nov 2007) New Revision: 1175 Modified: trunk/grassaddons/contributors.csv Log: +Brad Douglas Modified: trunk/grassaddons/contributors.csv =================================================================== --- trunk/grassaddons/contributors.csv 2007-11-04 12:39:13 UTC (rev 1174) +++ trunk/grassaddons/contributors.csv 2007-11-04 12:58:31 UTC (rev 1175) @@ -1,5 +1,6 @@ barton,Michael Barton bergenheim,Wolf Bergenheim +bradd,Brad Douglas bundala,Daniel Bundala calvelo,Daniel Calvelo Aros cannata,Massimiliano Cannata From neteler at grass.itc.it Sun Nov 4 14:00:48 2007 From: neteler at grass.itc.it (neteler@grass.itc.it) Date: Sun Nov 4 14:00:49 2007 Subject: [grass-addons] r1176 - in trunk/grassaddons: v.generalize v.path.obstacles Message-ID: <200711041300.lA4D0mdh012062@grass.itc.it> Author: neteler Date: 2007-11-04 14:00:42 +0100 (Sun, 04 Nov 2007) New Revision: 1176 Added: trunk/grassaddons/v.generalize/MOVED_TO_MAIN_GRASS.txt trunk/grassaddons/v.path.obstacles/MOVED_TO_MAIN_GRASS.txt Log: moved Added: trunk/grassaddons/v.generalize/MOVED_TO_MAIN_GRASS.txt =================================================================== --- trunk/grassaddons/v.generalize/MOVED_TO_MAIN_GRASS.txt (rev 0) +++ trunk/grassaddons/v.generalize/MOVED_TO_MAIN_GRASS.txt 2007-11-04 13:00:42 UTC (rev 1176) @@ -0,0 +1,2 @@ +This module is no longer maintained here but +was moved to the main repository of GRASS. Property changes on: trunk/grassaddons/v.generalize/MOVED_TO_MAIN_GRASS.txt ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/v.path.obstacles/MOVED_TO_MAIN_GRASS.txt =================================================================== --- trunk/grassaddons/v.path.obstacles/MOVED_TO_MAIN_GRASS.txt (rev 0) +++ trunk/grassaddons/v.path.obstacles/MOVED_TO_MAIN_GRASS.txt 2007-11-04 13:00:42 UTC (rev 1176) @@ -0,0 +1,3 @@ +This module is no longer maintained here but +was moved to the main repository of GRASS as +v.net.obstacle. Property changes on: trunk/grassaddons/v.path.obstacles/MOVED_TO_MAIN_GRASS.txt ___________________________________________________________________ Name: svn:eol-style + native From landa at grass.itc.it Tue Nov 13 19:18:16 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Tue Nov 13 19:18:21 2007 Subject: [grass-addons] r1178 - in trunk/grassaddons/gui: . gui_modules Message-ID: <200711131818.lADIIGbB015786@grass.itc.it> Author: landa Date: 2007-11-13 19:12:00 +0100 (Tue, 13 Nov 2007) New Revision: 1178 Modified: trunk/grassaddons/gui/gis_set.py trunk/grassaddons/gui/gui_modules/dbm.py trunk/grassaddons/gui/gui_modules/digit.py trunk/grassaddons/gui/gui_modules/gcmd.py trunk/grassaddons/gui/gui_modules/histogram.py trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/menuform.py trunk/grassaddons/gui/gui_modules/wxgui_utils.py trunk/grassaddons/gui/wxgui.py Log: Various fixes (command styled output, etc.) Basic improvements in attribute manager (browse data and manage tables), not all functional. Modified: trunk/grassaddons/gui/gis_set.py =================================================================== --- trunk/grassaddons/gui/gis_set.py 2007-11-06 06:42:20 UTC (rev 1177) +++ trunk/grassaddons/gui/gis_set.py 2007-11-13 18:12:00 UTC (rev 1178) @@ -190,7 +190,7 @@ dbase_sizer = wx.BoxSizer(wx.HORIZONTAL) location_sizer = wx.FlexGridSizer(rows=1, cols=2, vgap=4, hgap=4) select_box = wx.StaticBox (parent=self, id=wx.ID_ANY, - label=" %s " % _("Choose location and mapset")) + label=" %s " % _("Choose project location and mapset")) select_boxsizer = wx.StaticBoxSizer(select_box, wx.VERTICAL) select_sizer = wx.FlexGridSizer(rows=2, cols=2, vgap=4, hgap=4) manage_box = wx.StaticBox (parent=self, id=wx.ID_ANY, Modified: trunk/grassaddons/gui/gui_modules/dbm.py =================================================================== --- trunk/grassaddons/gui/gui_modules/dbm.py 2007-11-06 06:42:20 UTC (rev 1177) +++ trunk/grassaddons/gui/gui_modules/dbm.py 2007-11-13 18:12:00 UTC (rev 1178) @@ -6,6 +6,7 @@ * VirtualAttributeList * AttributeManager * DisplayAttributesDialog + * VectorDBInfo PURPOSE: GRASS attribute table manager @@ -36,6 +37,7 @@ import wx import wx.lib.mixins.listctrl as listmix +import wx.lib.flatnotebook as FN import sqlbuilder import grassenv @@ -53,32 +55,31 @@ """Update status bar""" self.parent.SetStatusText(text_string.strip()) -class VirtualAttributeList(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.ColumnSorterMixin): +class VirtualAttributeList(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, + listmix.ColumnSorterMixin): """ Support virtual attribute list class """ - def __init__(self, parent, log, vectmap, pointdata=None): + def __init__(self, parent, log, mapInfo, layer, gismgr=None, pointdata=None): wx.ListCtrl.__init__( self, parent=parent, id=wx.ID_ANY, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES | wx.LC_VIRTUAL) # # initialize variables + # self.log = log - self.vectmap = vectmap - self.parent = parent + self.mapInfo = mapInfo + self.gismgr = gismgr # Layer Manager instance or None + self.layer = layer self.qlayer = None - self.icon = '' - self.pointsize = '' - - if not "@" in self.vectmap: - self.vectmap = self.vectmap + "@" + grassenv.GetGRASSVariable("MAPSET") - self.mapname, self.mapset = self.vectmap.split("@") - if pointdata: self.icon = pointdata[0] self.pointsize = pointdata[1] + else: + self.icon = '' + self.pointsize = '' - self.columns = [] + self.columns = {} # <- LoadData() self.selectedCats = [] self.lastTurnSelectedCats = [] # just temporary, for comparation @@ -86,53 +87,29 @@ # add some attributes (colourful background for each item rows) # self.attr1 = wx.ListItemAttr() - self.attr1.SetBackgroundColour("light blue") + #self.attr1.SetBackgroundColour("light blue") + self.attr1.SetBackgroundColour(wx.Colour(238,238,238)) self.attr2 = wx.ListItemAttr() self.attr2.SetBackgroundColour("white") self.il = wx.ImageList(16, 16) - self.sm_up = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP, wx.ART_TOOLBAR, (16,16))) - self.sm_dn = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN, wx.ART_TOOLBAR, (16,16))) + self.sm_up = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP, wx.ART_TOOLBAR, + (16,16))) + self.sm_dn = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN, wx.ART_TOOLBAR, + (16,16))) self.SetImageList(self.il, wx.IMAGE_LIST_SMALL) - if self.parent.gismgr: # Layer Manager is running? - self.mapdisp = self.parent.gismgr.curr_page.maptree.mapdisplay - self.map = self.parent.gismgr.curr_page.maptree.Map + if self.gismgr: # Layer Manager is running? + self.mapdisp = self.curr_page.maptree.mapdisplay + self.map = self.gismgr.curr_page.maptree.Map else: self.mapdisp = self.map = None - # building the columns - # FIXME: Maximal number of columns, when the GUI is still usable - dbDescribe = gcmd.Command (cmd = ["db.describe", "-c", "--q", - "table=%s" % self.parent.tablename, - "driver=%s" % self.parent.driver, - "database=%s" % self.parent.database]) - - # structure (e.g.) - # - # ncols: 2 - # nrows: 11 - # Column 1: cat:INTEGER:11 - # Column 2: label:CHARACTER:43 - i = 0 - for line in dbDescribe.ReadStdOutput()[2:]: # skip ncols and nrows - colnum, column, type, length = line.strip().split(":") - column.strip() - # FIXME: here will be more types - if type.lower().find("integer") > -1: - self.columns.append({"name": column, "type": int, "length" : int(length)}) - elif type.lower().find("double") > -1: - self.columns.append({"name": column, "type": float, "length" : int(length)}) - elif type.lower().find("float") > -1: - self.columns.append({"name": column, "type": float, "length" : int(length)}) - else: - self.columns.append({"name": column, "type": str, "length" : int(length)}) - # These two should probably be passed to init more cleanly # setting the numbers of items = number of elements in the dictionary self.itemDataMap = {} self.itemIndexMap = [] - self.LoadData() + self.LoadData(layer) # self.SetItemCount(len(self.itemDataMap)) # setup mixins @@ -142,13 +119,11 @@ # sort by cat by default self.SortListItems(col=0, ascending=1) # FIXME category column can be different - # # events - # - self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self) - self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, self) - self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, self) - self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColumnClick, self) # sorting + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) + self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected) + self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated) + self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColumnClick) # sorting # self.Bind(wx.EVT_LIST_DELETE_ITEM, self.OnItemDelete, self.list) # self.Bind(wx.EVT_LIST_COL_RIGHT_CLICK, self.OnColRightClick, self.list) # self.Bind(wx.EVT_LIST_COL_BEGIN_DRAG, self.OnColBeginDrag, self.list) @@ -158,14 +133,14 @@ # self.list.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) # self.list.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) - if self.parent.gismgr: + if self.gismgr: self.mapdisp.MapWindow.Bind(wx.EVT_LEFT_DOWN, self.OnMapClick) - self.timer = wx.PyTimer(self.RedrawMap) + # self.timer = wx.PyTimer(self.RedrawMap) # check each 0.1s - self.timer.Start(100) + # self.timer.Start(100) - def LoadData(self, cols='*', where=''): + def LoadData(self, layer, cols='*', where=''): """Load data into list""" self.DeleteAllItems() @@ -174,59 +149,52 @@ for i in range(self.GetColumnCount()): self.DeleteColumn(0) - i = 0 + tableName = self.mapInfo.layers[layer]['table'] + self.columns = self.mapInfo.tables[tableName] + if cols != '*': - for column in cols.split(','): - self.InsertColumn(col=i, heading=column) - i += 1 - - if i >= 256: - self.log.write(_("Can display only 256 columns")) - + columnNames = cols.split(',') else: - for column in self.columns: - self.InsertColumn(col=i, heading=column["name"]) - i += 1 + columnNames = self.mapInfo.GetColumns(tableName) - if i >= 256: - self.log.write(_("Can display only 256 columns")) + i = 0 + for column in columnNames: + self.InsertColumn(col=i, heading=column) + i += 1 + + if i >= 256: + self.log.write(_("Can display only 256 columns")) - if where is '' or where is None: - cmdv = ["db.select", "-c", "--q", - "sql=SELECT %s FROM %s" % (cols, self.parent.tablename), - "database=%s" % self.parent.database, - "driver=%s" % self.parent.driver] - else: - cmdv = ["db.select", "-c", "--q", - "sql=SELECT %s FROM %s WHERE %s" % (cols, self.parent.tablename, where), - "database=%s" % self.parent.database, - "driver=%s" % self.parent.driver] + ### self.mapInfo.SelectFromTable(layer, cols, where) # <- values (FIXME) + # select values (only one record) - # run command - vDbSelect = gcmd.Command(cmd=cmdv) - # # read data # # FIXME: Max. number of rows, while the GUI is still usable + if where is None or where is '': + sql="SELECT %s FROM %s" % (cols, tableName) + else: + sql="SELECT %s FROM %s WHERE %s" % (cols, tableName, where) + + selectCommand = gcmd.Command(["db.select", "-c", "--q", + "sql=%s" % sql, + "database=%s" % self.mapInfo.layers[layer]["database"], + "driver=%s" % self.mapInfo.layers[layer]["driver"], + "fs=|"]) i = 0 - for line in vDbSelect.ReadStdOutput(): - attributes = line.strip().split("|") + for record in selectCommand.ReadStdOutput(): self.itemDataMap[i] = [] + j = 0 + for value in record.split('|'): + # casting ... + self.itemDataMap[i].append(self.columns[columnNames[j]]['ctype'] (value)) + j += 1 - # convert to appropriate type - for j in range(len(attributes)): - try: - attributes[j] = self.columns[j]["type"](attributes[j]) - except: - pass - # insert to table - index = self.InsertStringItem(index=sys.maxint, label=str(attributes[0])) - self.itemDataMap[i].append(attributes[0]) - for j in range(len(attributes[1:])): - self.SetStringItem(index=index, col=j+1, label=str(attributes[j+1])) - self.itemDataMap[i].append(attributes[j+1]) + index = self.InsertStringItem(index=sys.maxint, label=str(self.itemDataMap[i][0])) + for j in range(len(self.itemDataMap[i][1:])): + self.SetStringItem(index=index, col=j+1, label=str(self.itemDataMap[i][j+1])) self.SetItemData(item=index, data=i) self.itemIndexMap.append(i) @@ -238,34 +206,40 @@ self.SetItemCount(i) - for i in range(self.GetColumnCount()): - self.SetColumnWidth(col=i, width=self.columns[i]['length'] * 6) # FIXME + i = 0 + for col in columnNames: + self.SetColumnWidth(col=i, width=self.columns[col]['length'] * 6) # FIXME + i += 1 + + def OnCloseWindow(self, event): """Close attribute manager window""" if self.qlayer: self.map.DeleteLayer(self.qlayer) def OnItemSelected(self, event): - """Item selected""" + """Item selected. Add item to selected cats...""" self.selectedCats.append(int(self.GetItemText(event.m_itemIndex))) self.selectedCats.sort() + print "#+", self.selectedCats event.Skip() def OnItemDeselected(self, event): - - """Item deselected""" + """Item deselected. Remove item from selected cats...""" self.selectedCats.remove(int(self.GetItemText(event.m_itemIndex))) self.selectedCats.sort() + print "#-", self.selectedCats event.Skip() def OnItemActivated(self, event): - """Item activated""" + """Item activated, log purpose""" self.currentItem = event.m_itemIndex - self.log.write("OnItemActivated: %s\nTopItem: %s\n" % - (self.GetItemText(self.currentItem), self.GetTopItem())) + # self.log.write("OnItemActivated: %s\nTopItem: %s\n" % + # (self.GetItemText(self.currentItem), self.GetTopItem())) + print "#" event.Skip() def GetColumnText(self, index, col): @@ -393,21 +367,22 @@ "fcolor=yellow", "cats=%s" % catstr, "width=3"] - #print cmd if self.icon: gcmd.append("icon=%s" % (self.icon)) if self.pointsize: gcmd.append("size=%s" % (self.pointsize)) - self.qlayer = self.map.AddLayer(type="vector", name='qlayer', command=cmd, - l_active=True, l_hidden=True, l_opacity=1, l_render=False) - self.mapdisp.ReDraw(None) + self.qlayer = self.map.AddLayer(type='vector', name='qlayer', command=cmd, + l_active=True, l_hidden=True, l_opacity=1.0) + self.mapdisp.ReDraw() self.lastTurnSelectedCats = self.selectedCats[:] def OnMapClick(self, event): """ Gets coordinates from mouse clicking on display window """ + Debug.msg(3, "VirtualAttributeList.OnMapClick()") + # map coordinates x, y = self.mapdisp.MapWindow.Pixel2Cell(event.GetPositionTuple()[:]) @@ -501,30 +476,26 @@ """ GRASS Attribute manager main window """ - def __init__(self, parent, id, title, vectmap, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, + def __init__(self, parent, id, title, vectmap, + size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, pointdata=None): - self.vectmap = vectmap - self.parent = parent - self.gismgr = parent + self.vectmap = vectmap + self.pointdata = pointdata + self.parent = parent + self.gismgr = parent # status bar log class - log = Log(self) + self.log = Log(self) # -> statusbar - # get list of attribute tables (TODO: open more tables) - vDbConnect = gcmd.Command (cmd=["v.db.connect", - "-g", - "map=%s" % self.vectmap]) + # -> layers / tables description + self.mapInfo = VectorDBInfo(self.vectmap) - if vDbConnect.returncode == 0: - (self.layer, self.tablename, self.column, self.database, self.driver) = \ - vDbConnect.ReadStdOutput()[0].split(' ') # TODO all layers - else: - self.layer = None - - if not self.layer: + if len(self.mapInfo.layers.keys()) == 0: dlg = wx.MessageDialog(patent=parent, - message=_("No attribute table linked to vector map <%s>") % vectmap, + message=_("No attribute table linked to " + "vector map <%s> found.") % \ + self.vectmap, caption=_("Error"), style=wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() @@ -534,98 +505,256 @@ self.CreateStatusBar(number=1) - # set up virtual list - self.win = VirtualAttributeList(parent=self, log=log, vectmap=vectmap, pointdata=pointdata) + # set up virtual lists (each layer) + ### {layer: list, widgets...} + self.layerPage = {} + # flatnotebook (browse, create, alter) + self.notebook = FN.FlatNotebook(parent=self, id=wx.ID_ANY, + style=FN.FNB_BOTTOM | FN.FNB_NO_X_BUTTON | + FN.FNB_NO_NAV_BUTTONS) + self.browsePage = FN.FlatNotebook(self, id=wx.ID_ANY, + style=FN.FNB_NO_X_BUTTON) + self.notebook.AddPage(self.browsePage, text=_("Browse data")) + self.managePage = FN.FlatNotebook(self, id=wx.ID_ANY, + style=FN.FNB_NO_X_BUTTON) + self.notebook.AddPage(self.managePage, text=_("Manage tables")) + self.notebook.SetSelection(0) # select browse tab + + self.infoCollapseLabelExp = _("Click here to show database connection information") + self.infoCollapseLabelCol = _("Click here to hide database connection information") + + self.__createBrowsePage() + self.__createManagePage() + # # buttons # self.btnApply = wx.Button(parent=self, id=wx.ID_APPLY) self.btnQuit = wx.Button(parent=self, id=wx.ID_CANCEL) # self.btn_unselect = wx.Button(self, -1, "Unselect") - self.btnSqlBuilder = wx.Button(parent=self, id=wx.ID_ANY, label=_("SQL Builder")) + + # events + self.btnApply.Bind(wx.EVT_BUTTON, self.OnApplySqlStatement) + self.btnQuit.Bind(wx.EVT_BUTTON, self.OnCloseWindow) + self.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnLayerPageChanged, self.browsePage) + self.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnLayerPageChanged, self.managePage) - # radiobuttons - self.sqlSimple = wx.RadioButton(parent=self, id=wx.ID_ANY, - label=_("Simple")) - self.sqlAdvanced = wx.RadioButton(parent=self, id=wx.ID_ANY, - label=_("Advanced")) + # do layout + self.__layout() - # textarea - self.sqlWhere = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", - style=wx.TE_PROCESS_ENTER) - self.sqlStatement = wx.TextCtrl(parent=self, id=wx.ID_ANY, - value="SELECT * FROM %s" % self.tablename, - style=wx.TE_PROCESS_ENTER) + self.SetMinSize((640, 480)) - # labels - self.sqlLabel = wx.StaticText(parent=self, id=wx.ID_ANY, - label="SELECT * FROM %s WHERE " % self.tablename) - self.label_query = wx.StaticText(parent=self, id=wx.ID_ANY, - label="") + self.Show() - # boxes - self.sqlBox = wx.StaticBox(parent=self, id=wx.ID_ANY, - label=" %s " % _("SQL Query")) - self.listBox = wx.StaticBox(parent=self, id=wx.ID_ANY, - label=" %s " % _("Attribute data")) + def __createBrowsePage(self): + """Create browse tab page""" + for layer in self.mapInfo.layers.keys(): + panel = wx.Panel(parent=self.browsePage, id=wx.ID_ANY) + self.browsePage.AddPage(page=panel, text=_(" %s %d ") % (_("Layer"), layer)) - # collapsible areas - self.infoCollapseLabelExp = _("Click here to show database connection information") - self.infoCollapseLabelCol = _("Click here to hide database connection information") - self.infoCollapse = wx.CollapsiblePane(parent=self, - label=self.infoCollapseLabelExp, - style=wx.CP_DEFAULT_STYLE | wx.CP_NO_TLW_RESIZE | wx.EXPAND) - self.MakeInfoPaneContent(self.infoCollapse.GetPane()) + pageSizer = wx.BoxSizer(wx.VERTICAL) - # bindings - self.btnSqlBuilder.Bind(wx.EVT_BUTTON, self.OnBuilder) - self.btnApply.Bind(wx.EVT_BUTTON, self.OnApplySqlStatement) - self.btnQuit.Bind(wx.EVT_BUTTON, self.OnCloseWindow) - self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnInfoPaneChanged, self.infoCollapse) - self.sqlSimple.Bind(wx.EVT_RADIOBUTTON, self.OnChangeSql) - self.sqlAdvanced.Bind(wx.EVT_RADIOBUTTON, self.OnChangeSql) - self.sqlWhere.Bind(wx.EVT_TEXT_ENTER, self.OnApplySqlStatement) - self.sqlStatement.Bind(wx.EVT_TEXT_ENTER, self.OnApplySqlStatement) + # attribute data + listBox = wx.StaticBox(parent=panel, id=wx.ID_ANY, + label=" %s " % _("Attribute data")) + listSizer = wx.StaticBoxSizer(listBox, wx.VERTICAL) + win = VirtualAttributeList(parent=panel, gismgr=self.parent, log=self.log, + mapInfo=self.mapInfo, layer=layer, + pointdata=self.pointdata) # layer + listSizer.Add(item=win, proportion=1, + flag=wx.EXPAND | wx.ALL, + border=3) + + # sql statement box + btnSqlBuilder = wx.Button(parent=panel, id=wx.ID_ANY, label=_("SQL Builder")) + btnSqlBuilder.Bind(wx.EVT_BUTTON, self.OnBuilder) - # do layer - self.__layout() + sqlSimple = wx.RadioButton(parent=panel, id=wx.ID_ANY, + label=_("Simple")) + sqlAdvanced = wx.RadioButton(parent=panel, id=wx.ID_ANY, + label=_("Advanced")) + sqlSimple.Bind(wx.EVT_RADIOBUTTON, self.OnChangeSql) + sqlAdvanced.Bind(wx.EVT_RADIOBUTTON, self.OnChangeSql) + sqlWhere = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value="", + style=wx.TE_PROCESS_ENTER, + size=(200, -1)) + sqlStatement = wx.TextCtrl(parent=panel, id=wx.ID_ANY, + value="SELECT * FROM %s" % \ + self.mapInfo.layers[layer]['table'], + style=wx.TE_PROCESS_ENTER) + sqlWhere.Bind(wx.EVT_TEXT_ENTER, self.OnApplySqlStatement) + sqlStatement.Bind(wx.EVT_TEXT_ENTER, self.OnApplySqlStatement) + + sqlLabel = wx.StaticText(parent=panel, id=wx.ID_ANY, + label="SELECT * FROM %s WHERE " % \ + self.mapInfo.layers[layer]['table']) + label_query = wx.StaticText(parent=panel, id=wx.ID_ANY, + label="") + + sqlBox = wx.StaticBox(parent=panel, id=wx.ID_ANY, + label=" %s " % _("SQL Query")) + + sqlSizer = wx.StaticBoxSizer(sqlBox, wx.VERTICAL) + sqlFlexSizer = wx.FlexGridSizer (cols=3, hgap=5, vgap=5) + sqlFlexSizer.AddGrowableCol(1) + + sqlFlexSizer.Add(item=sqlSimple, + flag=wx.ALIGN_CENTER_VERTICAL) + sqlSimpleSizer = wx.BoxSizer(wx.HORIZONTAL) + sqlSimpleSizer.Add(item=sqlLabel, + flag=wx.ALIGN_CENTER_VERTICAL) + sqlSimpleSizer.Add(item=sqlWhere, + flag=wx.SHAPED | wx.GROW) + sqlFlexSizer.Add(item=sqlSimpleSizer, + flag=wx.ALIGN_CENTER_VERTICAL) + sqlFlexSizer.Add((0,0)) + sqlFlexSizer.Add(item=sqlAdvanced, + flag=wx.ALIGN_CENTER_VERTICAL) + sqlFlexSizer.Add(item=sqlStatement, + flag=wx.EXPAND) + sqlFlexSizer.Add(item=btnSqlBuilder, + flag=wx.ALIGN_RIGHT) + + sqlSizer.Add(item=sqlFlexSizer, + flag=wx.ALL | wx.EXPAND, + border=0) + + pageSizer.Add(item=listSizer, + proportion=1, + flag=wx.ALL | wx.EXPAND, + border=3) + + pageSizer.Add(item=sqlSizer, + proportion=0, + flag=wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.EXPAND, + border=3) + + panel.SetSizer(pageSizer) + + self.layerPage[layer]= {'list' : win, + 'simple' : sqlSimple, + 'advanced' : sqlAdvanced, + 'where' : sqlWhere, + 'builder' : btnSqlBuilder, + 'statement': sqlStatement} + + + self.browsePage.SetSelection(0) # select first layer + self.layer = self.mapInfo.layers.keys()[0] self.OnChangeSql(None) + self.log.write(_("Number of loaded records: %d") % \ + self.layerPage[self.layer]['list'].GetItemCount()) - self.SetMinSize((640, 480)) + def __createManagePage(self): + """Create manage page (create/link and alter tables)""" + for layer in self.mapInfo.layers.keys(): + panel = wx.Panel(parent=self.browsePage, id=wx.ID_ANY) + self.managePage.AddPage(page=panel, text=_(" %s %d ") % (_("Layer"), layer)) - self.Show() + pageSizer = wx.BoxSizer(wx.VERTICAL) + # dbInfo + infoCollapse = wx.CollapsiblePane(parent=panel, + label=self.infoCollapseLabelExp, + style=wx.CP_DEFAULT_STYLE | + wx.CP_NO_TLW_RESIZE | wx.EXPAND) + self.MakeInfoPaneContent(layer, infoCollapse.GetPane()) + infoCollapse.Collapse(False) + self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnInfoPaneChanged, infoCollapse) + + # table description + table = self.mapInfo.layers[layer]['table'] + tableBox = wx.StaticBox(parent=panel, id=wx.ID_ANY, + label=" %s " % _("Table %s") % table) + + tableSizer = wx.StaticBoxSizer(tableBox, wx.VERTICAL) + + list = self.__createTableDesc(panel, table) + tableSizer.Add(item=list, + flag=wx.ALL | wx.EXPAND, + proportion=1, + border=3) + + pageSizer.Add(item=infoCollapse, + flag=wx.ALL | wx.EXPAND, + proportion=0, + border=3) + + pageSizer.Add(item=tableSizer, + flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, + proportion=1, + border=3) + + panel.SetSizer(pageSizer) + + self.layerPage[layer]['dbinfo'] = infoCollapse + + self.managePage.SetSelection(0) # select first layer + self.layer = self.mapInfo.layers.keys()[0] + + def __createTableDesc(self, parent, table): + """Create list with table description""" + list = TableListCtrl(parent=parent, id=wx.ID_ANY, + table=self.mapInfo.tables[table], + columns=self.mapInfo.GetColumns(table), + style=wx.LC_REPORT | + wx.BORDER_NONE | + wx.LC_SORT_ASCENDING | + wx.LC_HRULES | + wx.LC_VRULES) + list.Populate() + # sorter + # itemDataMap = list.Populate() + # listmix.ColumnSorterMixin.__init__(self, 2) + + return list + + def OnLayerPageChanged(self, event): + """Layer tab changed""" + pageNum = event.GetSelection() + self.layer = self.mapInfo.layers.keys()[pageNum] + self.OnChangeSql(None) + self.log.write(_("Number of loaded records: %d") % \ + self.layerPage[self.layer]['list'].GetItemCount()) + def OnChangeSql(self, event): """Switch simple/advanced sql statement""" - if self.sqlSimple.GetValue(): - self.sqlWhere.Enable(True) - self.sqlStatement.Enable(False) - self.btnSqlBuilder.Enable(False) + if self.layerPage[self.layer]['simple'].GetValue(): + self.layerPage[self.layer]['where'].Enable(True) + self.layerPage[self.layer]['statement'].Enable(False) + self.layerPage[self.layer]['builder'].Enable(False) else: - self.sqlWhere.Enable(False) - self.sqlStatement.Enable(True) - self.btnSqlBuilder.Enable(True) + self.layerPage[self.layer]['where'].Enable(False) + self.layerPage[self.layer]['statement'].Enable(True) + self.layerPage[self.layer]['builder'].Enable(True) def OnApplySqlStatement(self, event): """Apply simple/advanced sql statement""" - if self.sqlSimple.GetValue(): + if self.layerPage[self.layer]['simple'].GetValue(): # simple sql statement - if len(self.sqlWhere.GetValue().strip()) > 0: - self.win.LoadData(where=self.sqlWhere.GetValue().strip()) + where = self.layerPage[self.layer]['where'].GetValue().strip() + if len(where) > 0: + self.layerPage[self.layer]['list'].LoadData(self.layer, where=where) else: - self.win.LoadData() + self.layerPage[self.layer]['list'].LoadData(self.layer) else: # advanced sql statement - valid, cols, where = self.ValidateSelectStatement(self.sqlStatement.GetValue().strip()) + valid, cols, where = \ + self.ValidateSelectStatement( \ + self.layerPage[self.layer]['statement'].GetValue().strip()) Debug.msg(4, "AttributeManager.OnApplySqlStatament(): valid=%s, cols=%s, where=%s" % (valid, cols, where)) if valid is True: - self.win.LoadData(cols=cols, where=where) + self.layerPage[self.layer]['list'].LoadData(self.layer, cols=cols, where=where) + # update statusbar + self.log.write(_("Number of loaded records: %d") % \ + self.layerPage[self.layer]['list'].GetItemCount()) + def ValidateSelectStatement(self, statement): """Validate Select SQL statement @@ -647,14 +776,19 @@ cols += c index += 1 - tablelen = len(self.tablename) + tablelen = len(self.mapInfo.layers[self.layer]['table']) if statement[index+1:index+6].lower() != 'from ' or \ - statement[index+6:index+6+tablelen] != '%s' % (self.tablename): + statement[index+6:index+6+tablelen] != '%s' % \ + (self.mapInfo.layers[self.layer]['table']): return (False, '', '') if len(statement[index+7+tablelen:]) > 0: - where = statement[index+7+tablelen:] + index = statement.lower().find('where ') + if index > -1: + where = statement[index+6:] + else: + where = '' else: where = '' @@ -663,15 +797,15 @@ def OnInfoPaneChanged(self, event): """Collapse database connection info box""" - if self.infoCollapse.IsExpanded(): - self.infoCollapse.SetLabel(self.infoCollapseLabelCol) + if self.layerPage[self.layer]['dbinfo'].IsExpanded(): + self.layerPage[self.layer]['dbinfo'].SetLabel(self.infoCollapseLabelCol) else: - self.infoCollapse.SetLabel(self.infoCollapseLabelExp) + self.layerPage[self.layer]['dbinfo'].SetLabel(self.infoCollapseLabelExp) # redo layout self.Layout() - def MakeInfoPaneContent(self, pane): + def MakeInfoPaneContent(self, layer, pane): """Create database connection information content""" # connection info border = wx.BoxSizer(wx.VERTICAL) @@ -685,15 +819,18 @@ infoFlexSizer.Add(item=wx.StaticText(parent=pane, id=wx.ID_ANY, label="Database:")) infoFlexSizer.Add(item=wx.StaticText(parent=pane, id=wx.ID_ANY, - label="%s" % self.database)) + label="%s" % \ + self.mapInfo.layers[layer]['database'])) infoFlexSizer.Add(item=wx.StaticText(parent=pane, id=wx.ID_ANY, label="Driver:")) infoFlexSizer.Add(item=wx.StaticText(parent=pane, id=wx.ID_ANY, - label="%s" % self.driver)) + label="%s" % \ + self.mapInfo.layers[layer]['driver'])) infoFlexSizer.Add(item=wx.StaticText(parent=pane, id=wx.ID_ANY, label="Table:")) infoFlexSizer.Add(item=wx.StaticText(parent=pane, id=wx.ID_ANY, - label="%s" % self.tablename)) + label="%s" % \ + self.mapInfo.layers[layer]['table'])) infoSizer.Add(item=infoFlexSizer, proportion=1, @@ -709,7 +846,8 @@ def OnCloseWindow(self, event): """Cancel button pressed""" - self.win.OnCloseWindow(event) + for item in self.layerPage.itervalues(): + item['list'].OnCloseWindow(event) self.Close() def OnBuilder(self,event): @@ -728,69 +866,66 @@ #self.panel = wx.Panel(self,-1, style=wx.SUNKEN_BORDER) #self.label_query.SetMinSize((500,50)) - self.sqlWhere.SetMinSize((250,-1)) +# self.sqlWhere.SetMinSize((250,-1)) - pageSizer = wx.BoxSizer(wx.VERTICAL) + # frame body + mainSizer = wx.BoxSizer(wx.VERTICAL) - # attribute data - listSizer = wx.StaticBoxSizer(self.listBox, wx.VERTICAL) - listSizer.Add(item=self.win, proportion=1, - flag=wx.EXPAND | wx.ALL, - border=3) - - # sql query - sqlSizer = wx.StaticBoxSizer(self.sqlBox, wx.VERTICAL) - sqlFlexSizer = wx.FlexGridSizer (cols=3, hgap=5, vgap=5) - sqlFlexSizer.AddGrowableCol(1) - - sqlFlexSizer.Add(item=self.sqlSimple, - flag=wx.ALIGN_CENTER_VERTICAL) - sqlSimpleSizer = wx.BoxSizer(wx.HORIZONTAL) - sqlSimpleSizer.Add(item=self.sqlLabel, - flag=wx.ALIGN_CENTER_VERTICAL) - sqlSimpleSizer.Add(item=self.sqlWhere, - flag=wx.SHAPED | wx.GROW) - sqlFlexSizer.Add(item=sqlSimpleSizer, - flag=wx.ALIGN_CENTER_VERTICAL) - sqlFlexSizer.Add((0,0)) - sqlFlexSizer.Add(item=self.sqlAdvanced, - flag=wx.ALIGN_CENTER_VERTICAL) - sqlFlexSizer.Add(item=self.sqlStatement, - flag=wx.EXPAND) - sqlFlexSizer.Add(item=self.btnSqlBuilder, - flag=wx.ALIGN_RIGHT) - - sqlSizer.Add(item=sqlFlexSizer, - flag=wx.ALL | wx.EXPAND, - border=0) - # buttons btnSizer = wx.StdDialogButtonSizer() btnSizer.AddButton(self.btnQuit) btnSizer.AddButton(self.btnApply) btnSizer.Realize() - pageSizer.Add(item=self.infoCollapse, - flag=wx.ALL | wx.EXPAND, - proportion=0, - border=3) - pageSizer.Add(item=listSizer, - proportion=1, - flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, - border=3) - pageSizer.Add(item=sqlSizer, - proportion=0, - flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, - border=3) - pageSizer.Add(item=btnSizer, - proportion=0, - flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, - border=3) + mainSizer.Add(item=self.notebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) + mainSizer.Add(item=btnSizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) - self.SetSizer(pageSizer) - pageSizer.Fit(self) + self.SetSizer(mainSizer) + mainSizer.Fit(self) + self.Layout() +class TableListCtrl(wx.ListCtrl, + listmix.ListCtrlAutoWidthMixin, + listmix.TextEditMixin): + """Table description list""" + + def __init__(self, parent, id, table, columns, pos=wx.DefaultPosition, + size=wx.DefaultSize, style=0): + + self.parent = parent + self.table = table + self.columns = columns + wx.ListCtrl.__init__(self, parent, id, pos, size, style) + + listmix.ListCtrlAutoWidthMixin.__init__(self) + listmix.TextEditMixin.__init__(self) + + def Populate(self): + """Populate the list""" + itemData = {} # requested by sorter + + headings = [_("Column name"), _("Type"), _("Length")] + i = 0 + for h in headings: + self.InsertColumn(col=i, heading=h) + self.SetColumnWidth(col=i, width=150) + i += 1 + + i = 0 + for column in self.columns: + index = self.InsertStringItem(sys.maxint, str(column)) + self.SetStringItem(index, 0, str(column)) + self.SetStringItem(index, 1, str(self.table[column]['type'])) + self.SetStringItem(index, 2, str(self.table[column]['length'])) + self.SetItemData(index, i) + itemData[i] = (str(column), + str(self.table[column]['type']), + int(self.table[column]['length'])) + i = i + 1 + + return itemData + class DisplayAttributesDialog(wx.Dialog): """ Standard dialog used to add/update/display attributes linked @@ -817,7 +952,7 @@ self.line = None # get layer/table/column information - self.mapInfo = VectorAttributeInfo(self.map) + self.mapInfo = VectorDBInfo(self.map) layers = self.mapInfo.layers.keys() # get available layers @@ -832,8 +967,9 @@ (self.layer, self.map) dlg = wx.MessageDialog(self.parent, - _("No attribute table found.\n" - "%s") % (label), + _("No attribute table linked to " + "vector map <%s> found.\n" + "%s") % (self.map, label), _("Error"), wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() @@ -1046,7 +1182,7 @@ continue if not self.queryCoords: # select using layer/cat - nselected = self.mapInfo.SelectFromTable(layer, self.cat) + nselected = self.mapInfo.SelectFromTable(layer, where="cat=%d" % self.cat) if nselected <= 0 and self.action != "add": continue # nothing selected ... @@ -1134,14 +1270,14 @@ return True -class VectorAttributeInfo: +class VectorDBInfo: """Class providing information about attribute tables linked to the vector map""" def __init__(self, map): self.map = map # {layer number : {table, database, driver}) self.layers = {} - # {table : {column name : type, values, ids}} + # {table : {column name : type, length, values, ids}} self.tables = {} if not self.__CheckDBConnection(): # -> self.layers @@ -1154,7 +1290,7 @@ layerCommand = gcmd.Command(cmd=["v.db.connect", "-g", "--q", "map=%s" % self.map,], - dlgMsg='txt') + dlgMsg='txt') if layerCommand.returncode != 0: return False @@ -1174,25 +1310,51 @@ """Describe linked tables""" for layer in self.layers.keys(): # determine column names and types - columnsCommand = gcmd.Command (cmd=["v.db.connect", "-c", "--q", - "map=%s" % self.map, - "layer=%d" % layer]) table = self.layers[layer]["table"] + columnsCommand = gcmd.Command (cmd=["db.describe", + "-c", "--q", + "table=%s" % self.layers[layer]["table"], + "driver=%s" % self.layers[layer]["driver"], + "database=%s" % self.layers[layer]["database"]]) + - columns = {} # {name: {type, [values], [ids]}} + columns = {} # {name: {type, length, [values], [ids]}} if columnsCommand.returncode == 0: - for line in columnsCommand.ReadStdOutput(): - columnType, columnName = line.split('|') - columnType = columnType.lower().strip() - columns[columnName] = { 'type' : columnType, - 'values' : [], - 'ids' : []} + # get rid of nrows and ncols row... + i = 0 + for line in columnsCommand.ReadStdOutput()[2:]: + num, name, type, length = line.strip().split(':') + # FIXME: here will be more types + if type.lower() == "integer": + ctype = int + elif type.lower() == "double" or type.lower() == "float": + ctype = float + else: + ctype = str + + columns[name.strip()] = { 'index' : i, + 'type' : type.lower(), + 'ctype' : ctype, + 'length' : int(length), + 'values' : [], + 'ids' : []} + i += 1 else: - pass + return False self.tables[table] = columns + return True + + def GetColumns(self, table): + """Return list of columns names (based on their index)""" + names = [''] * len(self.tables[table].keys()) + for name, desc in self.tables[table].iteritems(): + names[desc['index']] = name + + return names + def SelectByPoint(self, queryCoords, qdist): """Get attributes by coordinates (all available layers) @@ -1201,10 +1363,10 @@ nselected = 0 cmdWhat = gcmd.Command(cmd=['v.what', '-a', '--q', - 'map=%s' % self.map, - 'east_north=%f,%f' % \ - (float(queryCoords[0]), float(queryCoords[1])), - 'distance=%f' % qdist]) + 'map=%s' % self.map, + 'east_north=%f,%f' % \ + (float(queryCoords[0]), float(queryCoords[1])), + 'distance=%f' % qdist]) if cmdWhat.returncode == 0: read = False @@ -1215,7 +1377,9 @@ name = name.strip() # append value to the column try: - self.tables[table][name]['values'].append(value.strip()) + # casting ... + value = self.tables[table][name]['ctype'] (value.strip()) + self.tables[table][name]['values'].append(value) except: read = False @@ -1231,7 +1395,7 @@ return (line, nselected) - def SelectFromTable(self, layer, cat): + def SelectFromTable(self, layer, cols='*', where=None): """Select records from the table Return number of selected records, -1 on error @@ -1243,15 +1407,22 @@ table = self.layers[layer]["table"] # get table desc # select values (only one record) - selectCommand = gcmd.Command(cmd=["v.db.select", "-v", "--q", - "map=%s" % self.map, - "layer=%d" % layer, - "where=cat=%d" % cat]) + if where is None or where is '': + sql="SELECT %s FROM %s" % (cols, table) + else: + sql="SELECT %s FROM %s WHERE %s" % (cols, table, where) - #self.tables[table]["cat"][1] = str(cat) + selectCommand = gcmd.Command(["db.select", "-v", "--q", + "sql=%s" % sql, + "database=%s" % self.layers[layer]["database"], + "driver=%s" % self.layers[layer]["driver"]]) + + # self.tables[table]["cat"][1] = str(cat) if selectCommand.returncode == 0: for line in selectCommand.ReadStdOutput(): name, value = line.split('|') + # casting ... + value = self.tables[table][name]['ctype'] (value) self.tables[table][name]['values'].append(value) nselected = 1 @@ -1284,7 +1455,8 @@ app = wx.PySimpleApp() f = AttributeManager(parent=None, id=wx.ID_ANY, - title=_("GRASS Attribute Table Manager: vector map <%s>") % argv[1], + title=_("GRASS GIS Attribute Table Manager - vector map layer <%s>") % \ + argv[1], size=(700,600), vectmap=argv[1]) app.MainLoop() Modified: trunk/grassaddons/gui/gui_modules/digit.py =================================================================== --- trunk/grassaddons/gui/gui_modules/digit.py 2007-11-06 06:42:20 UTC (rev 1177) +++ trunk/grassaddons/gui/gui_modules/digit.py 2007-11-13 18:12:00 UTC (rev 1178) @@ -1371,7 +1371,8 @@ Debug.msg(3, "DigitCategoryDialog(): line=%d, cats=%s" % \ (self.line, self.cats)) - wx.Dialog.__init__(self, parent=self.parent, id=wx.ID_ANY, title=title, style=style, pos=pos) + wx.Dialog.__init__(self, parent=self.parent, id=wx.ID_ANY, title=title, + style=style, pos=pos) # list of categories box = wx.StaticBox(parent=self, id=wx.ID_ANY, Modified: trunk/grassaddons/gui/gui_modules/gcmd.py =================================================================== --- trunk/grassaddons/gui/gui_modules/gcmd.py 2007-11-06 06:42:20 UTC (rev 1177) +++ trunk/grassaddons/gui/gui_modules/gcmd.py 2007-11-13 18:12:00 UTC (rev 1178) @@ -2,8 +2,9 @@ MODULE: gcmd CLASSES: + * Popen * Command - * RunCommand + * CommandThread PURPOSE: GRASS command interface @@ -17,30 +18,139 @@ for details. """ -import os, sys +import os +import sys import time -import fcntl -from threading import Thread - -import wx # GUI dialogs... - +import errno try: import subprocess except: CompatPath = os.path.join(os.getenv("GISBASE"), "etc", "wx", "compat") sys.path.append(CompatPath) import subprocess +if subprocess.mswindows: + from win32file import ReadFile, WriteFile + from win32pipe import PeekNamedPipe + import msvcrt +else: + import select + import fcntl +from threading import Thread -# debugging & log window +import wx # GUI dialogs... + GuiModulePath = os.path.join(os.getenv("GISBASE"), "etc", "wx", "gui_modules") sys.path.append(GuiModulePath) - +# debugging & log window import wxgui_utils from debug import Debug as Debug +class Popen(subprocess.Popen): + """Subclass Popen...""" + def recv(self, maxsize=None): + return self._recv('stdout', maxsize) + + def recv_err(self, maxsize=None): + return self._recv('stderr', maxsize) + + def send_recv(self, input='', maxsize=None): + return self.send(input), self.recv(maxsize), self.recv_err(maxsize) + + def get_conn_maxsize(self, which, maxsize): + if maxsize is None: + maxsize = 1024 + elif maxsize < 1: + maxsize = 1 + return getattr(self, which), maxsize + + def _close(self, which): + getattr(self, which).close() + setattr(self, which, None) + + if subprocess.mswindows: + def send(self, input): + if not self.stdin: + return None + + try: + x = msvcrt.get_osfhandle(self.stdin.fileno()) + (errCode, written) = WriteFile(x, input) + except ValueError: + return self._close('stdin') + except (subprocess.pywintypes.error, Exception), why: + if why[0] in (109, errno.ESHUTDOWN): + return self._close('stdin') + raise + + return written + + def _recv(self, which, maxsize): + conn, maxsize = self.get_conn_maxsize(which, maxsize) + if conn is None: + return None + + try: + x = msvcrt.get_osfhandle(conn.fileno()) + (read, nAvail, nMessage) = PeekNamedPipe(x, 0) + if maxsize < nAvail: + nAvail = maxsize + if nAvail > 0: + (errCode, read) = ReadFile(x, nAvail, None) + except ValueError: + return self._close(which) + except (subprocess.pywintypes.error, Exception), why: + if why[0] in (109, errno.ESHUTDOWN): + return self._close(which) + raise + + if self.universal_newlines: + read = self._translate_newlines(read) + return read + + else: + def send(self, input): + if not self.stdin: + return None + + if not select.select([], [self.stdin], [], 0)[1]: + return 0 + + try: + written = os.write(self.stdin.fileno(), input) + except OSError, why: + if why[0] == errno.EPIPE: #broken pipe + return self._close('stdin') + raise + + return written + + def _recv(self, which, maxsize): + conn, maxsize = self.get_conn_maxsize(which, maxsize) + if conn is None: + return None + + flags = fcntl.fcntl(conn, fcntl.F_GETFL) + if not conn.closed: + fcntl.fcntl(conn, fcntl.F_SETFL, flags| os.O_NONBLOCK) + + try: + if not select.select([conn], [], [], 0)[0]: + return '' + + r = conn.read(maxsize) + if not r: + return self._close(which) + + if self.universal_newlines: + r = self._translate_newlines(r) + return r + finally: + if not conn.closed: + fcntl.fcntl(conn, fcntl.F_SETFL, flags) + class Command: """ - Run GRASS command + Run GRASS command in separate thread Parameters: cmd - command given as list @@ -73,15 +183,14 @@ # # set verbosity level # + verbose_orig = None if verbose == 0 and '--q' not in self.cmd: self.cmd.append('--q') elif verbose == 3 and '--v' not in self.cmd: self.cmd.append('--v') else: - verbosity = os.getenv("GRASS_VERBOSE") + verbose_orig = os.getenv("GRASS_VERBOSE") os.environ["GRASS_VERBOSE"] = str(verbose) - if verbosity: - os.environ["GRASS_VERBOSE"] = verbosity # # set message formatting @@ -90,10 +199,10 @@ os.environ["GRASS_MESSAGE_FORMAT"] = "gui" # - # run command + # create command thread # - self.cmdThread = RunCommand(cmd, stdin, - stdout, stderr) + self.cmdThread = CommandThread(cmd, stdin, + stdout, stderr) # # start thread @@ -105,7 +214,7 @@ self.cmdThread.module.wait() self.returncode = self.cmdThread.module.returncode else: - self.cmdThread.join(0.1) + self.cmdThread.join(0.5) self.returncode = None if self.returncode is not None: @@ -133,10 +242,15 @@ else: os.unsetenv("GRASS_MESSAGE_FORMAT") + if verbose_orig: + os.environ["GRASS_VERBOSE"] = verbose_orig + else: + os.unsetenv("GRASS_VERBOSE") + def __ReadOutput(self, stream): """Read stream and return list of lines - Note: Remove '\n' from output (TODO: '\r\n' ??) + Note: Remove os.linesep from output """ lineList = [] @@ -147,7 +261,7 @@ line = stream.readline() if not line: break - line = line.replace('\n', '').strip() + line = line.replace('%s' % os.linesep, '').strip() lineList.append(line) return lineList @@ -208,8 +322,8 @@ return msgString -class RunCommand(Thread): - """See Command class""" +class CommandThread(Thread): + """Run command in separate thread""" def __init__ (self, cmd, stdin=None, stdout=None, stderr=None): @@ -224,11 +338,11 @@ def run(self): """Run command""" - self.module = subprocess.Popen(self.cmd, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - close_fds=False) + self.module = Popen(self.cmd, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + # close_fds=False) (MS Windows ?) if self.stdin: # read stdin if requested ... self.module.stdin.write(self.stdin) @@ -237,11 +351,13 @@ if not self.module: return + # redirect standard outputs... if self.stdout and self.stderr: # make stdout/stderr non-blocking stdout_fileno = self.module.stdout.fileno() stderr_fileno = self.module.stderr.fileno() + # FIXME (MS Windows) flags = fcntl.fcntl(stdout_fileno, fcntl.F_GETFL) fcntl.fcntl(stdout_fileno, fcntl.F_SETFL, flags| os.O_NONBLOCK) @@ -250,6 +366,9 @@ # wait for the process to end, sucking in stuff until it does end while self.module.poll() is None: + evt = wxgui_utils.UpdateGMConsoleEvent() + #wx.PostEvent(self.stdout, evt) + #wx.PostEvent(self.stderr, evt) try: self.stdout.write(self.module.stdout.read()) except IOError: @@ -263,7 +382,6 @@ time.sleep(0.1) # get the last output - try: self.stdout.write(self.module.stdout.read()) pass @@ -275,7 +393,6 @@ except IOError: pass - # testing ... if __name__ == "__main__": SEP = "-----------------------------------------------------------------------------" Modified: trunk/grassaddons/gui/gui_modules/histogram.py =================================================================== --- trunk/grassaddons/gui/gui_modules/histogram.py 2007-11-06 06:42:20 UTC (rev 1177) +++ trunk/grassaddons/gui/gui_modules/histogram.py 2007-11-13 18:12:00 UTC (rev 1178) @@ -256,9 +256,9 @@ self.resize = False # update statusbar - #Debug.msg (3, "BufferedWindow.UpdateHist(%s): region=%s" % self.Map.region) + # Debug.msg (3, "BufferedWindow.UpdateHist(%s): region=%s" % self.Map.region) self.Map.SetRegion() - self.parent.statusbar.SetStatusText("Histogramming <%s>" % self.parent.mapname) + self.parent.statusbar.SetStatusText("Raster/Image map layer <%s>" % self.parent.mapname) # set default font and encoding environmental variables if oldfont != "": @@ -305,8 +305,8 @@ # Add statusbar # self.mapname = '' - self.statusbar = self.CreateStatusBar(number=2, style=0) - self.statusbar.SetStatusWidths([-2, -1]) + self.statusbar = self.CreateStatusBar(number=1, style=0) + # self.statusbar.SetStatusWidths([-2, -1]) hist_frame_statusbar_fields = ["Histogramming %s" % self.mapname] for i in range(len(hist_frame_statusbar_fields)): self.statusbar.SetStatusText(hist_frame_statusbar_fields[i], i) @@ -375,7 +375,7 @@ global gmpath completed = '' - menuform.GUI().ParseCommand('d.histogram', gmpath, + menuform.GUI().ParseCommand(['d.histogram'], gmpath, completed=(self.GetOptData, "hist", self.params), parentframe=None) @@ -404,8 +404,9 @@ if 'map=' in item: self.mapname = item.split('=')[1] - self.layer = self.Map.ChangeLayer(layer=self.layer, type="command", name='', command=cmd, - l_active=True, l_hidden=False, l_opacity=1, l_render=False) + self.layer = self.Map.ChangeLayer(layer=self.layer, type="command", name='histogram', + command=cmd, + l_active=True, l_hidden=False, l_opacity=1.0) return self.layer Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-11-06 06:42:20 UTC (rev 1177) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-11-13 18:12:00 UTC (rev 1178) @@ -1203,13 +1203,18 @@ # copy features from background map self.copyIds = digitClass.SelectLinesFromBackgroundMap(pos1, pos2) if len(self.copyIds) > 0: + color = digitClass.settings['symbolHighlight'][1] + colorStr = str(color[0]) + ":" + \ + str(color[1]) + ":" + \ + str(color[2]) + ":" dVectTmp = ['d.vect', 'map=%s' % digitClass.settings['backgroundMap'], 'cats=%s' % ",".join(["%d" % v for v in self.copyIds]), '-i', - 'color=yellow', - 'fcolor=yellow', - 'type=point,line,boundary,centroid'] + 'color=%s' % colorStr, + 'fcolor=%s' % colorStr, + 'type=point,line,boundary,centroid', + 'width=2'] self.layerTmp = self.Map.AddLayer(type='vector', command=dVectTmp) self.UpdateMap(render=True, renderVector=False) Modified: trunk/grassaddons/gui/gui_modules/menuform.py =================================================================== --- trunk/grassaddons/gui/gui_modules/menuform.py 2007-11-06 06:42:20 UTC (rev 1177) +++ trunk/grassaddons/gui/gui_modules/menuform.py 2007-11-13 18:12:00 UTC (rev 1178) @@ -525,7 +525,7 @@ self.task = task_description self.parent = parent - standalone = True + self.standalone = True # module name + keywords title = self.task.name @@ -560,10 +560,12 @@ guisizer = wx.BoxSizer(wx.VERTICAL) # set apropriate output window - # if self.parent: - # standalone=False - # self.goutput = self.parent.goutput - # else: + if self.parent: + self.standalone = False + try: + self.goutput = self.parent.GetLogWindow() + except: + self.goutput = None # logo+description topsizer = wx.BoxSizer(wx.HORIZONTAL) @@ -578,8 +580,8 @@ guisizer.Add (item=topsizer, proportion=0, flag=wx.ALIGN_BOTTOM | wx.EXPAND) # notebooks - self.notebookpanel = cmdPanel (parent=self, task=self.task, standalone=standalone) - if standalone: + self.notebookpanel = cmdPanel (parent=self, task=self.task, standalone=self.standalone) + if self.standalone: self.goutput = self.notebookpanel.goutput self.notebookpanel.OnUpdateValues = self.updateValuesHook guisizer.Add (item=self.notebookpanel, proportion=1, flag=wx.EXPAND) @@ -604,12 +606,19 @@ btn_cancel = wx.Button(parent=self, id=wx.ID_CANCEL) btn_cancel.SetToolTipString(_("Cancel the command settings and ignore changes")) btnsizer.Add(item=btn_cancel, proportion=0, flag=wx.ALL | wx.ALIGN_CENTER, border=10) + btn_cancel.Bind(wx.EVT_BUTTON, self.OnCancel) if self.get_dcmd is not None: # A callback has been set up - btn_apply = wx.Button(self, wx.ID_APPLY, _("Apply") ) - btnsizer.Add( btn_apply, 0, wx.ALL| wx.ALIGN_CENTER, 10) - btn_ok = wx.Button(self, wx.ID_OK, _("OK") ) - btnsizer.Add( btn_ok, 0, wx.ALL| wx.ALIGN_CENTER, 10) + btn_apply = wx.Button(parent=self, id=wx.ID_APPLY) + btn_ok = wx.Button(parent=self, id=wx.ID_OK) btn_ok.SetDefault() + + btnsizer.Add(item=btn_apply, proportion=0, + flag=wx.ALL | wx.ALIGN_CENTER, + border=10) + btnsizer.Add(item=btn_ok, proportion=0, + flag=wx.ALL | wx.ALIGN_CENTER, + border=10) + btn_apply.Bind(wx.EVT_BUTTON, self.OnApply) btn_ok.Bind(wx.EVT_BUTTON, self.OnOK) else: # We're standalone @@ -617,19 +626,28 @@ btn_run = wx.Button(parent=self, id=wx.ID_OK, label= _("&Run")) btn_run.SetToolTipString(_("Run the command")) btn_run.SetDefault() - btn_run.Bind(wx.EVT_BUTTON, self.OnRun) - btnsizer.Add( item=btn_run, proportion=0, flag=wx.ALL| wx.ALIGN_CENTER, border=10) # copy - btn_clipboard = wx.Button(parent=self, id=wx.ID_OK, label=_("C&opy") ) + btn_clipboard = wx.Button(parent=self, id=wx.ID_COPY, label=_("C&opy")) btn_clipboard.SetToolTipString(_("Copy the current command string to the clipboard")) + + btnsizer.Add(item=btn_run, proportion=0, + flag=wx.ALL | wx.ALIGN_CENTER, + border=10) + + btnsizer.Add(item=btn_clipboard, proportion=0, + flag=wx.ALL | wx.ALIGN_CENTER, + border=10) + + btn_run.Bind(wx.EVT_BUTTON, self.OnRun) btn_clipboard.Bind(wx.EVT_BUTTON, self.OnCopy) - btnsizer.Add(item=btn_clipboard, proportion=0, flag=wx.ALL| wx.ALIGN_CENTER, border=10) + guisizer.Add(item=btnsizer, proportion=0, flag=wx.ALIGN_CENTER) - btn_cancel.Bind(wx.EVT_BUTTON, self.OnCancel) + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) constrained_size = self.notebookpanel.GetSize() - self.notebookpanel.SetSize( (constrained_size[0],constrained_size[1]+80) ) # 80 takes the tabbar into account + # 80 takes the tabbar into account + self.notebookpanel.SetSize( (constrained_size[0],constrained_size[1]+80) ) self.notebookpanel.Layout() # for too long descriptions @@ -673,10 +691,11 @@ if cmd == [] or cmd == None: return - # change page if needed - if self.notebookpanel.notebook.GetSelection() != self.notebookpanel.outpageid: - self.notebookpanel.notebook.SetSelection(self.notebookpanel.outpageid) - + if self.standalone: + # change page if needed + if self.notebookpanel.notebook.GetSelection() != self.notebookpanel.outpageid: + self.notebookpanel.notebook.SetSelection(self.notebookpanel.outpageid) + if cmd[0][0:2] != "d.": # Send any non-display command to parent window (probably wxgui.py) # put to parents @@ -688,14 +707,6 @@ # Send any other command to the shell. else: runCmd = gcmd.Command(cmd) - # try: - # retcode = subprocess.call(cmd, shell=True) - # if retcode < 0: - # print >>sys.stderr, "Child was terminated by signal", -retcode - # elif retcode > 0: - # print >>sys.stderr, "Child returned", retcode - # except OSError, e: - # print >>sys.stderr, "Execution failed:", e def OnCopy(self, event): """Copy the command""" Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-11-06 06:42:20 UTC (rev 1177) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-11-13 18:12:00 UTC (rev 1178) @@ -22,18 +22,19 @@ This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. - """ import os import sys import string import tempfile +import time import wx import wx.lib.customtreectrl as CT import wx.combo import wx.stc +import wx.lib.newevent gmpath = os.path.join( os.getenv("GISBASE"),"etc","wx","gui_modules" ) sys.path.append(gmpath) @@ -53,6 +54,9 @@ except: from compat import subprocess +# define event for GRASS console (running GRASS command in separate thread) +(UpdateGMConsoleEvent, EVT_UPDATE_GMCONSOLE) = wx.lib.newevent.NewEvent() + class LayerTree(CT.CustomTreeCtrl): """ Creates layer tree structure @@ -95,9 +99,9 @@ Map=self.Map, auimgr=self.auimgr) # title - self.mapdisplay.SetTitle(_("GRASS GIS - Map Display: " + \ - str(self.disp_idx) + \ - " - Location: " + grassenv.GetGRASSVariable("LOCATION_NAME"))) + self.mapdisplay.SetTitle(_("GRASS GIS Map Display: " + + str(self.disp_idx) + + " - Location: " + grassenv.GetGRASSVariable("LOCATION_NAME"))) #show new display self.mapdisplay.Show() @@ -269,7 +273,14 @@ """ Plot histogram for given raster map layer """ - rastName = self.GetPyData(self.layer_selected)[0]['maplayer'].name + mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer'] + if not mapLayer.name: + dlg = wx.MessageDialog(self, _("Unable to display histogram for " + "raster map layer"), + _("Error"), wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return False if not hasattr (self, "histogramFrame"): self.histogramFrame = None @@ -279,16 +290,19 @@ if not self.histogramFrame: self.histogramFrame = histogram.HistFrame(self, - id=wx.ID_ANY, pos=wx.DefaultPosition, size=(400,300), + id=wx.ID_ANY, + pos=wx.DefaultPosition, size=(400, 300), style=wx.DEFAULT_FRAME_STYLE) # show new display self.histogramFrame.Show() - self.histogramFrame.SetHistLayer(['d.histogram', 'map=%s' % rastName]) + self.histogramFrame.SetHistLayer(['d.histogram', 'map=%s' % mapLayer.name]) self.histogramFrame.HistWindow.UpdateHist() self.histogramFrame.Refresh() self.histogramFrame.Update() + return True + def OnStartEditing (self, event): """ Start editing vector map layer requested by the user @@ -453,6 +467,7 @@ if ltype != 'group': if lopacity: opacity = lopacity + ctrl.SetValue(int(lopacity * 100)) else: opacity = 1.0 if lcmd and len(lcmd) > 1: @@ -980,22 +995,25 @@ # initialize variables self.Map = None - self.parent = parent # GMFrame - self.cmd_output = "" - self.console_command = "" - self.console_clear = "" - self.console_save = "" - self.gcmdlst = [] # list of commands in bin and scripts + self.parent = parent # GMFrame + self.gcmdlst = self.GetGRASSCmds() # list of commands in bin and scripts + self.cmdThreads = [] # list of command threads (alive or dead) + # progress bar + self.console_progressbar = wx.Gauge(parent=self, id=wx.ID_ANY, + range=100, pos=(110, 50), size=(-1, 25), + style=wx.GA_HORIZONTAL) + # text control for command output - # self.cmd_output = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", - # style=wx.TE_MULTILINE| wx.TE_READONLY) - # self.cmd_output.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.NORMAL, 0, '')) + ### self.cmd_output = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", + ### style=wx.TE_MULTILINE| wx.TE_READONLY) + ### self.cmd_output.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN, + ### wx.NORMAL, wx.NORMAL, 0, '')) self.cmd_output = GMStc(parent=self, id=wx.ID_ANY) - # redirect - # sys.stdout = GMStdout(self.cmd_output) - # sys.stderr = GMStderr(self.cmd_output) + self.cmd_stdout = GMStdout(self.cmd_output) + self.cmd_stderr = GMStderr(self.cmd_output, + self.console_progressbar) # buttons self.console_clear = wx.Button(parent=self, id=wx.ID_CLEAR) @@ -1003,12 +1021,7 @@ self.Bind(wx.EVT_BUTTON, self.ClearHistory, self.console_clear) self.Bind(wx.EVT_BUTTON, self.SaveHistory, self.console_save) - # progress bar - self.console_progressbar = wx.Gauge(parent=self, id=wx.ID_ANY, - range=100, pos=(110, 50), size=(-1, 25), - style=wx.GA_HORIZONTAL) - - # output control layout + # output control layout boxsizer1 = wx.BoxSizer(wx.VERTICAL) gridsizer1 = wx.GridSizer(rows=1, cols=2, vgap=0, hgap=0) boxsizer1.Add(item=self.cmd_output, proportion=1, @@ -1036,13 +1049,13 @@ Create list of all available GRASS commands to use when parsing string from the command line """ - self.gcmdlst = [] + gcmdlst = [] gisbase = os.environ['GISBASE'] - self.gcmdlst = os.listdir(os.path.join(gisbase,'bin')) - self.gcmdlst = self.gcmdlst + os.listdir(os.path.join(gisbase,'scripts')) + gcmdlst = os.listdir(os.path.join(gisbase,'bin')) + gcmdlst = gcmdlst + os.listdir(os.path.join(gisbase,'scripts')) #self.gcmdlst = self.gcmdlst + os.listdir(os.path.join(gisbase,'etc','gm','script')) - return self.gcmdlst + return gcmdlst def RunCmd(self, command): """ @@ -1058,9 +1071,6 @@ the focus (as indicted by mdidx). """ - # create list of available GRASS commands - gcmdlst = self.GetGRASSCmds() - # map display window available ? try: curr_disp = self.parent.curr_page.maptree.mapdisplay @@ -1074,7 +1084,7 @@ except: cmdlist = command - if cmdlist[0] in gcmdlst: + if cmdlist[0] in self.gcmdlst: # send GRASS command without arguments to GUI command interface # except display commands (they are handled differently) if cmdlist[0][0:2] == "d.": # display GRASS commands @@ -1106,25 +1116,42 @@ # select 'Command output' tab self.parent.notebook.SetSelection(1) - # activate compuational region (set with g.region) for all non-display commands. - tmpreg = os.getenv("GRASS_REGION") - os.unsetenv("GRASS_REGION") + if len(self.GetListOfCmdThreads(onlyAlive=True)) > 0: + busy = wx.BusyInfo(message=_("Please wait, there is another command " + "currently running"), + parent=self.parent) + # wx.Yield() + time.sleep(3) + busy.Destroy() + else: + # activate computational region (set with g.region) + # for all non-display commands. + tmpreg = os.getenv("GRASS_REGION") + os.unsetenv("GRASS_REGION") - # process GRASS command with argument - self.cmd_output.AddText('$ %s' % ' '.join(cmdlist) + os.linesep) - - grassCmd = gcmd.Command(cmdlist, verbose=3, wait=False, - stdout=GMStdout(self.cmd_output), - stderr=GMStderr(self.cmd_output, - self.console_progressbar)) - - # deactivate computational region and return to display settings - if tmpreg: - os.environ["GRASS_REGION"] = tmpreg + # process GRASS command with argument + p1 = self.cmd_output.GetCurrentPos() + self.cmd_output.AddText('$ %s' % ' '.join(cmdlist) + os.linesep) + self.cmd_output.EnsureCaretVisible() + p2 = self.cmd_output.GetCurrentPos() + self.cmd_output.StartStyling(p1, 0xff) + self.cmd_output.SetStyling(p2 - p1 + 1, self.cmd_output.StyleCommand) - if grassCmd.returncode != 0: - return False + +# grassCmd = gcmd.Command(cmdlist, verbose=3, wait=False, +# stdout=GMStdout(self.cmd_output), +# stderr=GMStderr(self.cmd_output, +# self.console_progressbar)) + grassCmd = gcmd.Command(cmdlist, verbose=3, wait=False, + stdout=self.cmd_stdout, + stderr=self.cmd_stderr) + self.cmdThreads.append(grassCmd.cmdThread) + + # deactivate computational region and return to display settings + if tmpreg: + os.environ["GRASS_REGION"] = tmpreg + else: # Send any other command to the shell. Send output to # console output window. @@ -1176,6 +1203,18 @@ dlg.Destroy() + def GetListOfCmdThreads(self, onlyAlive=False): + """Return list of command threads)""" + list = [] + for t in self.cmdThreads: + Debug.msg (4, "GMConsole.GetListOfCmdThreads(): name=%s, alive=%s" % + (t.getName(), t.isAlive())) + if onlyAlive and not t.isAlive(): + continue + list.append(t) + + return list + class GMStdout: """GMConsole standard output @@ -1214,7 +1253,7 @@ Licence: GPL """ def __init__(self, gmstc, gmgauge): - self.gmstc = gmstc + self.gmstc = gmstc self.gmgauge = gmgauge def write(self, s): @@ -1222,7 +1261,6 @@ # self.gmstc.GetParent().Show() s = s.replace('\n', os.linesep) - message = '' for line in s.split(os.linesep): if len(line) == 0: @@ -1251,14 +1289,21 @@ self.gmstc.AddText(line + os.linesep) self.gmstc.EnsureCaretVisible() p2 = self.gmstc.GetCurrentPos() - #self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleError) + self.gmstc.StartStyling(p1, 0xff) + self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleUnknown) if message != '': p1 = self.gmstc.GetCurrentPos() self.gmstc.AddText(message + os.linesep) self.gmstc.EnsureCaretVisible() p2 = self.gmstc.GetCurrentPos() - #self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleError) + self.gmstc.StartStyling(p1, 0xff) + if type == 'error': + self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleError) + elif type == 'warning': + self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleWarning) + elif type == 'message': + self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleMessage) class GMStc(wx.stc.StyledTextCtrl): """Styled GMConsole @@ -1275,33 +1320,67 @@ wx.stc.StyledTextCtrl.__init__(self, parent, id) self.parent = parent + # # styles - self.StyleDefault = 0 + # + self.StyleDefault = 0 self.StyleDefaultSpec = "face:Courier New,size:10,fore:#000000,back:#FFFFFF" - self.StyleOutput = 1 - self.StyleOutputSpec = "face:Courier New,size:10,fore:#0000FF,back:#FFFFFF" - self.StyleError = 2 - self.StyleErrorSpec = "face:Courier New,size:10,fore:#7F0000,back:#FFFFFF" + self.StyleCommand = 1 + self.StyleCommandSpec = "face:Courier New,size:10,fore:#000000,back:#bcbcbc" + self.StyleOutput = 2 + self.StyleOutputSpec = "face:Courier New,size:10,fore:#000000,back:#FFFFFF" + # fatal error + self.StyleError = 3 + self.StyleErrorSpec = "face:Courier New,size:10,fore:#7F0000,back:#FFFFFF" + # warning + self.StyleWarning = 4 + self.StyleWarningSpec = "face:Courier New,size:10,fore:#0000FF,back:#FFFFFF" + # message + self.StyleMessage = 5 + self.StyleMessageSpec = "face:Courier New,size:10,fore:#000000,back:#FFFFFF" + # unknown + self.StyleUnknown = 6 + self.StyleUnknownSpec = "face:Courier New,size:10,fore:#7F0000,back:#FFFFFF" # default and clear => init self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, self.StyleDefaultSpec) self.StyleClearAll() - self.StyleSetSpec(self.StyleOutput, self.StyleOutputSpec) - self.StyleSetSpec(self.StyleError, self.StyleErrorSpec) + self.StyleSetSpec(self.StyleCommand, self.StyleCommandSpec) + self.StyleSetSpec(self.StyleOutput, self.StyleOutputSpec) + self.StyleSetSpec(self.StyleError, self.StyleErrorSpec) + self.StyleSetSpec(self.StyleWarning, self.StyleWarningSpec) + self.StyleSetSpec(self.StyleMessage, self.StyleMessageSpec) + self.StyleSetSpec(self.StyleUnknown, self.StyleUnknownSpec) + # # margin widths + # self.SetMarginWidth(0, 0) self.SetMarginWidth(1, 0) self.SetMarginWidth(2, 0) - # miscellaneous, a few parameters + # + # miscellaneous + # self.SetMarginLeft(2) - self.SetViewWhiteSpace(True) + self.SetViewWhiteSpace(False) self.SetTabWidth(4) self.SetUseTabs(False) - #~ self.SetEOLMode(wx.stc.STC_EOL_CRLF) - #~ self.SetViewEOL(True) + # self.SetEOLMode(wx.stc.STC_EOL_CRLF) + # self.SetViewEOL(True) self.UsePopUp(True) self.SetSelBackground(True, "#FFFF00") - self.SetUseHorizontalScrollBar(True) + self.SetUseHorizontalScrollBar(False) + # + # bindins + # + self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy) + + def OnDestroy(self, evt): + """The clipboard contents can be preserved after + the app has exited""" + + wx.TheClipboard.Flush() + evt.Skip() + Modified: trunk/grassaddons/gui/wxgui.py =================================================================== --- trunk/grassaddons/gui/wxgui.py 2007-11-06 06:42:20 UTC (rev 1177) +++ trunk/grassaddons/gui/wxgui.py 2007-11-13 18:12:00 UTC (rev 1178) @@ -2,7 +2,6 @@ MODULE: wxgui.py CLASSES: - * GRasterDialog * GMFrame * GMApp * ProcessGrcXml @@ -82,137 +81,117 @@ menucmd = {} -class GRasterDialog(wx.Frame): - def __init__(self,parent,id=-1,title="Set raster layer"): - wx.Frame.__init__(self, parent, id , title, size=(50,600)) - - # sizers - sizer = wx.BoxSizer(wx.VERTICAL) - buttsizer = wx.BoxSizer(wx.HORIZONTAL) - - # labels - lmap = wx.StaticText(self,-1,"Map name") - lvalues = wx.StaticText(self,-1,"List of values to be displayed") - lopaque = wx.StaticText(self,-1,"Transparency") - - # checkboxes - cboverlay = wx.CheckBox(self, -1, "Overlay (non-null values)") - cboverlay.SetValue(True) - - # text entries - tmapname = wx.TextCtrl(self,-1,size=(-1,-1)) - tvalues = wx.TextCtrl(self,-1,size=(-1,-1)) - - # buttons - bsize=(75,-1) - bok = wx.Button(self,-1, "OK",size=bsize) - bapply = wx.Button(self,-1, "Apply", size=bsize) - bcancel = wx.Button(self,-1, "Cancel", size=bsize) - - buttsizer.Add(bok, 0, wx.ADJUST_MINSIZE, 1) - buttsizer.Add(bapply, 0, wx.ADJUST_MINSIZE, 1) - buttsizer.Add(bcancel, 0, wx.ADJUST_MINSIZE, 1) - sizer.Add(lopaque,1, wx.EXPAND, 1) - sizer.Add(lmap,0, wx.EXPAND, 1) - sizer.Add(tmapname,0, wx.EXPAND, 1) - sizer.Add(lvalues,0, wx.EXPAND, 1) - sizer.Add(tvalues,0, wx.EXPAND, 1) - sizer.Add(cboverlay,1, wx.EXPAND, 1) - sizer.Add(buttsizer,0, wx.ADJUST_MINSIZE, 1) - self.SetSizer(sizer) - sizer.Fit(self) - self.Layout() - class GMFrame(wx.Frame): """ GIS Manager frame with notebook widget for controlling GRASS GIS. Includes command console page for typing GRASS (and other) commands, tree widget page for managing GIS map layers. """ - def __init__(self, parent, id, title): - self.parent = parent - self.iconsize = (16, 16) - wx.Frame.__init__(self, parent=parent, id=-1, title=title, style=wx.DEFAULT_FRAME_STYLE) + def __init__(self, parent, id=wx.ID_ANY, title=_("GRASS GIS Layer Manager")): + self.parent = parent + self.baseTitle = title + self.iconsize = (16, 16) - self.CreateStatusBar() + wx.Frame.__init__(self, parent=parent, id=id, + style=wx.DEFAULT_FRAME_STYLE) + self.SetTitle(self.baseTitle) + self.SetIcon(wx.Icon(os.path.join(imagepath, 'grass.smlogo.gif'), wx.BITMAP_TYPE_ANY)) + self._auimgr = wx.aui.AuiManager(self) # creating widgets - self.notebook = self.__createNoteBook() - - self.cmdinput = self.__createCommandInput() + # -> self.notebook, self.goutput, self.outpage + self.notebook = self.__createNoteBook() self.cmdprompt = self.__createCommandPrompt() - self.menubar = self.__createMenuBar() - toolbar = self.__createToolBar() - #self.panel = wx.Panel(self,-1, style= wx.EXPAND) - self.sizer= wx.BoxSizer(wx.VERTICAL) - # self.cmdsizer = wx.BoxSizer(wx.HORIZONTAL) + self.menubar = self.__createMenuBar() + self.toolbar = self.__createToolBar() + self.statusbar = self.CreateStatusBar(number=1) - # do layout - self.SetTitle(_("GRASS GIS Layer Manager")) - self.SetMinSize((500, 400)) - self.SetIcon(wx.Icon(os.path.join(imagepath,'grass.smlogo.gif'), wx.BITMAP_TYPE_ANY)) - # set environmental variables os.environ["GRASS_RENDER_IMMEDIATE"] = "TRUE" # initialize variables - self.disp_idx = 0 # index value for map displays and layer trees - self.curr_page = '' # currently selected page for layer tree notebook - self.curr_pagenum = '' # currently selected page number for layer tree notebook - self.encoding = 'ISO-8859-1' # default encoding for display fonts - self.workspaceFile = None # workspace file + self.disp_idx = 0 # index value for map displays and layer trees + self.curr_page = '' # currently selected page for layer tree notebook + self.curr_pagenum = '' # currently selected page number for layer tree notebook + self.encoding = 'ISO-8859-1' # default encoding for display fonts + self.workspaceFile = None # workspace file - self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) - self.Bind(wx.EVT_LEFT_DOWN, self.AddRaster) + # bindings + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + self.Bind(wx.EVT_LEFT_DOWN, self.AddRaster, self.notebook) - self._auimgr.AddPane(toolbar, wx.aui.AuiPaneInfo().ToolbarPane(). - Top().Dockable(False).CloseButton(False). - DestroyOnClose(True).Row(0).Layer(0)) + # minimal frame size + self.SetMinSize((500, 400)) + + # AUI stuff + # self._auimgr.AddPane(self.toolbar, wx.aui.AuiPaneInfo().ToolbarPane(). + # Top().Dockable(False).CloseButton(False). + # DestroyOnClose(True).Row(0).Layer(0)) self._auimgr.AddPane(self.notebook, wx.aui.AuiPaneInfo(). - Left().CentrePane().BestSize((-1,-1)).Dockable(False). - CloseButton(False).DestroyOnClose(True).Row(1).Layer(0)) + Left().CentrePane().BestSize((-1,-1)).Dockable(False). + CloseButton(False).DestroyOnClose(True).Row(1).Layer(0)) self._auimgr.AddPane(self.cmdprompt, wx.aui.AuiPaneInfo(). - Bottom().BestSize((-1,25)).Dockable(False). - CloseButton(False).DestroyOnClose(True). - PaneBorder(False).Row(2).Layer(0).Position(0). - Fixed().CaptionVisible(False).PinButton(False)) - self._auimgr.AddPane(self.cmdinput, wx.aui.AuiPaneInfo(). - Bottom().BestSize((-1,25)).Dockable(False). - CloseButton(False).DestroyOnClose(True). - PaneBorder(False).Row(2).Layer(0).Position(1). - CaptionVisible(False)) + Bottom().BestSize((-1,25)).Dockable(False). + CloseButton(False).DestroyOnClose(True). + PaneBorder(False).Row(1).Layer(0).Position(0). + CaptionVisible(False)) + self._auimgr.Update() - # item, proportion, flag, border, userData -# self.sizer.Add(self.notebook, proportion=1, flag=wx.EXPAND, border=1) -# self.sizer.Add(self.cmdinput, proportion=0, flag=wx.EXPAND, border=1) -# self.SetSizer(self.sizer) - self.sizer.Fit(self) - self.Layout() wx.CallAfter(self.notebook.SetSelection, 0) # start default initial display self.NewDisplay() + + def __doLayout(self): + """Do Layout (unused bacause of aui manager...)""" + # self.panel = wx.Panel(self,-1, style= wx.EXPAND) + # sizer= wx.BoxSizer(wx.VERTICAL) + # self.cmdsizer = wx.BoxSizer(wx.HORIZONTAL) + # item, proportion, flag, border, userData + # self.sizer.Add(self.notebook, proportion=1, flag=wx.EXPAND, border=1) + # self.sizer.Add(self.cmdinput, proportion=0, flag=wx.EXPAND, border=1) + # self.SetSizer(self.sizer) + + # self.sizer.Fit(self) + # self.Layout() + def __createCommandPrompt(self): - """Creates command prompt""" - self.cmdprompt = wx.StaticText(self, -1, "GRASS>") - return self.cmdprompt + """Creates command-line input area""" + self.cmdprompt = wx.Panel(self) + + label = wx.StaticText(parent=self.cmdprompt, id=wx.ID_ANY, label="GRASS>", + size=(-1, 25)) + input = wx.TextCtrl(parent=self.cmdprompt, id=wx.ID_ANY, + value="", + style=wx.HSCROLL | wx.TE_LINEWRAP | wx.TE_PROCESS_ENTER, + size=(-1, 25)) - def __createCommandInput(self): - """Creates command input area""" - self.cmdinput = wx.TextCtrl(self, id=wx.ID_ANY, value="", style=wx.HSCROLL | wx.TE_LINEWRAP | - wx.TE_PROCESS_ENTER) + input.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.NORMAL, 0, '')) - self.cmdinput.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.NORMAL, 0, '')) - wx.CallAfter(self.cmdinput.SetInsertionPoint, 0) + wx.CallAfter(input.SetInsertionPoint, 0) - self.Bind(wx.EVT_TEXT_ENTER, self.OnRunCmd, self.cmdinput) + self.Bind(wx.EVT_TEXT_ENTER, self.OnRunCmd, input) + self.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar, input) - return self.cmdinput + # layout + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(item=label, proportion=0, + flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER, + border=4) + sizer.Add(item=input, proportion=1, + flag=wx.EXPAND | wx.ALL, + border=1) + self.cmdprompt.SetSizer(sizer) + sizer.Fit(self.cmdprompt) + self.cmdprompt.Layout() + + return self.cmdprompt + def __createMenuBar(self): """Creates menubar""" @@ -228,7 +207,7 @@ return self.menubar def __createMenu(self, menuData): - """Cretes menu""" + """Creates menu""" menu = wx.Menu() for eachItem in menuData: @@ -257,31 +236,49 @@ """Creates notebook widgets""" # create main notebook widget - nbStyle=FN.FNB_FANCY_TABS|FN.FNB_BOTTOM|FN.FNB_NO_X_BUTTON|FN.FNB_NO_NAV_BUTTONS - self.notebook = FN.FlatNotebook(self, id=wx.ID_ANY, style=nbStyle) + nbStyle = FN.FNB_FANCY_TABS | \ + FN.FNB_BOTTOM | \ + FN.FNB_NO_X_BUTTON | \ + FN.FNB_NO_NAV_BUTTONS + self.notebook = FN.FlatNotebook(parent=self, id=wx.ID_ANY, style=nbStyle) # create displays notebook widget and add it to main notebook page - cbStyle=FN.FNB_VC8|FN.FNB_BACKGROUND_GRADIENT|FN.FNB_X_ON_TAB|FN.FNB_TABS_BORDER_SIMPLE + cbStyle = FN.FNB_VC8 | \ + FN.FNB_BACKGROUND_GRADIENT | \ + FN.FNB_X_ON_TAB | \ + FN.FNB_TABS_BORDER_SIMPLE self.gm_cb = FN.FlatNotebook(self, id=wx.ID_ANY, style=cbStyle) self.gm_cb.SetTabAreaColour(wx.Colour(125,200,175)) - self.notebook.AddPage(self.gm_cb, text="Map layers for each display") + self.notebook.AddPage(self.gm_cb, text=_("Map layers for each display")) # create command output text area and add it to main notebook page self.goutput = wxgui_utils.GMConsole(self) - self.outpage = self.notebook.AddPage(self.goutput, text="Command output") + self.outpage = self.notebook.AddPage(self.goutput, text=_("Command output")) + # bingings self.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.onCBPageChanged, self.gm_cb) self.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CLOSING, self.onCBPageClosed, self.gm_cb) - self.out_sizer = wx.BoxSizer(wx.VERTICAL) - self.out_sizer.Add(self.goutput, proportion=1, flag=wx.EXPAND, border=1) - self.SetSizer(self.out_sizer) - #self.out_sizer.Fit(self.outpage) - #self.outpage.Layout() + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(item=self.goutput, proportion=1, + flag=wx.EXPAND | wx.ALL, border=1) + self.SetSizer(sizer) + # self.out_sizer.Fit(self.outpage) + # self.outpage.Layout() self.Centre() return self.notebook + def __createToolBar(self): + """Creates toolbar""" + + self.toolbar = self.CreateToolBar() + for each in self.ToolbarData(): + self.AddToolbarButton(self.toolbar, *each) + self.toolbar.Realize() + + return self.toolbar + def OnMenuHighlight(self, event): """ Default menu help handler @@ -359,14 +356,25 @@ self.gm_cb.GetPage(event.GetSelection()).maptree.Close(True) event.Skip() - def OnRunCmd(self,event): + def OnRunCmd(self, event): """Run command""" - #global gmpath - cmd = self.cmdinput.GetValue() + cmd = event.GetString() self.goutput.RunCmd(cmd) + self.OnUpdateStatusBar(None) + + def GetLogWindow(self): + """Get widget for command output""" + return self.goutput + + def OnUpdateStatusBar(self, event): + if event is None: + self.statusbar.SetStatusText("") + else: + self.statusbar.SetStatusText(_("Type GRASS command and run by pressing ENTER")) + def GetMenuCmd(self, event): """Get GRASS command from menu item @@ -464,6 +472,7 @@ self.LoadGrcXmlToLayerTree(filename) self.workspaceFile = filename + self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile)) def LoadGrcXmlToLayerTree(self, filename): """Load layer tree definition stored in GRC XML file @@ -524,9 +533,11 @@ maptree.Map.ReverseListOfLayers() file.close() - except: - dlg = wx.MessageDialog(self, _("Unable to read workspace file <%s>.") % filename, - _("Error"), wx.OK | wx.ICON_ERROR) + except Exception, err: + dlg = wx.MessageDialog(parent=self, + message=_("Unable to read workspace file <%s>.\n\n%s") % \ + (filename, err), + caption=_("Error"), style=wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return False @@ -562,6 +573,7 @@ self.SaveLayerTreeToGrcXml(filename) self.workspaceFile = filename + self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile)) def OnWorkspaceSave(self, event=None): """Save file with workspace definition""" @@ -685,8 +697,8 @@ Debug.msg(4, "GMFrame.OnWorkspaceClose(): file=%s" % self.workspaceFile) self.workspaceFile = None + self.SetTitle(self.baseTitle) - def RulesCmd(self, event): """ Launches dialog for commands that need rules @@ -802,14 +814,6 @@ self.profile.Update() - def __createToolBar(self): - """Creates toolbar""" - - toolbar = self.CreateToolBar() - for each in self.ToolbarData(): - self.AddToolbarButton(toolbar, *each) - toolbar.Realize() - def AddToolbarButton(self, toolbar, label, icon, help, handler): """Adds button to the given toolbar""" @@ -880,7 +884,8 @@ pointdata = (icon, size) self.dbmanager = dbm.AttributeManager(parent=self, id=wx.ID_ANY, - title=_("GRASS Attribute Table Manager: %s") % mapname, + title=_("GRASS GIS Attribute Table Manager - " + "vector map layer <%s>") % mapname, size=wx.Size(500,300), vectmap=mapname, pointdata=pointdata) @@ -1220,7 +1225,6 @@ sizer.Fit(self) - class GMApp(wx.App): """ GMApp class @@ -1240,7 +1244,7 @@ wx.Yield() # create and show main frame - mainframe = GMFrame(parent=None, id=wx.ID_ANY, title="") + mainframe = GMFrame(parent=None, id=wx.ID_ANY, title=_("GRASS GIS Layer Manager")) mainframe.Show() self.SetTopWindow(mainframe) @@ -1371,6 +1375,48 @@ print >> sys.stderr, _('re-executing using pythonw') os.execvp('pythonw',['pythonw',__file__] + sys.argv[1:]) +### 2007/11 -- seems to be unused... +# class GRasterDialog(wx.Frame): +# def __init__(self,parent,id=-1,title="Set raster layer"): +# wx.Frame.__init__(self, parent, id , title, size=(50,600)) + +# # sizers +# sizer = wx.BoxSizer(wx.VERTICAL) +# buttsizer = wx.BoxSizer(wx.HORIZONTAL) + +# # labels +# lmap = wx.StaticText(self,-1,"Map name") +# lvalues = wx.StaticText(self,-1,"List of values to be displayed") +# lopaque = wx.StaticText(self,-1,"Transparency") + +# # checkboxes +# cboverlay = wx.CheckBox(self, -1, "Overlay (non-null values)") +# cboverlay.SetValue(True) + +# # text entries +# tmapname = wx.TextCtrl(self,-1,size=(-1,-1)) +# tvalues = wx.TextCtrl(self,-1,size=(-1,-1)) + +# # buttons +# bsize=(75,-1) +# bok = wx.Button(self,-1, "OK",size=bsize) +# bapply = wx.Button(self,-1, "Apply", size=bsize) +# bcancel = wx.Button(self,-1, "Cancel", size=bsize) + +# buttsizer.Add(bok, 0, wx.ADJUST_MINSIZE, 1) +# buttsizer.Add(bapply, 0, wx.ADJUST_MINSIZE, 1) +# buttsizer.Add(bcancel, 0, wx.ADJUST_MINSIZE, 1) +# sizer.Add(lopaque,1, wx.EXPAND, 1) +# sizer.Add(lmap,0, wx.EXPAND, 1) +# sizer.Add(tmapname,0, wx.EXPAND, 1) +# sizer.Add(lvalues,0, wx.EXPAND, 1) +# sizer.Add(tvalues,0, wx.EXPAND, 1) +# sizer.Add(cboverlay,1, wx.EXPAND, 1) +# sizer.Add(buttsizer,0, wx.ADJUST_MINSIZE, 1) +# self.SetSizer(sizer) +# sizer.Fit(self) +# self.Layout() + if __name__ == "__main__": reexec_with_pythonw() From landa at grass.itc.it Tue Nov 13 21:55:53 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Tue Nov 13 21:55:55 2007 Subject: [grass-addons] r1179 - in trunk/grassaddons/gui: . display_driver gui_modules Message-ID: <200711132055.lADKtrA4017402@grass.itc.it> Author: landa Date: 2007-11-13 21:51:32 +0100 (Tue, 13 Nov 2007) New Revision: 1179 Removed: trunk/grassaddons/gui/display_driver/Makefile.in trunk/grassaddons/gui/display_driver/README trunk/grassaddons/gui/display_driver/pseudodc.cpp trunk/grassaddons/gui/display_driver/pseudodc.h Modified: trunk/grassaddons/gui/README trunk/grassaddons/gui/display_driver/Makefile trunk/grassaddons/gui/display_driver/driver.h trunk/grassaddons/gui/gui_modules/dbm.py trunk/grassaddons/gui/gui_modules/digit.py trunk/grassaddons/gui/wxgui.py Log: Redundant pseudodc files removed, README updated. Cosmetics in attribute table manager. Modified: trunk/grassaddons/gui/README =================================================================== --- trunk/grassaddons/gui/README 2007-11-13 18:12:00 UTC (rev 1178) +++ trunk/grassaddons/gui/README 2007-11-13 20:51:32 UTC (rev 1179) @@ -30,6 +30,19 @@ Solaris (SPARC), Windows: http://www.activestate.com/store/download.aspx?prdGUID=b08b04e0-6872-4d9d-a722-7a0c2dea2758 + E.g. On Debian GNU/Linux install these packages: + * libwxbase2.8-0 + * libwxbase2.8-dbg + * libwxbase2.8-dev + * libwxgtk2.8-0 + * libwxgtk2.8-dbg + * libwxgtk2.8-dev + * python-wxgtk2.8 + * wx2.8-doc + * wx2.8-examples + * wx2.8-headers + * wx2.8-i18n + 1 - INSTALLATION Download fresh source code from Subversion repository: @@ -134,3 +147,27 @@ To re-enable default icons (TCL/TK theme) $ g.gisenv set=GRASS_ICONPATH= + +7 - DIGITIZATION TOOL + +To enable digitization tool you need to compile display driver located +in directory 'display_driver'. + +Before compiling the driver go to the wxPython directory, e.g. + +$ cd /usr/lib/python2.4/site-packages/wx-2.8-gtk2-unicode/wx + +Make symlink + +sudo ln -s _gdi_.so libgdi.so + +Add /usr/lib/python2.4/site-packages/wx-2.8-gtk2-unicode/wx to +LIBRARY_PATH or edit /etc/ld.so.conf file. + +Then you can compile the driver + +$ cd $GISBASE/etc/wx/display_driver +$ make + +Note: You probably will need to modify the Makefile. This need to be +fixed in the future. \ No newline at end of file Modified: trunk/grassaddons/gui/display_driver/Makefile =================================================================== --- trunk/grassaddons/gui/display_driver/Makefile 2007-11-13 18:12:00 UTC (rev 1178) +++ trunk/grassaddons/gui/display_driver/Makefile 2007-11-13 20:51:32 UTC (rev 1179) @@ -1,3 +1,6 @@ +### Note: This is working file, to compile on your machine you need +### probably modify this Makefile... + PYTHONVERSION=2.4 MODULE_TOPDIR = ../../.. @@ -7,14 +10,14 @@ SWIG=swig -CFLAGS=-c -fpic -I/usr/include/python$(PYTHONVERSION) -I./ -I$(ARCH_DISTDIR)/include `wx-config --cxxflags` `gdal-config --cflags` +CFLAGS=-c -fpic -I/usr/include/python$(PYTHONVERSION) -I./ -I$(ARCH_DISTDIR)/include `wx-config --cxxflags` -LDFLAGS=-shared -L$(ARCH_LIBDIR) -lgrass_vect -lgrass_gis `wx-config --libs` +LDFLAGS=-shared -fpic -L$(ARCH_LIBDIR) -lgrass_vect -lgrass_gis `wx-config --libs` -L/usr/lib/python$(PYTHONVERSION)/site-packages/wx-2.8-gtk2-unicode/wx -lgdi default: grass6_wxdriver.so clean: - -rm -f *.o *.so grass6_wxdriver_wrap.cxx grass6_wxdriver.py grass6_wxdriver.i grass6_wxdriver.pyc + -rm -f *.o _grass6_wxdriver.so grass6_wxdriver_wrap.cxx grass6_wxdriver.py grass6_wxdriver.i grass6_wxdriver.pyc grass6_wxdriver.i: cat ./driver.i > grass6_wxdriver.i @@ -30,8 +33,5 @@ driver.o: driver.cpp driver.h $(CXX) $(CFLAGS) $(INCLUDE_DIRS) $< -pseudodc.o: pseudodc.cpp - $(CXX) $(CFLAGS) $(INCLUDE_DIRS) $< - -grass6_wxdriver.so: grass6_wxdriver_wrap.o driver.o pseudodc.o - $(CXX) $(LDFLAGS) grass6_wxdriver_wrap.o driver.o pseudodc.o -o _grass6_wxdriver.so +grass6_wxdriver.so: grass6_wxdriver_wrap.o driver.o # pseudodc.o + $(CXX) $(LDFLAGS) grass6_wxdriver_wrap.o driver.o -o _grass6_wxdriver.so Deleted: trunk/grassaddons/gui/display_driver/Makefile.in =================================================================== --- trunk/grassaddons/gui/display_driver/Makefile.in 2007-11-13 18:12:00 UTC (rev 1178) +++ trunk/grassaddons/gui/display_driver/Makefile.in 2007-11-13 20:51:32 UTC (rev 1179) @@ -1,38 +0,0 @@ -### DEFINITIONS - -PYTHONVERSION=@PYVERSION@ - -### END DEFINITIONS - -MODULE_TOPDIR = ../../.. - -include $(MODULE_TOPDIR)/include/Make/Lib.make -include $(MODULE_TOPDIR)/include/Make/Doxygen.make - -SWIG=swig - -CFLAGS=-c -fpic -I/usr/include/python$(PYTHONVERSION) -I./ -I$(ARCH_DISTDIR)/include `wx-config --cxxflags` - -LDFLAGS=-shared -L$(ARCH_LIBDIR) -lgrass_vect -lgrass_gis `wx-config --libs` - -default: grass6_wxdriver.so - -clean: - -rm -f *.o *.so grass6_wxdriver_wrap.cxx grass6_wxdriver.py grass6_wxdriver.i grass6_wxdriver.pyc - -grass6_wxdriver.i: - cat ./driver.i > grass6_wxdriver.i - echo "/* auto-generate swig typedef file (with some GRASS functions removed) */" >> grass6_wxdriver.i - cat ./driver.h >> grass6_wxdriver.i - -grass6_wxdriver_wrap.cxx: grass6_wxdriver.i - $(SWIG) -c++ -python -shadow $< - -grass6_wxdriver_wrap.o: grass6_wxdriver_wrap.cxx - $(CXX) $(CFLAGS) $(INCLUDE_DIRS) $< - -driver.o: driver.cc - $(CXX) $(CFLAGS) $(INCLUDE_DIRS) $< - -grass6_wxdriver.so: grass6_wxdriver_wrap.o driver.o - $(CXX) $(LDFLAGS) grass6_wxdriver_wrap.o driver.o -o _grass6_wxdriver.so Deleted: trunk/grassaddons/gui/display_driver/README =================================================================== --- trunk/grassaddons/gui/display_driver/README 2007-11-13 18:12:00 UTC (rev 1178) +++ trunk/grassaddons/gui/display_driver/README 2007-11-13 20:51:32 UTC (rev 1179) @@ -1,4 +0,0 @@ -Experimental C++ display driver for Digitization tool -===================================================== - -Under development ... *not* ready for testing! Modified: trunk/grassaddons/gui/display_driver/driver.h =================================================================== --- trunk/grassaddons/gui/display_driver/driver.h 2007-11-13 18:12:00 UTC (rev 1178) +++ trunk/grassaddons/gui/display_driver/driver.h 2007-11-13 20:51:32 UTC (rev 1179) @@ -19,8 +19,8 @@ #include #include -//#include -#include "pseudodc.h" +#include +//#include "pseudodc.h" extern "C" { #include Deleted: trunk/grassaddons/gui/display_driver/pseudodc.cpp =================================================================== --- trunk/grassaddons/gui/display_driver/pseudodc.cpp 2007-11-13 18:12:00 UTC (rev 1178) +++ trunk/grassaddons/gui/display_driver/pseudodc.cpp 2007-11-13 20:51:32 UTC (rev 1179) @@ -1,634 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: common/pseudodc.cpp -// Purpose: Implementation of the wxPseudoDC Class -// Author: Paul Lanier -// Modified by: -// Created: 05/25/06 -// RCS-ID: $Id: pseudodc.cpp 49047 2007-10-05 18:08:39Z RD $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -//include "wx/wxprec.h" - -#undef DEBUG -#include -#include "wx/wxPython/wxPython.h" -#include "wx/wxPython/pseudodc.h" - -// wxList based class definitions -#include -WX_DEFINE_LIST(pdcOpList); -WX_DEFINE_LIST(pdcObjectList); - -//---------------------------------------------------------------------------- -// Helper functions used for drawing greyed out versions of objects -//---------------------------------------------------------------------------- -wxColour &MakeColourGrey(const wxColour &c) -{ - static wxColour rval; - rval.Set(byte((230-c.Red())*0.7+c.Red()), - byte((230-c.Green())*0.7+c.Green()), - byte((230-c.Blue())*0.7+c.Blue())); - return rval; -} -wxBrush &GetGreyBrush(wxBrush &brush) -{ - static wxBrush b; - wxColour c; - b = brush; - c = MakeColourGrey(brush.GetColour()); - b.SetColour(c); - return b; -} - -wxPen &GetGreyPen(wxPen &pen) -{ - static wxPen p; - wxColour c; - p = pen; - c = MakeColourGrey(pen.GetColour()); - p.SetColour(c); - return p; -} - -void GreyOutImage(wxImage &img) -{ - unsigned char *data = img.GetData(); - unsigned char r,g,b; - unsigned char mr,mg,mb; - int i, tst; - int len = img.GetHeight()*img.GetWidth()*3; - if (img.HasMask()) - { - mr = img.GetMaskRed(); - mg = img.GetMaskGreen(); - mb = img.GetMaskBlue(); - } - tst=0; - for (i=0;iGetData()->DrawToDC(dc, m_greyedout); - node = node->GetNext(); - } -} - -// ---------------------------------------------------------------------------- -// Translate - translate all the operations by some dx,dy -// ---------------------------------------------------------------------------- -void pdcObject::Translate(wxCoord dx, wxCoord dy) -{ - pdcOpList::Node *node = m_oplist.GetFirst(); - while(node) - { - node->GetData()->Translate(dx,dy); - node = node->GetNext(); - } - if (m_bounded) - { - m_bounds.x += dx; - m_bounds.y += dy; - } -} - -// ---------------------------------------------------------------------------- -// SetGreyedOut - set the greyout member and cache grey versions of everything -// if greyout is true -// ---------------------------------------------------------------------------- -void pdcObject::SetGreyedOut(bool greyout) -{ - m_greyedout=greyout; - if (greyout) - { - pdcOpList::Node *node = m_oplist.GetFirst(); - pdcOp *obj; - while(node) - { - - obj = node->GetData(); - obj->CacheGrey(); - node = node->GetNext(); - } - } -} - -// ============================================================================ -// wxPseudoDC implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// Destructor -// ---------------------------------------------------------------------------- -wxPseudoDC::~wxPseudoDC() -{ - // delete all the nodes in the list - RemoveAll(); - -} - -// ---------------------------------------------------------------------------- -// ClearAll - remove all nodes from list -// ---------------------------------------------------------------------------- -void wxPseudoDC::RemoveAll(void) -{ - m_objectlist.Clear(); - m_objectIndex.clear(); - m_currId = -1; - m_lastObject = NULL; - -} - -// ---------------------------------------------------------------------------- -// GetLen - return the number of operations in the current op list -// ---------------------------------------------------------------------------- -int wxPseudoDC::GetLen(void) -{ - pdcObjectList::Node *pt = m_objectlist.GetFirst(); - int len=0; - while (pt) - { - len += pt->GetData()->GetLen(); - pt = pt->GetNext(); - } - return len; -} - -// ---------------------------------------------------------------------------- -// FindObject - find and return an object node by id. If node doesn't exist -// and create is true then create one and return it. Otherwise -// return NULL. -// ---------------------------------------------------------------------------- -pdcObject *wxPseudoDC::FindObject(int id, bool create) -{ - // see if last operation was for same id - //~ if (m_lastObject && m_lastObject->GetId() == id) - //~ return m_lastObject; - // if not then search for it - pdcObjectHash::iterator lookup = m_objectIndex.find(id); - if (lookup == m_objectIndex.end()) {//not found - if (create) { - m_lastObject = new pdcObject(id); - m_objectlist.Append(m_lastObject); - pdcObjectHash::value_type insert(id, m_lastObject); - m_objectIndex.insert(insert); - return m_lastObject; - } else { - return NULL; - } - } else { //found - return lookup->second; - } -} - -// ---------------------------------------------------------------------------- -// AddToList - Add a node to the list at the end (preserve draw order) -// ---------------------------------------------------------------------------- -void wxPseudoDC::AddToList(pdcOp *newOp) -{ - pdcObject *obj = FindObject(m_currId, true); - obj->AddOp(newOp); -} - -// ---------------------------------------------------------------------------- -// ClearID - remove all the operations associated with a single ID -// ---------------------------------------------------------------------------- -void wxPseudoDC::ClearId(int id) -{ - pdcObject *obj = FindObject(id); - if (obj) obj->Clear(); -} - -// ---------------------------------------------------------------------------- -// RemoveID - Remove the object node (and all operations) associated with an id -// ---------------------------------------------------------------------------- -void wxPseudoDC::RemoveId(int id) -{ - pdcObject *obj = FindObject(id); - if (obj) - { - if (m_lastObject == obj) - m_lastObject = obj; - m_objectlist.DeleteObject(obj); - } - m_objectIndex.erase(id); -} - -// ---------------------------------------------------------------------------- -// SetIdBounds - Set the bounding rect for a given id -// ---------------------------------------------------------------------------- -void wxPseudoDC::SetIdBounds(int id, wxRect& rect) -{ - pdcObject *obj = FindObject(id, true); - obj->SetBounds(rect); -} - -// ---------------------------------------------------------------------------- -// GetIdBounds - Get the bounding rect for a given id -// ---------------------------------------------------------------------------- -void wxPseudoDC::GetIdBounds(int id, wxRect& rect) -{ - pdcObject *obj = FindObject(id); - if (obj && obj->IsBounded()) - rect = obj->GetBounds(); - else - rect.x = rect.y = rect.width = rect.height = 0; -} - -// ---------------------------------------------------------------------------- -// TranslateId - Translate all the operations of a single id -// ---------------------------------------------------------------------------- -void wxPseudoDC::TranslateId(int id, wxCoord dx, wxCoord dy) -{ - pdcObject *obj = FindObject(id); - if (obj) obj->Translate(dx,dy); -} - -// ---------------------------------------------------------------------------- -// DrawIdToDC - Draw a specific id to the dc passed in -// ---------------------------------------------------------------------------- -void wxPseudoDC::DrawIdToDC(int id, wxDC *dc) -{ - pdcObject *obj = FindObject(id); - if (obj) obj->DrawToDC(dc); -} - -// ---------------------------------------------------------------------------- -// SetIdGreyedOut - Set the greyedout member of id -// ---------------------------------------------------------------------------- -void wxPseudoDC::SetIdGreyedOut(int id, bool greyout) -{ - pdcObject *obj = FindObject(id); - if (obj) obj->SetGreyedOut(greyout); -} - -// ---------------------------------------------------------------------------- -// GetIdGreyedOut - Get the greyedout member of id -// ---------------------------------------------------------------------------- -bool wxPseudoDC::GetIdGreyedOut(int id) -{ - pdcObject *obj = FindObject(id); - if (obj) return obj->GetGreyedOut(); - else return false; -} - -// ---------------------------------------------------------------------------- -// FindObjectsByBBox - Return a list of all the ids whose bounding boxes -// contain (x,y) -// ---------------------------------------------------------------------------- -PyObject *wxPseudoDC::FindObjectsByBBox(wxCoord x, wxCoord y) -{ - //wxPyBlock_t blocked = wxPyBeginBlockThreads(); - pdcObjectList::Node *pt = m_objectlist.GetFirst(); - pdcObject *obj; - PyObject* pyList = NULL; - pyList = PyList_New(0); - wxRect r; - while (pt) - { - obj = pt->GetData(); - r = obj->GetBounds(); - if (obj->IsBounded() && r.Contains(x,y)) - { - PyObject* pyObj = PyInt_FromLong((long)obj->GetId()); - PyList_Insert(pyList, 0, pyObj); - Py_DECREF(pyObj); - } - pt = pt->GetNext(); - } - //wxPyEndBlockThreads(blocked); - return pyList; -} - -// ---------------------------------------------------------------------------- -// FindObjects - Return a list of all the ids that draw to (x,y) -// ---------------------------------------------------------------------------- -PyObject *wxPseudoDC::FindObjects(wxCoord x, wxCoord y, - wxCoord radius, const wxColor& bg) -{ - //wxPyBlock_t blocked = wxPyBeginBlockThreads(); - pdcObjectList::Node *pt = m_objectlist.GetFirst(); - pdcObject *obj; - PyObject* pyList = NULL; - pyList = PyList_New(0); - wxBrush bgbrush(bg); - wxPen bgpen(bg); - // special case radius = 0 - if (radius == 0) - { - wxBitmap bmp(4,4,24); - wxMemoryDC memdc; - wxColor pix; - wxRect viewrect(x-2,y-2,4,4); - // setup the memdc for rendering - memdc.SelectObject(bmp); - memdc.SetBackground(bgbrush); - memdc.Clear(); - memdc.SetDeviceOrigin(2-x,2-y); - while (pt) - { - obj = pt->GetData(); - if (obj->IsBounded() && obj->GetBounds().Contains(x,y)) - { - // start clean - memdc.SetBrush(bgbrush); - memdc.SetPen(bgpen); - memdc.DrawRectangle(viewrect); - // draw the object - obj->DrawToDC(&memdc); - memdc.GetPixel(x,y,&pix); - // clear and update rgn2 - if (pix != bg) - { - PyObject* pyObj = PyInt_FromLong((long)obj->GetId()); - PyList_Insert(pyList, 0, pyObj); - Py_DECREF(pyObj); - } - } - pt = pt->GetNext(); - } - memdc.SelectObject(wxNullBitmap); - } - else - { - wxRect viewrect(x-radius,y-radius,2*radius,2*radius); - wxBitmap maskbmp(2*radius,2*radius,24); - wxMemoryDC maskdc; - // create bitmap with circle for masking - maskdc.SelectObject(maskbmp); - maskdc.SetBackground(*wxBLACK_BRUSH); - maskdc.Clear(); - maskdc.SetBrush(*wxWHITE_BRUSH); - maskdc.SetPen(*wxWHITE_PEN); - maskdc.DrawCircle(radius,radius,radius); - // now setup a memdc for rendering our object - wxBitmap bmp(2*radius,2*radius,24); - wxMemoryDC memdc; - memdc.SelectObject(bmp); - // set the origin so (x,y) is in the bmp center - memdc.SetDeviceOrigin(radius-x,radius-y); - // a region will be used to see if the result is empty - wxRegion rgn2; - while (pt) - { - obj = pt->GetData(); - if (obj->IsBounded() && viewrect.Intersects(obj->GetBounds())) - { - // start clean - //memdc.Clear(); - memdc.SetBrush(bgbrush); - memdc.SetPen(bgpen); - memdc.DrawRectangle(viewrect); - // draw the object - obj->DrawToDC(&memdc); - // remove background color - memdc.SetLogicalFunction(wxXOR); - memdc.SetBrush(bgbrush); - memdc.SetPen(bgpen); - memdc.DrawRectangle(viewrect); - memdc.SetLogicalFunction(wxCOPY); -#ifdef __WXMAC__ - // wxAND is not supported on wxMac, but it doesn't seem to - // hurt anything to use wxCOPY instead... - memdc.Blit(x-radius,y-radius,2*radius,2*radius,&maskdc,0,0,wxCOPY); -#else - // AND with circle bitmap - memdc.Blit(x-radius,y-radius,2*radius,2*radius,&maskdc,0,0,wxAND); -#endif - // clear and update rgn2 - memdc.SelectObject(wxNullBitmap); - rgn2.Clear(); - rgn2.Union(bmp, *wxBLACK); - //rgn2.Intersect(rgn); - memdc.SelectObject(bmp); - if (!rgn2.IsEmpty()) - { - PyObject* pyObj = PyInt_FromLong((long)obj->GetId()); - PyList_Insert(pyList, 0, pyObj); - Py_DECREF(pyObj); - } - } - pt = pt->GetNext(); - } - maskdc.SelectObject(wxNullBitmap); - memdc.SelectObject(wxNullBitmap); - } - //wxPyEndBlockThreads(blocked); - return pyList; -} - -// ---------------------------------------------------------------------------- -// DrawToDCClipped - play back the op list to the DC but clip any objects -// known to be not in rect. This is a coarse level of -// clipping to speed things up when lots of objects are off -// screen and doesn't affect the dc level clipping -// ---------------------------------------------------------------------------- -void wxPseudoDC::DrawToDCClipped(wxDC *dc, const wxRect& rect) -{ - pdcObjectList::Node *pt = m_objectlist.GetFirst(); - pdcObject *obj; - while (pt) - { - obj = pt->GetData(); - if (!obj->IsBounded() || rect.Intersects(obj->GetBounds())) - obj->DrawToDC(dc); - pt = pt->GetNext(); - } -} -void wxPseudoDC::DrawToDCClippedRgn(wxDC *dc, const wxRegion& region) -{ - pdcObjectList::Node *pt = m_objectlist.GetFirst(); - pdcObject *obj; - while (pt) - { - obj = pt->GetData(); - if (!obj->IsBounded() || - (region.Contains(obj->GetBounds()) != wxOutRegion)) - obj->DrawToDC(dc); - pt = pt->GetNext(); - } -} - -// ---------------------------------------------------------------------------- -// DrawToDC - play back the op list to the DC -// ---------------------------------------------------------------------------- -void wxPseudoDC::DrawToDC(wxDC *dc) -{ - pdcObjectList::Node *pt = m_objectlist.GetFirst(); - while (pt) - { - pt->GetData()->DrawToDC(dc); - pt = pt->GetNext(); - } -} - Deleted: trunk/grassaddons/gui/display_driver/pseudodc.h =================================================================== --- trunk/grassaddons/gui/display_driver/pseudodc.h 2007-11-13 18:12:00 UTC (rev 1178) +++ trunk/grassaddons/gui/display_driver/pseudodc.h 2007-11-13 20:51:32 UTC (rev 1179) @@ -1,825 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: pseudodc.h -// Purpose: wxPseudoDC class -// Author: Paul Lanier -// Modified by: -// Created: 05/25/06 -// RCS-ID: $Id: pseudodc.h 49047 2007-10-05 18:08:39Z RD $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// -#ifndef _WX_PSUEDO_DC_H_BASE_ -#define _WX_PSUEDO_DC_H_BASE_ - -//---------------------------------------------------------------------------- -// Base class for all pdcOp classes -//---------------------------------------------------------------------------- -class pdcOp -{ - public: - // Constructor and Destructor - pdcOp() {} - virtual ~pdcOp() {} - - // Virtual Drawing Methods - virtual void DrawToDC(wxDC *dc, bool grey=false)=0; - virtual void Translate(wxCoord WXUNUSED(dx), wxCoord WXUNUSED(dy)) {} - virtual void CacheGrey() {} -}; - -//---------------------------------------------------------------------------- -// declare a list class for list of pdcOps -//---------------------------------------------------------------------------- -WX_DECLARE_LIST(pdcOp, pdcOpList); - - -//---------------------------------------------------------------------------- -// Helper functions used for drawing greyed out versions of objects -//---------------------------------------------------------------------------- -wxColour &MakeColourGrey(const wxColour &c); -wxBrush &GetGreyBrush(wxBrush &brush); -wxPen &GetGreyPen(wxPen &pen); -wxIcon &GetGreyIcon(wxIcon &icon); -wxBitmap &GetGreyBitmap(wxBitmap &bmp); - -//---------------------------------------------------------------------------- -// Classes derived from pdcOp -// There is one class for each method mirrored from wxDC to wxPseudoDC -//---------------------------------------------------------------------------- -class pdcSetFontOp : public pdcOp -{ - public: - pdcSetFontOp(const wxFont& font) - {m_font=font;} - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->SetFont(m_font);} - protected: - wxFont m_font; -}; - -class pdcSetBrushOp : public pdcOp -{ - public: - pdcSetBrushOp(const wxBrush& brush) - {m_greybrush=m_brush=brush;} - virtual void DrawToDC(wxDC *dc, bool grey=false) - { - if (!grey) dc->SetBrush(m_brush); - else dc->SetBrush(m_greybrush); - } - virtual void CacheGrey() {m_greybrush=GetGreyBrush(m_brush);} - protected: - wxBrush m_brush; - wxBrush m_greybrush; -}; - -class pdcSetBackgroundOp : public pdcOp -{ - public: - pdcSetBackgroundOp(const wxBrush& brush) - {m_greybrush=m_brush=brush;} - virtual void DrawToDC(wxDC *dc, bool grey=false) - { - if (!grey) dc->SetBackground(m_brush); - else dc->SetBackground(m_greybrush); - } - virtual void CacheGrey() {m_greybrush=GetGreyBrush(m_brush);} - protected: - wxBrush m_brush; - wxBrush m_greybrush; -}; - -class pdcSetPenOp : public pdcOp -{ - public: - pdcSetPenOp(const wxPen& pen) - {m_greypen=m_pen=pen;} - virtual void DrawToDC(wxDC *dc, bool grey=false) - { - if (!grey) dc->SetPen(m_pen); - else dc->SetPen(m_greypen); - } - virtual void CacheGrey() {m_greypen=GetGreyPen(m_pen);} - protected: - wxPen m_pen; - wxPen m_greypen; -}; - -class pdcSetTextBackgroundOp : public pdcOp -{ - public: - pdcSetTextBackgroundOp(const wxColour& colour) - {m_colour=colour;} - virtual void DrawToDC(wxDC *dc, bool grey=false) - { - if (!grey) dc->SetTextBackground(m_colour); - else dc->SetTextBackground(MakeColourGrey(m_colour)); - } - protected: - wxColour m_colour; -}; - -class pdcSetTextForegroundOp : public pdcOp -{ - public: - pdcSetTextForegroundOp(const wxColour& colour) - {m_colour=colour;} - virtual void DrawToDC(wxDC *dc, bool grey=false) - { - if (!grey) dc->SetTextForeground(m_colour); - else dc->SetTextForeground(MakeColourGrey(m_colour)); - } - protected: - wxColour m_colour; -}; - -class pdcDrawRectangleOp : public pdcOp -{ - public: - pdcDrawRectangleOp(wxCoord x, wxCoord y, wxCoord w, wxCoord h) - {m_x=x; m_y=y; m_w=w; m_h=h;} - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->DrawRectangle(m_x,m_y,m_w,m_h);} - virtual void Translate(wxCoord dx, wxCoord dy) - {m_x+=dx;m_y+=dy;} - protected: - wxCoord m_x,m_y,m_w,m_h; -}; - -class pdcDrawLineOp : public pdcOp -{ - public: - pdcDrawLineOp(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) - {m_x1=x1; m_y1=y1; m_x2=x2; m_y2=y2;} - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->DrawLine(m_x1,m_y1,m_x2,m_y2);} - virtual void Translate(wxCoord dx, wxCoord dy) - {m_x1+=dx; m_y1+=dy; m_x2+=dx; m_y2+=dy;} - protected: - wxCoord m_x1,m_y1,m_x2,m_y2; -}; - -class pdcSetBackgroundModeOp : public pdcOp -{ - public: - pdcSetBackgroundModeOp(int mode) {m_mode=mode;} - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->SetBackgroundMode(m_mode);} - protected: - int m_mode; -}; - -class pdcDrawTextOp : public pdcOp -{ - public: - pdcDrawTextOp(const wxString& text, wxCoord x, wxCoord y) - {m_text=text; m_x=x; m_y=y;} - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->DrawText(m_text, m_x, m_y);} - virtual void Translate(wxCoord dx, wxCoord dy) - {m_x+=dx; m_y+=dy;} - protected: - wxString m_text; - wxCoord m_x, m_y; -}; - -class pdcClearOp : public pdcOp -{ - public: - pdcClearOp() {} - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->Clear();} -}; - -class pdcBeginDrawingOp : public pdcOp -{ - public: - pdcBeginDrawingOp() {} - virtual void DrawToDC(wxDC *WXUNUSED(dc), bool WXUNUSED(grey)=false) {} -}; - -class pdcEndDrawingOp : public pdcOp -{ - public: - pdcEndDrawingOp() {} - virtual void DrawToDC(wxDC *WXUNUSED(dc), bool WXUNUSED(grey)=false) {} -}; - -class pdcFloodFillOp : public pdcOp -{ - public: - pdcFloodFillOp(wxCoord x, wxCoord y, const wxColour& col, - int style) {m_x=x; m_y=y; m_col=col; m_style=style;} - virtual void DrawToDC(wxDC *dc, bool grey=false) - { - if (!grey) dc->FloodFill(m_x,m_y,m_col,m_style); - else dc->FloodFill(m_x,m_y,MakeColourGrey(m_col),m_style); - } - virtual void Translate(wxCoord dx, wxCoord dy) - {m_x+=dx; m_y+=dy;} - protected: - wxCoord m_x,m_y; - wxColour m_col; - int m_style; -}; - -class pdcCrossHairOp : public pdcOp -{ - public: - pdcCrossHairOp(wxCoord x, wxCoord y) {m_x=x; m_y=y;} - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->CrossHair(m_x,m_y);} - virtual void Translate(wxCoord dx, wxCoord dy) - {m_x+=dx; m_y+=dy;} - protected: - wxCoord m_x,m_y; -}; - -class pdcDrawArcOp : public pdcOp -{ - public: - pdcDrawArcOp(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, - wxCoord xc, wxCoord yc) - {m_x1=x1; m_y1=y1; m_x2=x2; m_y2=y2; m_xc=xc; m_yc=yc;} - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) - {dc->DrawArc(m_x1,m_y1,m_x2,m_y2,m_xc,m_yc);} - virtual void Translate(wxCoord dx, wxCoord dy) - {m_x1+=dx; m_x2+=dx; m_y1+=dy; m_y2+=dy;} - protected: - wxCoord m_x1,m_x2,m_xc; - wxCoord m_y1,m_y2,m_yc; -}; - -class pdcDrawCheckMarkOp : public pdcOp -{ - public: - pdcDrawCheckMarkOp(wxCoord x, wxCoord y, - wxCoord width, wxCoord height) - {m_x=x; m_y=y; m_w=width; m_h=height;} - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) - {dc->DrawCheckMark(m_x,m_y,m_w,m_h);} - virtual void Translate(wxCoord dx, wxCoord dy) - {m_x+=dx; m_y+=dy;} - protected: - wxCoord m_x,m_y,m_w,m_h; -}; - -class pdcDrawEllipticArcOp : public pdcOp -{ - public: - pdcDrawEllipticArcOp(wxCoord x, wxCoord y, wxCoord w, wxCoord h, - double sa, double ea) - {m_x=x; m_y=y; m_w=w; m_h=h; m_sa=sa; m_ea=ea;} - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) - {dc->DrawEllipticArc(m_x,m_y,m_w,m_h,m_sa,m_ea);} - virtual void Translate(wxCoord dx, wxCoord dy) - {m_x+=dx; m_y+=dy;} - protected: - wxCoord m_x,m_y,m_w,m_h; - double m_sa,m_ea; -}; - -class pdcDrawPointOp : public pdcOp -{ - public: - pdcDrawPointOp(wxCoord x, wxCoord y) - {m_x=x; m_y=y;} - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->DrawPoint(m_x,m_y);} - virtual void Translate(wxCoord dx, wxCoord dy) - {m_x+=dx; m_y+=dy;} - protected: - wxCoord m_x,m_y; -}; - -class pdcDrawRoundedRectangleOp : public pdcOp -{ - public: - pdcDrawRoundedRectangleOp(wxCoord x, wxCoord y, wxCoord width, - wxCoord height, double radius) - {m_x=x; m_y=y; m_w=width; m_h=height; m_r=radius;} - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) - {dc->DrawRoundedRectangle(m_x,m_y,m_w,m_h,m_r);} - virtual void Translate(wxCoord dx, wxCoord dy) - {m_x+=dx; m_y+=dy;} - protected: - wxCoord m_x,m_y,m_w,m_h; - double m_r; -}; - -class pdcDrawEllipseOp : public pdcOp -{ - public: - pdcDrawEllipseOp(wxCoord x, wxCoord y, wxCoord width, wxCoord height) - {m_x=x; m_y=y; m_w=width; m_h=height;} - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->DrawEllipse(m_x,m_y,m_w,m_h);} - virtual void Translate(wxCoord dx, wxCoord dy) - {m_x+=dx; m_y+=dy;} - protected: - wxCoord m_x,m_y,m_w,m_h; -}; - -class pdcDrawIconOp : public pdcOp -{ - public: - pdcDrawIconOp(const wxIcon& icon, wxCoord x, wxCoord y) - {m_icon=icon; m_x=x; m_y=y;} - virtual void DrawToDC(wxDC *dc, bool grey=false) - { - if (grey) dc->DrawIcon(m_greyicon,m_x,m_y); - else dc->DrawIcon(m_icon,m_x,m_y); - } - virtual void CacheGrey() {m_greyicon=GetGreyIcon(m_icon);} - virtual void Translate(wxCoord dx, wxCoord dy) - {m_x+=dx; m_y+=dy;} - protected: - wxIcon m_icon; - wxIcon m_greyicon; - wxCoord m_x,m_y; -}; - -class pdcDrawLinesOp : public pdcOp -{ - public: - pdcDrawLinesOp(int n, wxPoint points[], - wxCoord xoffset = 0, wxCoord yoffset = 0); - virtual ~pdcDrawLinesOp(); - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) - {dc->DrawLines(m_n,m_points,m_xoffset,m_yoffset);} - virtual void Translate(wxCoord dx, wxCoord dy) - { - for(int i=0; iDrawPolygon(m_n,m_points,m_xoffset,m_yoffset,m_fillStyle);} - - virtual void Translate(wxCoord dx, wxCoord dy) - { - for(int i=0; iDrawPolyPolygon(m_n,m_count,m_points, - m_xoffset,m_yoffset,m_fillStyle);} - virtual void Translate(wxCoord dx, wxCoord dy) - { - for(int i=0; iDrawRotatedText(m_text,m_x,m_y,m_angle);} - virtual void Translate(wxCoord dx, wxCoord dy) - {m_x+=dx; m_y+=dy;} - protected: - wxString m_text; - wxCoord m_x,m_y; - double m_angle; -}; - -class pdcDrawBitmapOp : public pdcOp -{ - public: - pdcDrawBitmapOp(const wxBitmap &bmp, wxCoord x, wxCoord y, - bool useMask = false) - {m_bmp=bmp; m_x=x; m_y=y; m_useMask=useMask;} - virtual void DrawToDC(wxDC *dc, bool grey=false) - { - if (grey) dc->DrawBitmap(m_greybmp,m_x,m_y,m_useMask); - else dc->DrawBitmap(m_bmp,m_x,m_y,m_useMask); - } - virtual void CacheGrey() {m_greybmp=GetGreyBitmap(m_bmp);} - virtual void Translate(wxCoord dx, wxCoord dy) - {m_x+=dx; m_y+=dy;} - protected: - wxBitmap m_bmp; - wxBitmap m_greybmp; - wxCoord m_x,m_y; - bool m_useMask; -}; - -class pdcDrawLabelOp : public pdcOp -{ - public: - pdcDrawLabelOp(const wxString& text, - const wxBitmap& image, - const wxRect& rect, - int alignment = wxALIGN_LEFT | wxALIGN_TOP, - int indexAccel = -1) - {m_text=text; m_image=image; m_rect=rect; - m_align=alignment; m_iAccel=indexAccel;} - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) - {dc->DrawLabel(m_text,m_image,m_rect,m_align,m_iAccel);} - virtual void Translate(wxCoord dx, wxCoord dy) - {m_rect.x+=dx; m_rect.y+=dy;} - protected: - wxString m_text; - wxBitmap m_image; - wxRect m_rect; - int m_align; - int m_iAccel; -}; - -#if wxUSE_SPLINES -class pdcDrawSplineOp : public pdcOp -{ - public: - pdcDrawSplineOp(int n, wxPoint points[]); - virtual ~pdcDrawSplineOp(); - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->DrawSpline(m_n,m_points);} - virtual void Translate(wxCoord dx, wxCoord dy) - { - int i; - for(i=0; iSetPalette(m_palette);} - protected: - wxPalette m_palette; -}; -#endif // wxUSE_PALETTE - -class pdcSetLogicalFunctionOp : public pdcOp -{ - public: - pdcSetLogicalFunctionOp(int function) {m_function=function;} - virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->SetLogicalFunction(m_function);} - protected: - int m_function; -}; - -//---------------------------------------------------------------------------- -// pdcObject type to contain list of operations for each real (Python) object -//---------------------------------------------------------------------------- -class pdcObject -{ - public: - pdcObject(int id) - {m_id=id; m_bounded=false; m_oplist.DeleteContents(true); - m_greyedout=false;} - - virtual ~pdcObject() {m_oplist.Clear();} - - // Protected Member Access - void SetId(int id) {m_id=id;} - int GetId() {return m_id;} - void SetBounds(wxRect& rect) {m_bounds=rect; m_bounded=true;} - wxRect GetBounds() {return m_bounds;} - void SetBounded(bool bounded) {m_bounded=bounded;} - bool IsBounded() {return m_bounded;} - void SetGreyedOut(bool greyout=true); - bool GetGreyedOut() {return m_greyedout;} - - // Op List Management Methods - void Clear() {m_oplist.Clear();} - void AddOp(pdcOp *op) - { - m_oplist.Append(op); - if (m_greyedout) op->CacheGrey(); - } - int GetLen() {return m_oplist.GetCount();} - virtual void Translate(wxCoord dx, wxCoord dy); - - // Drawing Method - virtual void DrawToDC(wxDC *dc); - protected: - int m_id; // id of object (associates this pdcObject - // with a Python object with same id) - wxRect m_bounds; // bounding rect of this object - bool m_bounded; // true if bounds is valid, false by default - pdcOpList m_oplist; // list of operations for this object - bool m_greyedout; // if true then draw this object in greys only -}; - - -//---------------------------------------------------------------------------- -// Declare a wxList to hold all the objects. List order reflects drawing -// order (Z order) and is the same order as objects are added to the list -//---------------------------------------------------------------------------- -class pdcObjectList; -WX_DECLARE_LIST(pdcObject, pdcObjectList); - -//Declare a hashmap that maps from ids to nodes in the object list. -WX_DECLARE_HASH_MAP( - int, - pdcObject *, - wxIntegerHash, - wxIntegerEqual, - pdcObjectHash -); - - -// ---------------------------------------------------------------------------- -// wxPseudoDC class -// ---------------------------------------------------------------------------- -// This is the actual PseudoDC class -// This class stores a list of recorded dc operations in m_list -// and plays them back to a real dc using DrawToDC or DrawToDCClipped. -// Drawing methods are mirrored from wxDC but add nodes to m_list -// instead of doing any real drawing. -// ---------------------------------------------------------------------------- -class wxPseudoDC : public wxObject -{ -public: - wxPseudoDC() - {m_currId=-1; m_lastObject=NULL; m_objectlist.DeleteContents(true);m_objectIndex.clear();} - ~wxPseudoDC(); - // ------------------------------------------------------------------------ - // List managment methods - // - void RemoveAll(); - int GetLen(); - - // ------------------------------------------------------------------------ - // methods for managing operations by ID - // - // Set the Id for all subsequent operations (until SetId is called again) - void SetId(int id) {m_currId = id;} - // Remove all the operations associated with an id so it can be redrawn - void ClearId(int id); - // Remove the object node (and all operations) associated with an id - void RemoveId(int id); - // Set the bounding rect of a given object - // This will create an object node if one doesn't exist - void SetIdBounds(int id, wxRect& rect); - void GetIdBounds(int id, wxRect& rect); - // Translate all the operations for this id - void TranslateId(int id, wxCoord dx, wxCoord dy); - // Grey-out an object - void SetIdGreyedOut(int id, bool greyout=true); - bool GetIdGreyedOut(int id); - // Find Objects at a point. Returns Python list of id's - // sorted in reverse drawing order (result[0] is top object) - // This version looks at drawn pixels - PyObject *FindObjects(wxCoord x, wxCoord y, - wxCoord radius=1, const wxColor& bg=*wxWHITE); - // This version only looks at bounding boxes - PyObject *FindObjectsByBBox(wxCoord x, wxCoord y); - - // ------------------------------------------------------------------------ - // Playback Methods - // - // draw to dc but skip objects known to be outside of rect - // This is a coarse level of clipping to speed things up - // when lots of objects are off screen and doesn't affect the dc level - // clipping - void DrawToDCClipped(wxDC *dc, const wxRect& rect); - void DrawToDCClippedRgn(wxDC *dc, const wxRegion& region); - // draw to dc with no clipping (well the dc will still clip) - void DrawToDC(wxDC *dc); - // draw a single object to the dc - void DrawIdToDC(int id, wxDC *dc); - - // ------------------------------------------------------------------------ - // Hit Detection Methods - // - // returns list of object with a drawn pixel within radius pixels of (x,y) - // the list is in reverse draw order so last drawn is first in list - // PyObject *HitTest(wxCoord x, wxCoord y, double radius) - // returns list of objects whose bounding boxes include (x,y) - // PyObject *HitTestBB(wxCoord x, wxCoord y) - - - // ------------------------------------------------------------------------ - // Methods mirrored from wxDC - // - void FloodFill(wxCoord x, wxCoord y, const wxColour& col, - int style = wxFLOOD_SURFACE) - {AddToList(new pdcFloodFillOp(x,y,col,style));} - void FloodFill(const wxPoint& pt, const wxColour& col, - int style = wxFLOOD_SURFACE) - { FloodFill(pt.x, pt.y, col, style); } - - void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) - {AddToList(new pdcDrawLineOp(x1, y1, x2, y2));} - void DrawLine(const wxPoint& pt1, const wxPoint& pt2) - { DrawLine(pt1.x, pt1.y, pt2.x, pt2.y); } - - void CrossHair(wxCoord x, wxCoord y) - {AddToList(new pdcCrossHairOp(x,y));} - void CrossHair(const wxPoint& pt) - { CrossHair(pt.x, pt.y); } - - void DrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, - wxCoord xc, wxCoord yc) - {AddToList(new pdcDrawArcOp(x1,y1,x2,y2,xc,yc));} - void DrawArc(const wxPoint& pt1, const wxPoint& pt2, const wxPoint& centre) - { DrawArc(pt1.x, pt1.y, pt2.x, pt2.y, centre.x, centre.y); } - - void DrawCheckMark(wxCoord x, wxCoord y, - wxCoord width, wxCoord height) - {AddToList(new pdcDrawCheckMarkOp(x,y,width,height));} - void DrawCheckMark(const wxRect& rect) - { DrawCheckMark(rect.x, rect.y, rect.width, rect.height); } - - void DrawEllipticArc(wxCoord x, wxCoord y, wxCoord w, wxCoord h, - double sa, double ea) - {AddToList(new pdcDrawEllipticArcOp(x,y,w,h,sa,ea));} - void DrawEllipticArc(const wxPoint& pt, const wxSize& sz, - double sa, double ea) - { DrawEllipticArc(pt.x, pt.y, sz.x, sz.y, sa, ea); } - - void DrawPoint(wxCoord x, wxCoord y) - {AddToList(new pdcDrawPointOp(x,y));} - void DrawPoint(const wxPoint& pt) - { DrawPoint(pt.x, pt.y); } - - void DrawPolygon(int n, wxPoint points[], - wxCoord xoffset = 0, wxCoord yoffset = 0, - int fillStyle = wxODDEVEN_RULE) - {AddToList(new pdcDrawPolygonOp(n,points,xoffset,yoffset,fillStyle));} - - void DrawPolyPolygon(int n, int count[], wxPoint points[], - wxCoord xoffset = 0, wxCoord yoffset = 0, - int fillStyle = wxODDEVEN_RULE) - {AddToList(new pdcDrawPolyPolygonOp(n,count,points,xoffset,yoffset,fillStyle));} - - void DrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height) - {AddToList(new pdcDrawRectangleOp(x, y, width, height));} - void DrawRectangle(const wxPoint& pt, const wxSize& sz) - { DrawRectangle(pt.x, pt.y, sz.x, sz.y); } - void DrawRectangle(const wxRect& rect) - { DrawRectangle(rect.x, rect.y, rect.width, rect.height); } - - void DrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, - double radius) - {AddToList(new pdcDrawRoundedRectangleOp(x,y,width,height,radius));} - void DrawRoundedRectangle(const wxPoint& pt, const wxSize& sz, - double radius) - { DrawRoundedRectangle(pt.x, pt.y, sz.x, sz.y, radius); } - void DrawRoundedRectangle(const wxRect& r, double radius) - { DrawRoundedRectangle(r.x, r.y, r.width, r.height, radius); } - - void DrawCircle(wxCoord x, wxCoord y, wxCoord radius) - { DrawEllipse(x - radius, y - radius, 2*radius, 2*radius); } - void DrawCircle(const wxPoint& pt, wxCoord radius) - { DrawCircle(pt.x, pt.y, radius); } - - void DrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height) - {AddToList(new pdcDrawEllipseOp(x,y,width,height));} - void DrawEllipse(const wxPoint& pt, const wxSize& sz) - { DrawEllipse(pt.x, pt.y, sz.x, sz.y); } - void DrawEllipse(const wxRect& rect) - { DrawEllipse(rect.x, rect.y, rect.width, rect.height); } - - void DrawIcon(const wxIcon& icon, wxCoord x, wxCoord y) - {AddToList(new pdcDrawIconOp(icon,x,y));} - void DrawIcon(const wxIcon& icon, const wxPoint& pt) - { DrawIcon(icon, pt.x, pt.y); } - - void DrawLines(int n, wxPoint points[], - wxCoord xoffset = 0, wxCoord yoffset = 0) - {AddToList(new pdcDrawLinesOp(n,points,xoffset,yoffset));} - - void DrawBitmap(const wxBitmap &bmp, wxCoord x, wxCoord y, - bool useMask = false) - {AddToList(new pdcDrawBitmapOp(bmp,x,y,useMask));} - void DrawBitmap(const wxBitmap &bmp, const wxPoint& pt, - bool useMask = false) - { DrawBitmap(bmp, pt.x, pt.y, useMask); } - - void DrawText(const wxString& text, wxCoord x, wxCoord y) - {AddToList(new pdcDrawTextOp(text, x, y));} - void DrawText(const wxString& text, const wxPoint& pt) - { DrawText(text, pt.x, pt.y); } - - void DrawRotatedText(const wxString& text, wxCoord x, wxCoord y, double angle) - {AddToList(new pdcDrawRotatedTextOp(text,x,y,angle));} - void DrawRotatedText(const wxString& text, const wxPoint& pt, double angle) - { DrawRotatedText(text, pt.x, pt.y, angle); } - - // this version puts both optional bitmap and the text into the given - // rectangle and aligns is as specified by alignment parameter; it also - // will emphasize the character with the given index if it is != -1 - void DrawLabel(const wxString& text, - const wxBitmap& image, - const wxRect& rect, - int alignment = wxALIGN_LEFT | wxALIGN_TOP, - int indexAccel = -1) - {AddToList(new pdcDrawLabelOp(text,image,rect,alignment,indexAccel));} - - void DrawLabel(const wxString& text, const wxRect& rect, - int alignment = wxALIGN_LEFT | wxALIGN_TOP, - int indexAccel = -1) - { DrawLabel(text, wxNullBitmap, rect, alignment, indexAccel); } - -/*?????? I don't think that the source dc would stick around - void Blit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, - wxDC *source, wxCoord xsrc, wxCoord ysrc, - int rop = wxCOPY, bool useMask = false, wxCoord xsrcMask = wxDefaultCoord, wxCoord ysrcMask = wxDefaultCoord) - {AddToList(new pdcBlitOp(xdest,ydest,width,height,source,xsrc, - ysrc,rop,useMask,xsrcMask,ysrcMask));} - void Blit(const wxPoint& destPt, const wxSize& sz, - wxDC *source, const wxPoint& srcPt, - int rop = wxCOPY, bool useMask = false, const wxPoint& srcPtMask = wxDefaultPosition) - { - Blit(destPt.x, destPt.y, sz.x, sz.y, source, srcPt.x, srcPt.y, - rop, useMask, srcPtMask.x, srcPtMask.y); - } -??????*/ - -#if wxUSE_SPLINES - void DrawSpline(int n, wxPoint points[]) - {AddToList(new pdcDrawSplineOp(n,points));} -#endif // wxUSE_SPLINES - -#if wxUSE_PALETTE - void SetPalette(const wxPalette& palette) - {AddToList(new pdcSetPaletteOp(palette));} -#endif // wxUSE_PALETTE - - void SetLogicalFunction(int function) - {AddToList(new pdcSetLogicalFunctionOp(function));} - void SetFont(const wxFont& font) - {AddToList(new pdcSetFontOp(font));} - void SetPen(const wxPen& pen) - {AddToList(new pdcSetPenOp(pen));} - void SetBrush(const wxBrush& brush) - {AddToList(new pdcSetBrushOp(brush));} - void SetBackground(const wxBrush& brush) - {AddToList(new pdcSetBackgroundOp(brush));} - void SetBackgroundMode(int mode) - {AddToList(new pdcSetBackgroundModeOp(mode));} - void SetTextBackground(const wxColour& colour) - {AddToList(new pdcSetTextBackgroundOp(colour));} - void SetTextForeground(const wxColour& colour) - {AddToList(new pdcSetTextForegroundOp(colour));} - - void Clear() - {AddToList(new pdcClearOp());} - void BeginDrawing() - {AddToList(new pdcBeginDrawingOp());} - void EndDrawing() - {AddToList(new pdcEndDrawingOp());} - -protected: - // ------------------------------------------------------------------------ - // protected helper methods - void AddToList(pdcOp *newOp); - pdcObject *FindObject(int id, bool create=false); - - // ------------------------------------------------------------------------ - // Data members - // - int m_currId; // id to use for operations done on the PseudoDC - pdcObject *m_lastObject; // used to find last used object quickly - pdcObjectList m_objectlist; // list of objects - pdcObjectHash m_objectIndex; //id->object lookup index - -}; - -#endif - Modified: trunk/grassaddons/gui/gui_modules/dbm.py =================================================================== --- trunk/grassaddons/gui/gui_modules/dbm.py 2007-11-13 18:12:00 UTC (rev 1178) +++ trunk/grassaddons/gui/gui_modules/dbm.py 2007-11-13 20:51:32 UTC (rev 1179) @@ -99,7 +99,7 @@ self.SetImageList(self.il, wx.IMAGE_LIST_SMALL) if self.gismgr: # Layer Manager is running? - self.mapdisp = self.curr_page.maptree.mapdisplay + self.mapdisp = self.gismgr.curr_page.maptree.mapdisplay self.map = self.gismgr.curr_page.maptree.Map else: self.mapdisp = self.map = None @@ -512,13 +512,21 @@ # flatnotebook (browse, create, alter) self.notebook = FN.FlatNotebook(parent=self, id=wx.ID_ANY, style=FN.FNB_BOTTOM | FN.FNB_NO_X_BUTTON | - FN.FNB_NO_NAV_BUTTONS) + FN.FNB_NO_NAV_BUTTONS | FN.FNB_FANCY_TABS) self.browsePage = FN.FlatNotebook(self, id=wx.ID_ANY, - style=FN.FNB_NO_X_BUTTON) + style=FN.FNB_NO_X_BUTTON | FN.FNB_VC8 | + FN.FNB_BACKGROUND_GRADIENT | + FN.FNB_TABS_BORDER_SIMPLE) self.notebook.AddPage(self.browsePage, text=_("Browse data")) + self.browsePage.SetTabAreaColour(wx.Colour(125,200,175)) + self.managePage = FN.FlatNotebook(self, id=wx.ID_ANY, - style=FN.FNB_NO_X_BUTTON) + style=FN.FNB_NO_X_BUTTON | FN.FNB_VC8 | + FN.FNB_BACKGROUND_GRADIENT | + FN.FNB_TABS_BORDER_SIMPLE) self.notebook.AddPage(self.managePage, text=_("Manage tables")) + self.managePage.SetTabAreaColour(wx.Colour(125,200,175)) + self.notebook.SetSelection(0) # select browse tab self.infoCollapseLabelExp = _("Click here to show database connection information") @@ -543,10 +551,8 @@ # do layout self.__layout() - self.SetMinSize((640, 480)) + self.SetMinSize(self.GetBestSize()) - self.Show() - def __createBrowsePage(self): """Create browse tab page""" for layer in self.mapInfo.layers.keys(): @@ -877,7 +883,7 @@ btnSizer.AddButton(self.btnApply) btnSizer.Realize() - mainSizer.Add(item=self.notebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) + mainSizer.Add(item=self.notebook, proportion=1, flag=wx.EXPAND) mainSizer.Add(item=btnSizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) self.SetSizer(mainSizer) @@ -1458,6 +1464,8 @@ title=_("GRASS GIS Attribute Table Manager - vector map layer <%s>") % \ argv[1], size=(700,600), vectmap=argv[1]) + f.Show() + app.MainLoop() if __name__ == '__main__': Modified: trunk/grassaddons/gui/gui_modules/digit.py =================================================================== --- trunk/grassaddons/gui/gui_modules/digit.py 2007-11-13 18:12:00 UTC (rev 1178) +++ trunk/grassaddons/gui/gui_modules/digit.py 2007-11-13 20:51:32 UTC (rev 1179) @@ -50,7 +50,7 @@ from grass6_wxdriver import DisplayDriver except: print >> sys.stderr, "Digitization tool is disabled.\n" \ - "Under development...\n" + "Detailed information in README file." USEVEDIT = True Modified: trunk/grassaddons/gui/wxgui.py =================================================================== --- trunk/grassaddons/gui/wxgui.py 2007-11-13 18:12:00 UTC (rev 1178) +++ trunk/grassaddons/gui/wxgui.py 2007-11-13 20:51:32 UTC (rev 1179) @@ -860,8 +860,10 @@ maptype = None if not maptype or maptype != 'vector': - dlg = wx.MessageDialog(self, _("Attribute management is available only for vector map layers"), - _("Error"), wx.OK | wx.ICON_ERROR) + dlg = wx.MessageDialog(parent=self, + message=_("Attribute management is available only " + "for vector map layers"), + caption=_("Error"), style=wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return @@ -888,6 +890,7 @@ "vector map layer <%s>") % mapname, size=wx.Size(500,300), vectmap=mapname, pointdata=pointdata) + self.dbmanager.Show() def NewDisplay(self, event=None): """ From landa at grass.itc.it Wed Nov 14 23:04:16 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Wed Nov 14 23:04:19 2007 Subject: [grass-addons] r1180 - trunk/grassaddons/gui/gui_modules Message-ID: <200711142204.lAEM4Gsj007979@grass.itc.it> Author: landa Date: 2007-11-14 23:03:29 +0100 (Wed, 14 Nov 2007) New Revision: 1180 Added: trunk/grassaddons/gui/gui_modules/globalvar.py Modified: trunk/grassaddons/gui/gui_modules/dbm.py trunk/grassaddons/gui/gui_modules/digit.py trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/render.py Log: Minor improvements in Attribute Table Manager. New module for global variables. Modified: trunk/grassaddons/gui/gui_modules/dbm.py =================================================================== --- trunk/grassaddons/gui/gui_modules/dbm.py 2007-11-13 20:51:32 UTC (rev 1179) +++ trunk/grassaddons/gui/gui_modules/dbm.py 2007-11-14 22:03:29 UTC (rev 1180) @@ -42,6 +42,7 @@ import sqlbuilder import grassenv import gcmd +import globalvar from debug import Debug as Debug class Log: @@ -60,7 +61,7 @@ """ Support virtual attribute list class """ - def __init__(self, parent, log, mapInfo, layer, gismgr=None, pointdata=None): + def __init__(self, parent, log, mapInfo, layer): wx.ListCtrl.__init__( self, parent=parent, id=wx.ID_ANY, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES | wx.LC_VIRTUAL) @@ -69,15 +70,7 @@ # self.log = log self.mapInfo = mapInfo - self.gismgr = gismgr # Layer Manager instance or None self.layer = layer - self.qlayer = None - if pointdata: - self.icon = pointdata[0] - self.pointsize = pointdata[1] - else: - self.icon = '' - self.pointsize = '' self.columns = {} # <- LoadData() self.selectedCats = [] @@ -98,12 +91,6 @@ (16,16))) self.SetImageList(self.il, wx.IMAGE_LIST_SMALL) - if self.gismgr: # Layer Manager is running? - self.mapdisp = self.gismgr.curr_page.maptree.mapdisplay - self.map = self.gismgr.curr_page.maptree.Map - else: - self.mapdisp = self.map = None - # These two should probably be passed to init more cleanly # setting the numbers of items = number of elements in the dictionary self.itemDataMap = {} @@ -122,7 +109,6 @@ # events self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected) - self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated) self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColumnClick) # sorting # self.Bind(wx.EVT_LIST_DELETE_ITEM, self.OnItemDelete, self.list) # self.Bind(wx.EVT_LIST_COL_RIGHT_CLICK, self.OnColRightClick, self.list) @@ -133,13 +119,6 @@ # self.list.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) # self.list.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) - if self.gismgr: - self.mapdisp.MapWindow.Bind(wx.EVT_LEFT_DOWN, self.OnMapClick) - - # self.timer = wx.PyTimer(self.RedrawMap) - # check each 0.1s - # self.timer.Start(100) - def LoadData(self, layer, cols='*', where=''): """Load data into list""" @@ -166,8 +145,6 @@ self.log.write(_("Can display only 256 columns")) ### self.mapInfo.SelectFromTable(layer, cols, where) # <- values (FIXME) - # select values (only one record) - # # read data # @@ -211,13 +188,6 @@ self.SetColumnWidth(col=i, width=self.columns[col]['length'] * 6) # FIXME i += 1 - - - def OnCloseWindow(self, event): - """Close attribute manager window""" - if self.qlayer: - self.map.DeleteLayer(self.qlayer) - def OnItemSelected(self, event): """Item selected. Add item to selected cats...""" self.selectedCats.append(int(self.GetItemText(event.m_itemIndex))) @@ -234,14 +204,6 @@ print "#-", self.selectedCats event.Skip() - def OnItemActivated(self, event): - """Item activated, log purpose""" - self.currentItem = event.m_itemIndex - # self.log.write("OnItemActivated: %s\nTopItem: %s\n" % - # (self.GetItemText(self.currentItem), self.GetTopItem())) - print "#" - event.Skip() - def GetColumnText(self, index, col): """Return column text""" item = self.GetItem(index, col) @@ -321,62 +283,6 @@ item = self.GetItem(index, col) return item.GetText() - def RedrawMap(self): - """Redraw a map""" - if self.lastTurnSelectedCats[:] != self.selectedCats[:]: - if self.qlayer: - self.map.DeleteLayer(self.qlayer) - - cats = self.selectedCats - catstr = "" - i = 0 - while 1: - next = 0 - j = 0 - while 1: - try: - if cats[i+j]+1 == cats[i+j+1]: - next +=1 - else: - break - except IndexError: - next = 0 - if j+i >= len(cats)-2: - break - else: - j += 1 - if next > 1: - catstr += "%d-%d," % (cats[i], cats[i+next]) - i += next - else: - catstr += "%d," % (cats[i]) - - i += 1 - if i >= len(cats): - break - - if catstr[-1] == ",": - catstr = string.join(catstr[:-1],"") - - - # FIXME: width=1, because of maybe bug in PNG driver elusion - # should be width=3 or something like this - cmd = ["d.vect", - "map=%s" % self.vectmap, - "color=yellow", - "fcolor=yellow", - "cats=%s" % catstr, - "width=3"] - if self.icon: - gcmd.append("icon=%s" % (self.icon)) - if self.pointsize: - gcmd.append("size=%s" % (self.pointsize)) - - self.qlayer = self.map.AddLayer(type='vector', name='qlayer', command=cmd, - l_active=True, l_hidden=True, l_opacity=1.0) - self.mapdisp.ReDraw() - self.lastTurnSelectedCats = self.selectedCats[:] - def OnMapClick(self, event): """ Gets coordinates from mouse clicking on display window @@ -482,17 +388,32 @@ self.vectmap = vectmap self.pointdata = pointdata - self.parent = parent - self.gismgr = parent + self.parent = parent # GMFrame + try: + self.map = self.parent.curr_page.maptree.Map + self.mapdisplay = self.parent.curr_page.maptree.mapdisplay + except: + self.map = self.mapdisplay = None + if pointdata: + self.icon = pointdata[0] + self.pointsize = pointdata[1] + else: + self.icon = None + self.pointsize = None + + # status bar log class self.log = Log(self) # -> statusbar + # query map layer (if parent (GMFrame) is given) + self.qlayer = None + # -> layers / tables description self.mapInfo = VectorDBInfo(self.vectmap) if len(self.mapInfo.layers.keys()) == 0: - dlg = wx.MessageDialog(patent=parent, + dlg = wx.MessageDialog(patent=self.parent, message=_("No attribute table linked to " "vector map <%s> found.") % \ self.vectmap, @@ -543,8 +464,8 @@ # self.btn_unselect = wx.Button(self, -1, "Unselect") # events - self.btnApply.Bind(wx.EVT_BUTTON, self.OnApplySqlStatement) - self.btnQuit.Bind(wx.EVT_BUTTON, self.OnCloseWindow) + self.btnApply.Bind(wx.EVT_BUTTON, self.OnApplySqlStatement) + self.btnQuit.Bind(wx.EVT_BUTTON, self.OnCloseWindow) self.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnLayerPageChanged, self.browsePage) self.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnLayerPageChanged, self.managePage) @@ -553,6 +474,12 @@ self.SetMinSize(self.GetBestSize()) + def __del__(self): + pass + # if self.qlayer and self.map: + # self.map.DeleteLayer(self.qlayer) + # self.mapdisplay.ReRender(None) + def __createBrowsePage(self): """Create browse tab page""" for layer in self.mapInfo.layers.keys(): @@ -565,9 +492,10 @@ listBox = wx.StaticBox(parent=panel, id=wx.ID_ANY, label=" %s " % _("Attribute data")) listSizer = wx.StaticBoxSizer(listBox, wx.VERTICAL) - win = VirtualAttributeList(parent=panel, gismgr=self.parent, log=self.log, - mapInfo=self.mapInfo, layer=layer, - pointdata=self.pointdata) # layer + win = VirtualAttributeList(panel, self.log, + self.mapInfo, layer) + win.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnDataItemActivated) + listSizer.Add(item=win, proportion=1, flag=wx.EXPAND | wx.ALL, border=3) @@ -639,19 +567,19 @@ panel.SetSizer(pageSizer) - self.layerPage[layer]= {'list' : win, - 'simple' : sqlSimple, - 'advanced' : sqlAdvanced, - 'where' : sqlWhere, - 'builder' : btnSqlBuilder, - 'statement': sqlStatement} + self.layerPage[layer]= {'data' : win.GetId(), + 'simple' : sqlSimple.GetId(), + 'advanced' : sqlAdvanced.GetId(), + 'where' : sqlWhere.GetId(), + 'builder' : btnSqlBuilder.GetId(), + 'statement': sqlStatement.GetId()} self.browsePage.SetSelection(0) # select first layer self.layer = self.mapInfo.layers.keys()[0] self.OnChangeSql(None) self.log.write(_("Number of loaded records: %d") % \ - self.layerPage[self.layer]['list'].GetItemCount()) + self.FindWindowById(self.layerPage[self.layer]['data']).GetItemCount()) def __createManagePage(self): """Create manage page (create/link and alter tables)""" @@ -678,6 +606,10 @@ tableSizer = wx.StaticBoxSizer(tableBox, wx.VERTICAL) list = self.__createTableDesc(panel, table) + list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnTableRightUp) #wxMSW + list.Bind(wx.EVT_RIGHT_UP, self.OnTableRightUp) #wxGTK + self.layerPage[layer]['tableData'] = list.GetId() + tableSizer.Add(item=list, flag=wx.ALL | wx.EXPAND, proportion=1, @@ -695,7 +627,7 @@ panel.SetSizer(pageSizer) - self.layerPage[layer]['dbinfo'] = infoCollapse + self.layerPage[layer]['dbinfo'] = infoCollapse.GetId() self.managePage.SetSelection(0) # select first layer self.layer = self.mapInfo.layers.keys()[0] @@ -717,49 +649,126 @@ return list + def __layout(self): + """Do layout""" + # frame body + mainSizer = wx.BoxSizer(wx.VERTICAL) + + # buttons + btnSizer = wx.StdDialogButtonSizer() + btnSizer.AddButton(self.btnQuit) + btnSizer.AddButton(self.btnApply) + btnSizer.Realize() + + mainSizer.Add(item=self.notebook, proportion=1, flag=wx.EXPAND) + mainSizer.Add(item=btnSizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) + + self.SetSizer(mainSizer) + mainSizer.Fit(self) + + self.Layout() + + def OnTableRightUp(self, event): + """Table description area, context menu""" + if not hasattr(self, "popupID1"): + self.popupID1 = wx.NewId() + self.popupID2 = wx.NewId() + self.popupID3 = wx.NewId() + self.popupID4 = wx.NewId() + self.Bind(wx.EVT_MENU, self.OnTableItemAdd, id=self.popupID1) + self.Bind(wx.EVT_MENU, self.OnTableItemDelete, id=self.popupID2) + self.Bind(wx.EVT_MENU, self.OnTableItemDeleteAll, id=self.popupID3) + self.Bind(wx.EVT_MENU, self.OnTableReload, id=self.popupID4) + + # generate popup-menu + menu = wx.Menu() + menu.Append(self.popupID1, _("Add new column")) + menu.AppendSeparator() + menu.Append(self.popupID2, _("Delete selected")) + if self.FindWindowById(self.layerPage[self.layer]['tableData']).GetFirstSelected() == -1: + menu.Enable(self.popupID2, False) + menu.Append(self.popupID3, _("Delete all")) + menu.AppendSeparator() + menu.Append(self.popupID4, _("Reload")) + + self.PopupMenu(menu) + menu.Destroy() + + def OnTableItemDelete(self, event): + """Delete selected item(s) from the list (layer/category pair)""" + list = self.FindWindowById(self.layerPage[self.layer]['tableData']) + item = list.GetFirstSelected() + while item != -1: + # layer = int (self.list.GetItem(item, 0).GetText()) + # cat = int (self.list.GetItem(item, 1).GetText()) + list.DeleteItem(item) + # self.cats[layer].remove(cat) + + item = list.GetFirstSelected() + + event.Skip() + + def OnTableItemDeleteAll(self, event): + """Delete all items from the list""" + self.FindWindowById(self.layerPage[self.layer]['tableData']).DeleteAllItems() + # self.cats = {} + + event.Skip() + + def OnTableReload(self, event): + """Reload table description""" + pass + + def OnTableItemAdd(self, event): + """Add new column to the table""" + pass + def OnLayerPageChanged(self, event): """Layer tab changed""" pageNum = event.GetSelection() self.layer = self.mapInfo.layers.keys()[pageNum] self.OnChangeSql(None) self.log.write(_("Number of loaded records: %d") % \ - self.layerPage[self.layer]['list'].GetItemCount()) + self.FindWindowById(self.layerPage[self.layer]['data']).GetItemCount()) def OnChangeSql(self, event): """Switch simple/advanced sql statement""" - if self.layerPage[self.layer]['simple'].GetValue(): - self.layerPage[self.layer]['where'].Enable(True) - self.layerPage[self.layer]['statement'].Enable(False) - self.layerPage[self.layer]['builder'].Enable(False) + if self.FindWindowById(self.layerPage[self.layer]['simple']).GetValue(): + self.FindWindowById(self.layerPage[self.layer]['where']).Enable(True) + self.FindWindowById(self.layerPage[self.layer]['statement']).Enable(False) + self.FindWindowById(self.layerPage[self.layer]['builder']).Enable(False) else: - self.layerPage[self.layer]['where'].Enable(False) - self.layerPage[self.layer]['statement'].Enable(True) - self.layerPage[self.layer]['builder'].Enable(True) + self.FindWindowById(self.layerPage[self.layer]['where']).Enable(False) + self.FindWindowById(self.layerPage[self.layer]['statement']).Enable(True) + self.FindWindowById(self.layerPage[self.layer]['builder']).Enable(True) def OnApplySqlStatement(self, event): """Apply simple/advanced sql statement""" - if self.layerPage[self.layer]['simple'].GetValue(): + if self.FindWindowById(self.layerPage[self.layer]['simple']).GetValue(): # simple sql statement - where = self.layerPage[self.layer]['where'].GetValue().strip() + where = self.FindWindowById(self.layerPage[self.layer]['where']).GetValue().strip() if len(where) > 0: - self.layerPage[self.layer]['list'].LoadData(self.layer, where=where) + self.FindWindowById(self.layerPage[self.layer]['data']).LoadData( \ + self.layer, where=where) else: - self.layerPage[self.layer]['list'].LoadData(self.layer) + self.FindWindowById(self.layerPage[self.layer]['data']).LoadData( \ + self.layer) else: # advanced sql statement valid, cols, where = \ self.ValidateSelectStatement( \ - self.layerPage[self.layer]['statement'].GetValue().strip()) + self.FindWindowById(self.layerPage[self.layer]['statement']).GetValue().strip()) Debug.msg(4, "AttributeManager.OnApplySqlStatament(): valid=%s, cols=%s, where=%s" % (valid, cols, where)) if valid is True: - self.layerPage[self.layer]['list'].LoadData(self.layer, cols=cols, where=where) + self.FindWindowById(self.layerPage[self.layer]['data']).LoadData( \ + self.layer, cols=cols, where=where) # update statusbar self.log.write(_("Number of loaded records: %d") % \ - self.layerPage[self.layer]['list'].GetItemCount()) + self.FindWindowById(self.layerPage[self.layer]['data']).GetItemCount()) def ValidateSelectStatement(self, statement): """Validate Select SQL statement @@ -803,10 +812,12 @@ def OnInfoPaneChanged(self, event): """Collapse database connection info box""" - if self.layerPage[self.layer]['dbinfo'].IsExpanded(): - self.layerPage[self.layer]['dbinfo'].SetLabel(self.infoCollapseLabelCol) + if self.FindWindowById(self.layerPage[self.layer]['dbinfo']).IsExpanded(): + self.FindWindowById(self.layerPage[self.layer]['dbinfo']).SetLabel( \ + self.infoCollapseLabelCol) else: - self.layerPage[self.layer]['dbinfo'].SetLabel(self.infoCollapseLabelExp) + self.FindWindowById(self.layerPage[self.layer]['dbinfo']).SetLabel( \ + self.infoCollapseLabelExp) # redo layout self.Layout() @@ -852,9 +863,8 @@ def OnCloseWindow(self, event): """Cancel button pressed""" - for item in self.layerPage.itervalues(): - item['list'].OnCloseWindow(event) self.Close() + event.Skip() def OnBuilder(self,event): """SQL Builder button pressed""" @@ -867,30 +877,79 @@ def OnSQLBuilder(self, event): pass - def __layout(self): - """Do layout""" - #self.panel = wx.Panel(self,-1, style=wx.SUNKEN_BORDER) + def OnDataItemActivated(self, event): + """Item activated, log purpose""" + list = self.FindWindowById(self.layerPage[self.layer]['data']) + list.currentItem = event.m_itemIndex - #self.label_query.SetMinSize((500,50)) -# self.sqlWhere.SetMinSize((250,-1)) + if self.map and self.mapdisplay: + # list.lastTurnSelectedCats[:] != list.selectedCats[:]: - # frame body - mainSizer = wx.BoxSizer(wx.VERTICAL) + # add map layer with higlighted vector features + self.AddQueryMapLayer(self.map) + self.mapdisplay.MapWindow.UpdateMap(render=True) + + #list.lastTurnSelectedCats = list.selectedCats[:] - # buttons - btnSizer = wx.StdDialogButtonSizer() - btnSizer.AddButton(self.btnQuit) - btnSizer.AddButton(self.btnApply) - btnSizer.Realize() + event.Skip() - mainSizer.Add(item=self.notebook, proportion=1, flag=wx.EXPAND) - mainSizer.Add(item=btnSizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) + def AddQueryMapLayer(self, map): + """Redraw a map - self.SetSizer(mainSizer) - mainSizer.Fit(self) + Return True if map has been redrawn, False if no map is given + """ + if self.qlayer: + map.DeleteLayer(self.qlayer) + + list = self.FindWindowById(self.layerPage[self.layer]['data']) + cats = list.selectedCats[:] + + # for i in range(len(cats)): + # next = 0 + # j = 0 + # while True: + # try: + # if cats[i+j]+1 == cats[i+j+1]: + # next += 1 + # else: + # break + # except IndexError: + # next = 0 + # if j+i >= len(cats)-2: + # break + # else: + # j += 1 + # if next > 1: + # catstr += "%d-%d," % (cats[i], cats[i+next]) + # i += next + # else: + # catstr += "%d," % (cats[i]) + + # print "#", catstr + + # if catstr[-1] == ",": + # catstr = string.join(catstr[:-1],"") - self.Layout() + digitClass = self.mapdisplay.digit + color = digitClass.settings['symbolHighlight'][1] + colorStr = str(color[0]) + ":" + \ + str(color[1]) + ":" + \ + str(color[2]) + ":" + cmd = ["d.vect", + "map=%s" % self.vectmap, + "color=%s" % colorStr, + "fcolor=%s" % colorStr, + # "cats=%s" % (",".join(["%d" % c for c in cats])), + "cats=%s" % str(int(list.GetItemText(list.currentItem))), # FIXME + "width=%d" % digitClass.settings['lineWidth'][0]] # FIXME (units) + if self.icon: + gcmd.append("icon=%s" % (self.icon)) + if self.pointsize: + gcmd.append("size=%s" % (self.pointsize)) + self.qlayer = map.AddLayer(type='vector', name=globalvar.QUERYLAYER, command=cmd, + l_active=True, l_hidden=True, l_opacity=1.0) + class TableListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.TextEditMixin): Modified: trunk/grassaddons/gui/gui_modules/digit.py =================================================================== --- trunk/grassaddons/gui/gui_modules/digit.py 2007-11-13 20:51:32 UTC (rev 1179) +++ trunk/grassaddons/gui/gui_modules/digit.py 2007-11-14 22:03:29 UTC (rev 1180) @@ -1426,15 +1426,15 @@ # buttons btnApply = wx.Button(self, wx.ID_APPLY) btnCancel = wx.Button(self, wx.ID_CANCEL) - btnReload = wx.Button(self, wx.ID_UNDO, _("&Reload")) + #btnReload = wx.Button(self, wx.ID_UNDO, _("&Reload")) btnOk = wx.Button(self, wx.ID_OK) btnOk.SetDefault() # sizers btnSizer = wx.StdDialogButtonSizer() btnSizer.AddButton(btnCancel) - btnSizer.AddButton(btnReload) - btnSizer.SetNegativeButton(btnReload) + #btnSizer.AddButton(btnReload) + #btnSizer.SetNegativeButton(btnReload) btnSizer.AddButton(btnApply) btnSizer.AddButton(btnOk) btnSizer.Realize() @@ -1457,7 +1457,7 @@ # bindings # buttons - btnReload.Bind(wx.EVT_BUTTON, self.OnReload) + #btnReload.Bind(wx.EVT_BUTTON, self.OnReload) btnApply.Bind(wx.EVT_BUTTON, self.OnApply) btnOk.Bind(wx.EVT_BUTTON, self.OnOK) btnAddCat.Bind(wx.EVT_BUTTON, self.OnAddCat) @@ -1532,13 +1532,20 @@ if not hasattr(self, "popupID1"): self.popupID1 = wx.NewId() self.popupID2 = wx.NewId() - self.Bind(wx.EVT_MENU, self.OnItemDelete, id=self.popupID1) + self.popupID3 = wx.NewId() + self.Bind(wx.EVT_MENU, self.OnItemDelete, id=self.popupID1) self.Bind(wx.EVT_MENU, self.OnItemDeleteAll, id=self.popupID2) + self.Bind(wx.EVT_MENU, self.OnReload, id=self.popupID3) # generate popup-menu menu = wx.Menu() menu.Append(self.popupID1, _("Delete selected")) + if self.list.GetFirstSelected() == -1: + menu.Enable(self.popupID1, False) + menu.Append(self.popupID2, _("Delete all")) + menu.AppendSeparator() + menu.Append(self.popupID3, _("Reload")) self.PopupMenu(menu) menu.Destroy() Added: trunk/grassaddons/gui/gui_modules/globalvar.py =================================================================== --- trunk/grassaddons/gui/gui_modules/globalvar.py (rev 0) +++ trunk/grassaddons/gui/gui_modules/globalvar.py 2007-11-14 22:03:29 UTC (rev 1180) @@ -0,0 +1,23 @@ +""" +MODULE: global.py + +PURPOSE: Global variables + + This module provide the space for global variables + used in the code. + +AUTHOR(S): GRASS Development Team + Martin Landa + +COPYRIGHT: (C) 2007 by the GRASS Development Team + + This program is free software under the GNU General Public + License (>=v2). Read the file COPYING that comes with GRASS + for details. +""" + +""" +Query layer (generated for example by selecting item in the Attribute Table Manager) +Deleted automatically on re-render action +""" +QUERYLAYER = 'qlayer' Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-11-13 20:51:32 UTC (rev 1179) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-11-14 22:03:29 UTC (rev 1180) @@ -62,6 +62,7 @@ import defaultfont import histogram import profile +import globalvar from digit import Digit as Digit from digit import DigitCategoryDialog as DigitCategoryDialog from digit import DigitZBulkDialog as DigitZBulkDialog @@ -72,7 +73,10 @@ imagepath = images.__path__[0] sys.path.append(imagepath) -# for cmdlinef +### +### global variables +### +# for standalone app cmdfilename = None class Command(Thread): @@ -2247,6 +2251,9 @@ Rerender button clicked """ Debug.msg(3, "BufferedWindow.ReRender():") + qlayer = self.Map.GetListOfLayers(l_name=globalvar.QUERYLAYER) + for layer in qlayer: + self.Map.DeleteLayer(layer) self.MapWindow.UpdateMap(render=True) def OnPointer(self, event): Modified: trunk/grassaddons/gui/gui_modules/render.py =================================================================== --- trunk/grassaddons/gui/gui_modules/render.py 2007-11-13 20:51:32 UTC (rev 1179) +++ trunk/grassaddons/gui/gui_modules/render.py 2007-11-14 22:03:29 UTC (rev 1180) @@ -529,14 +529,17 @@ else: return None - def GetListOfLayers(self, l_type=None, l_mapset=None, l_active=None, l_hidden=None): + def GetListOfLayers(self, l_type=None, l_mapset=None, l_name=None, + l_active=None, l_hidden=None): """ Returns list of layers (including overlays [l_type='overlay'] of selected type or list of all layers. It is also possible to get list of active or hidden layers. Parameters: - l_type - layer type, e.g. raster/vector/wms/overlay ... + l_type - layer type, e.g. raster/vector/wms/overlay ... + l_mapset - all layer from given mapset + l_name - all layer with given name l_active - only layers with 'active' attribute set to True or False l_hidden - only layers with 'hidden' attribute set to True or False @@ -556,6 +559,10 @@ if l_mapset != None and layer.GetMapset() != l_mapset: continue + # name + if l_name != None and layer.name != l_name: + continue + # hidden and active layers if l_active != None and \ l_hidden != None: From bergenheim at grass.itc.it Tue Nov 6 07:42:23 2007 From: bergenheim at grass.itc.it (bergenheim@grass.itc.it) Date: Mon Nov 26 16:59:29 2007 Subject: [grass-addons] r1177 - trunk/grassaddons/v.path.obstacles Message-ID: <200711060642.lA66gN4I011575@grass.itc.it> Author: bergenheim Date: 2007-11-06 07:42:20 +0100 (Tue, 06 Nov 2007) New Revision: 1177 Modified: trunk/grassaddons/v.path.obstacles/MOVED_TO_MAIN_GRASS.txt Log: Fixed new name Modified: trunk/grassaddons/v.path.obstacles/MOVED_TO_MAIN_GRASS.txt =================================================================== --- trunk/grassaddons/v.path.obstacles/MOVED_TO_MAIN_GRASS.txt 2007-11-04 13:00:42 UTC (rev 1176) +++ trunk/grassaddons/v.path.obstacles/MOVED_TO_MAIN_GRASS.txt 2007-11-06 06:42:20 UTC (rev 1177) @@ -1,3 +1,3 @@ This module is no longer maintained here but was moved to the main repository of GRASS as -v.net.obstacle. +v.net.visibility.