From 1574fb62236a0713b032b15b95b4b403b708cb28 Mon Sep 17 00:00:00 2001 From: Tomas Zigo Date: Sat, 15 Aug 2020 07:58:03 +0200 Subject: [PATCH] wxGUI/datacalog: distinguish vector map layer type by icon * 3D vector map layer ('vector_3d.png' icon) * Vector map layer is stored in the db, but db connection is refused ('vector_db_disconnect.png' icon) * Link external vector map layer, but source path changed/deleted ('vector_link_without_src.png' icon) --- gui/icons/grass/vector_3d.png | Bin 0 -> 2402 bytes gui/icons/grass/vector_db_disconnect.png | Bin 0 -> 2339 bytes gui/icons/grass/vector_link_without_src.png | Bin 0 -> 2312 bytes gui/wxpython/datacatalog/tree.py | 88 +++++++++++++++++--- 4 files changed, 75 insertions(+), 13 deletions(-) create mode 100644 gui/icons/grass/vector_3d.png create mode 100644 gui/icons/grass/vector_db_disconnect.png create mode 100644 gui/icons/grass/vector_link_without_src.png diff --git a/gui/icons/grass/vector_3d.png b/gui/icons/grass/vector_3d.png new file mode 100644 index 0000000000000000000000000000000000000000..57d62c07540459e27dac6bc636d7c522ea9cd976 GIT binary patch literal 2402 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 U0HycLdH?_b07*qoM6N<$g0iQR=Kufz literal 0 HcmV?d00001 diff --git a/gui/icons/grass/vector_db_disconnect.png b/gui/icons/grass/vector_db_disconnect.png new file mode 100644 index 0000000000000000000000000000000000000000..62c53697a23b566b2c70c437769acf5cb9eb6eb7 GIT binary patch literal 2339 zcmV+;3EcLHP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+SOKBk}D|;{O1&N1SBDrl68$PrrQP(jSh{_;P^sYw{PxcMHo65kC(2VZ+mQ&ND`fWAwed>^vCt zC!(ym*qL)+SU|a~X&xouQMAJ<2_@QWD$WfzAgZio~RX}vyIiO~) zEUPa{;KWs?PHq+&93)ADf-IH0fpkvzhK1I;X{}c&V&z6KWr8!pl$XVPH~5=k#;B7b zvhl_haPbULz?jO-H>@BCjiZ|`g0FJqw|DV_P=$iJXpY!mwq?60N*}Q$OJ{+dqTWY{ zOlZdeD8kwbFeFgGdJ-j1HZTVw@E9Rb26D#PC{Tb@xd9|Q5zi)YsqMf?O85kpx;ovL~b8jU8+UcB?_y$^mSxf~?8puvX_Vn`uJi7smN zF~k^C%!!jA2Ws*uq?l65nN7w*8NM>?GkOXaDXwVoC6riF$ra&KUDfJqsIjJ+8#if4 z6V12KVoNP|G98(syRO~$&|^n2i&G>Wkz*F(7<+w}kdJ*f zC!J#B_0JTHzc?J-$%S%rsM(wbs69?Y?byN z>`!&5(=9GY#reS!#|1wAuFc!J_Yi5O?**lvjUX4?xav5}Oa93a4vET9I1b#L%N0xq zPWGj6_)Zt|C=h481iJOc!6hF}hO?uLeh^>CM-p#V8{<)W*|19;T=~h??dcu2z13^W zLv@EnH4dMz-_tmmD=sAG4vmBqxk*Ec^LokOIRdMD9X92V*Hau-;xksi904pwZOp6R z+ap=Ch$tN!LaNV1Kk^xqS*AjF@^A=g@cB1{L+|`@^Ua67m}x>IhSvv;Q~Ox=#EwfJ zBwrkxO={NdSE*LsCLUKyTD`b41XJBX+(Yh=VULAc(?DFT$o>+E9wfun(5XJp{4~*A zGf%1*xRLPLD*kZ)c>DnUP!g!x105G-&&8aWt-XH;?&=ZTyV0uqEci|MTz8NT+>2(| z{`Slw8%|4U)X@)Y>jkkh6Ppv-atOPD+i@QSmQr70NhjP!N-_d&eKy~R?-w&(#J~CE z;qh>mbOP_>m>g%kANefZCqHvLp5LqcV_2Bq&#WgNJR;y^>=enQjgFB6PGZen@GbHN zzYi>#x6{RI1%2LWWT+j{^Y%Dzr(z$1z`Yd&=37mF0n)sK{vAk0{v$|+{{+(8jt0IR z6LQVJ?tvZlEX>4Tx0C=2zkv&MmKpe$iQ>8^(I@m$P zAwv}h3!);9T7@E12(?114kp)6Xws0RxHt-~1qVMCs}3&Cx;nTDg5U>;lcSTOi`Fbc@b)aN8A1<&zy4)O&;^MfxvseU#<}FMz%!#p zCOuCaB^FCvtaLFe8!GV>aV)QDlrLmm&U4=4tXAu+eNXDJc?(N?*?f!lMC{=QaLdA`O00006 zVoOIv0O|nh0P25@IuQT>010qNS#tmY2|54(2|5ArWRgk%000McNliruv z!P4^5+i&UgeZ$Ion|!|W*~MRd_Aj3ncG~OQQ~BlmI^bP3z^?guQ#Z7B*$kr@%SziF z&Ssk!8$D~>TTxZo2BNK<2f~x8O110=Mh4o0k&A$owC?V(sj7uXe4dKWs>sKVL(!hf z)3*g;PE;e9<^_ciBKr`Tn0k0~f0+w*r*T#+J<}FA;aUywI=&AoGCp(X(of(Ba1FQz zoGb%8z8g=Y+%}xnsgkxQ5b`J*$Tch`ic&q023i1T0U$Dl$ZcL}H}~NCK% zaB^>EX>4U6ba`-PAZ2)IW&i+q+SOKBlI182{O1&N1SGMD#`&lrg0v#NF3-oI%$XUL_6QQ~yxYkgN2%{hNE#oZ7T#q&h6~Dh zQd^eO*>;X^^Vr}bSZW><33C?`yWYBOWIq{?;!WaUMi2?%*w-i<)}NYE3> zSIvB6|5p1zKIhXeAGi#MBUC=^Apbe}i{gig<%Wo#I}lOvWjW^=qv;rZuP(a)M#G6H zYc6)?7#J2%E^An@(`7)cD9U*!+-kF}ki6My3+_sZ7^)0Ijv8ee)K^)l0;1#25hZhF zS#2tj6IYo!xp~vzC`lR=WU1T@q;tYIEVSlLYraZ~nH#~B3C;*Z-rnY`&fmGs7G%FUEZP_l0r+aM4(pg~VQSL27 zCbr`M6k%=;FeFgG1`ZLkp~Rvkm0S@%)m2|Zja6%^xp9+* zG|@tfORHLIBFQukkys3s( z6XWHAW;*dxGbqN6pm>}LAfS0_W|f@dsod1eCdQ`l43K_mV;W7xAffBTe$Y+3yK+C$ z&3OHhZv35cW=i*OC}$wut8SmD*5)}^mtuPtPEM_0_rWH!8a&qG^{3_k)RA<8UIJTU8dwB0(BYSFl?3f z8tivvtkW$HNRR!4DUJ*L{9TK;b+18brtbx%o`oP6+_>u4%uD{s5H^XIqp%K~oXZtV z2X^+QaQsRa^DGc&e+hJJ)xjknO@_0hjD8Sb$VZZ3RvrB+y=>T}4zB!S>-O-D)86`P z$;0~{8r3-bzJ5*PWUjcFoI5lUQsgELDK7X+{>}=l?tR#lLtalhs^}}$up9v_dadTw z9_*2o@ z*T|D922LdWwn{kMKW{%kKa@nO_CUu$*>f=`W^3Hv2uPp5BIqc^4P&1FD{Q2#A1_v6GTXdvZn&IEgiP z!N15Se16H6`Ej~%}>z(r2LON!k=O? z{{X9^7p#9&k#+z80fcEoLr_UWLm+T+Z)Rz1WdHzpoPCi!NW(xJ#a~mUMOr%8LBt_L z6$cBVB92;xB2);qLaPoY*H38DkfgXc3a$kQKNhPFF3!3-xC(;c2Z)oSlcI~1_`jsk zBF2N`e!RQ)xO)c(%_>vPo^e3cEF+yvh}qn#7~P z%lq7)Bb+ao4DgA>vrIQE;tk^IO-tvzPaI`sIZu2}JZ8`Zi66PHxctVs#TiG{=!f}TUq8h%^@VQh$To6p`eZm zs<05JRU^ejn)VYO{z1ntkxL<01&kaEs6mD7_`(0+ceiG7a>7jtC4k-++x{2^0=qz~ zVcXxww%s}b{LjFZ*74Vxz|1GxO5FelhrmdQve!M{9qjJy-!tw0egG&{a*0C4je-CG00v@9 zM??VX0O|nhe~mg300009a7bBm000R(000R(0q|s!N&o-=2XskIMF->v4htp_Lz1&+ z0005oNkl++xb`A}@O2z&U@;`8|j8 z{~u9Rwo`^}mTUe)x^v>`^TyVb;b;E>kd~hQH@0PkQY))_rblk4%WjIr%&G78qqW@H z^4DbYp>gtoU?_Ago%z}7{_^?#QMcDWna|~S18>U#jx8N^8?i=hIn+0pn* z6-n7UDi=jvu`Mz*0N@7h0sX+v!n`98+?DcqEBv|4r|hP#7fMzKDf(J2dEwWqH8bNw iueJby>VW+B-}ndpSG!c!JQ{@n0000nF literal 0 HcmV?d00001 diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index 7c8aedfbca6..c8e052a99be 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -22,6 +22,7 @@ import re import copy from multiprocessing import Process, Queue, cpu_count +import subprocess import wx @@ -157,7 +158,43 @@ def getLocationTree(gisdbase, location, queue, mapsets=None): for each in listOfMaps: ltype, wholename = each.split('/') name, mapset = wholename.split('@') - maps_dict[mapset].append({'name': name, 'type': ltype}) + if ltype == 'vector': + p = gscript.pipe_command( + 'v.info', flags='t', map=wholename, layer=1, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) + stdout, stderr = p.communicate() + stdout = gscript.decode(stdout) + stderr = gscript.decode(stderr) + + if not stderr: + map_info = dict( + [ + (kv.split('=')) for kv in stdout.split('\n') + if kv + ] + ) + if map_info and int(map_info['map3d']): + maps_dict[mapset].append( + {'name': name, 'type': 'vector_3d'}, + ) + elif map_info: + maps_dict[mapset].append( + {'name': name, 'type': 'vector'}, + ) + # Vector map layer is stored in the db + elif 'Connection refused' in stderr: + maps_dict[mapset].append( + {'name': name, 'type': 'vector_db_disconnect'}, + ) + # Link external vector map layer + elif 'Unable to open OGR data source' in stderr: + maps_dict[mapset].append( + {'name': name, 'type': 'vector_link_without_src'}, + ) + else: + maps_dict[mapset].append({'name': name, 'type': ltype}) + else: + maps_dict[mapset].append({'name': name, 'type': ltype}) queue.put((maps_dict, None)) gscript.try_remove(tmp_gisrc_file) @@ -259,6 +296,10 @@ def __init__( self._giface = giface self._restricted = True + self.vector = [ + 'vector', 'vector_3d', 'vector_db_disconnect', + 'vector_link_without_src', + ] self.showNotification = Signal('Tree.showNotification') self.changeMapset = Signal('Tree.changeMapset') @@ -267,7 +308,7 @@ def __init__( self.contextMenu.connect(self.OnRightClick) self.itemActivated.connect(self.OnDoubleClick) self._iconTypes = ['grassdb', 'location', 'mapset', 'raster', - 'vector', 'raster_3d'] + 'raster_3d', *self.vector] self._initImages() self._resetSelectVariables() @@ -556,7 +597,12 @@ def _initImages(self): 'mapset': MetaIcon(img='mapset').GetBitmap(bmpsize), 'raster': MetaIcon(img='raster').GetBitmap(bmpsize), 'vector': MetaIcon(img='vector').GetBitmap(bmpsize), - 'raster_3d': MetaIcon(img='raster3d').GetBitmap(bmpsize) + 'raster_3d': MetaIcon(img='raster3d').GetBitmap(bmpsize), + 'vector_3d': MetaIcon(img='vector3d').GetBitmap(bmpsize), + 'vector_db_disconnect': MetaIcon( + img='vector_db_disconnect').GetBitmap(bmpsize), + 'vector_link_without_src': MetaIcon( + img='vector_link_without_src').GetBitmap(bmpsize), } il = wx.ImageList(bmpsize[0], bmpsize[1], mask=False) for each in self._iconTypes: @@ -573,7 +619,7 @@ def DefineItems(self, selected): mixed = [] for item in selected: type = item.data['type'] - if type in ('raster', 'raster_3d', 'vector'): + if type in ('raster', 'raster_3d', *self.vector): self.selected_layer.append(item) self.selected_mapset.append(item.parent) self.selected_location.append(item.parent.parent) @@ -876,7 +922,7 @@ def Rename(self, old, new): self.selected_mapset[0].data['name']) label = _("Renaming map <{name}>...").format(name=string) self.showNotification.emit(message=label) - if self.selected_layer[0].data['type'] == 'vector': + if self.selected_layer[0].data['type'] in self.vector: renamed, cmd = self._runCommand('g.rename', vector=string, env=env) elif self.selected_layer[0].data['type'] == 'raster': renamed, cmd = self._runCommand('g.rename', raster=string, env=env) @@ -939,9 +985,9 @@ def OnPasteMap(self, event): else: label = _("Moving <{name}>...").format(name=string) self.showNotification.emit(message=label) - if self.copy_layer[i].data['type'] == 'vector': + if self.copy_layer[i].data['type'] in self.vector: pasted, cmd = self._runCommand('g.copy', vector=string, env=env) - node = 'vector' + node = self.copy_layer[i].data['type'] elif self.copy_layer[i].data['type'] == 'raster': pasted, cmd = self._runCommand('g.copy', raster=string, env=env) node = 'raster' @@ -1006,8 +1052,10 @@ def _onDoneReprojection(self, iEnv, iGisrc, oGisrc, cLayer, cMapset, cMode, name self.ExpandNode(self.selected_mapset[0], recursive=True) def _removeMapAfterCopy(self, cLayer, cMapset, env): - removed, cmd = self._runCommand('g.remove', type=cLayer.data['type'], - name=cLayer.data['name'], flags='f', env=env) + removed, cmd = self._runCommand( + 'g.remove', type=self._getMapLayerType(cLayer.data['type']), + name=cLayer.data['name'], flags='f', env=env, + ) if removed == 0: self._model.RemoveNode(cLayer) self.RefreshNode(cMapset, recursive=True) @@ -1083,8 +1131,12 @@ def OnDeleteMap(self, event): self.selected_location[i].data['name'], self.selected_mapset[i].data['name']) removed, cmd = self._runCommand( - 'g.remove', flags='f', type=self.selected_layer[i].data['type'], - name=self.selected_layer[i].data['name'], env=env) + 'g.remove', flags='f', + type=self._getMapLayerType( + self.selected_layer[i].data['type'], + ), + name=self.selected_layer[i].data['name'], env=env, + ) if removed == 0: self._model.RemoveNode(self.selected_layer[i]) self.RefreshNode(self.selected_mapset[i], recursive=True) @@ -1200,7 +1252,11 @@ def DisplayLayer(self): names = {'raster': [], 'vector': [], 'raster_3d': []} for i in range(len(self.selected_layer)): name = self.selected_layer[i].data['name'] + '@' + self.selected_mapset[i].data['name'] - names[self.selected_layer[i].data['type']].append(name) + names[ + self._getMapLayerType( + self.selected_layer[i].data['type'], + ) + ].append(name) all_names.append(name) #if self.selected_location[0].data['name'] == gisenv()['LOCATION_NAME'] and self.selected_mapset[0]: for ltype in names: @@ -1292,7 +1348,7 @@ def done(event): for i in range(len(self.selected_layer)): if self.selected_layer[i].data['type'] == 'raster': cmd = ['r.info'] - elif self.selected_layer[i].data['type'] == 'vector': + elif self.selected_layer[i].data['type'] in self.vector: cmd = ['v.info'] elif self.selected_layer[i].data['type'] == 'raster_3d': cmd = ['r3.info'] @@ -1573,3 +1629,9 @@ def _popupMenuEmpty(self): item.Enable(False) self.PopupMenu(menu) menu.Destroy() + + def _getMapLayerType(self, ltype): + """Get map layer type""" + if ltype in self.vector: + return 'vector' + return ltype