Skip to content

Commit 3f1e04f

Browse files
committed
v0.2.6.7
1 parent 29de311 commit 3f1e04f

File tree

13 files changed

+29867
-555
lines changed

13 files changed

+29867
-555
lines changed

README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@ python3 gedcom-to-map.py /users/darren/documents/myhertitagetree.ged myTree -mai
6060
```
6161

6262
## GUI
63-
![img](docs/img/python_2025-03-29.png)
63+
![img](docs/img/GUI-python_2025-09-03.png)
6464

65-
To use the GUI version, `File- > Open` and select your .ged file.
65+
To use the GUI version, click on `Input File` and select your .ged file.
6666
Set your options in the GUI interface
67-
- Type in the Output file name (It saves to the same directory as the Load file).
67+
- Type in the Output file name (Default is same name, different extension in same directory as the Input file).
6868
- Result type drives the options mixture
6969

7070
Once you have selected your options,
@@ -105,14 +105,22 @@ off all the layout measurements. (Need to add math to get actual font size)
105105
| geopy | https://github.com/geopy/geopy |https://geopy.readthedocs.io/en/latest/#geocoders |
106106
| folium | https://github.com/python-visualization/folium | https://python-visualization.github.io/folium/latest/|
107107
| xyzservices | https://github.com/geopandas/xyzservices | https://xyzservices.readthedocs.io/en/stable/index.html |
108+
| nnjeim/world | https://github.com/nnjeim/world | https://github.com/nnjeim/world?tab=readme-ov-file#available-actions
108109

109110

110111
# Results
111112
## KML Example revised
112113
### Google Earth Online
114+
(Uncheck FlyTo Balloon)
113115
![img](docs/img/Google_earth_2025-03.png)
114116
* KML Output : [samples/input.kml](samples/input.kml) using 'native' only
117+
### Google Earth Pro
118+
(Check FlyTo Balloon)
119+
![img](docs/img/googleearth_2025-09-01.jpg)
120+
* KML Output : [samples/royal92.kml](samples/royal92.kml) all people, birth, death
121+
115122
### ArcGIS Earth
123+
(Uncheck FlyTo Balloon)
116124
![img](docs/img/ArcGISEarth_2025-03-input.jpg)
117125

118126
Go to https://www.google.ca/maps/about/mymaps

docs/img/GUI-python_2025-09-03.png

105 KB
Loading
564 KB
Loading

gedcom-to-map/gedcom/gpslookup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626

2727

2828
# TODO This needs to be moved into it's out JSON driven configuration
29-
fixuplist = {r'\bof\s': '',
30-
r'\spart of\s' : ' ',
29+
fixuplist = {r'\spart of\s' : ' ',
30+
r'\bof\s': '',
3131
r'po box [0-9]+\s' : ' ',
3232
r'\([\w\s\.]+\)' : '',
3333
'(town)' : '',

gedcom-to-map/gedcomDialogs.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ def __init__(self, parent, title, gOptions):
105105
self.TEXTcsvcmdline = wx.TextCtrl(cfgpanel, wx.ID_FILE1, "", size=(250,20))
106106
if gOptions.CSVcmdline:
107107
self.TEXTcsvcmdline.SetValue(gOptions.CSVcmdline)
108+
TEXTtracecmdlinelbl = wx.StaticText(cfgpanel, -1, " Trace Table Editor Command line: ")
109+
self.TEXTtracecmdline = wx.TextCtrl(cfgpanel, wx.ID_FILE1, "", size=(250,20))
110+
if gOptions.Tracecmdline:
111+
self.TEXTtracecmdline.SetValue(gOptions.Tracecmdline)
108112
GRIDctl = gridlib.Grid(cfgpanel)
109113
if includeNOTSET:
110114
gridlen = len(logging.root.manager.loggerDict)
@@ -160,14 +164,13 @@ def makeCells():
160164

161165
sizer = wx.BoxSizer(wx.VERTICAL)
162166
l1 = wx.BoxSizer(wx.HORIZONTAL)
163-
l1.AddMany([TEXTkmlcmdlinelbl, (6,20), self.TEXTkmlcmdline])
167+
l1.AddMany([TEXTkmlcmdlinelbl, (3,20), self.TEXTkmlcmdline])
164168
l2 = wx.BoxSizer(wx.HORIZONTAL)
165-
l2.AddMany([TEXTcsvcmdlinelbl, (6,20), self.TEXTcsvcmdline])
166-
sizer.AddSpacer(5)
167-
sizer.Add(l1)
168-
sizer.AddSpacer(10)
169-
sizer.Add(l2)
170-
sizer.AddSpacer(10)
169+
l2.AddMany([TEXTcsvcmdlinelbl, (3,20), self.TEXTcsvcmdline])
170+
l3 = wx.BoxSizer(wx.HORIZONTAL)
171+
l3.AddMany([TEXTtracecmdlinelbl, (3,20), self.TEXTtracecmdline])
172+
sizer.AddMany([(5,20), l1, (5,20), l2, (5,20), l3, (10,20)])
173+
171174

172175
sizer.Add( wx.StaticText(cfgpanel, -1, "Use $n for the name of the file within a command line - such as notepad $n"))
173176
sizer.Add( wx.StaticText(cfgpanel, -1, "Use $n without any command to open default application for that file type"))
@@ -195,6 +198,7 @@ def onSave(self, event):
195198
updatelog.setLevel(getattr(logging, logLevel))
196199
self.gOptions.KMLcmdline = self.TEXTkmlcmdline.GetValue()
197200
self.gOptions.CSVcmdline = self.TEXTcsvcmdline.GetValue()
201+
self.gOptions.Tracecmdline = self.TEXTtracecmdline.GetValue()
198202
self.gOptions.savesettings()
199203
self.Close()
200204
self.DestroyLater()
@@ -633,7 +637,7 @@ def Run(self):
633637
else:
634638
self.SayInfoMessage(f"Cancelled loading people")
635639
if self.gOptions.Main:
636-
self.SayInfoMessage(f" with '{self.gOptions.Main}' as starting person", False)
640+
self.SayInfoMessage(f" with '{self.gOptions.Main}' as starting person from {Path(self.gOptions.GEDCOMinput).name}", False)
637641
else:
638642
self.SayErrorMessage(f"Error: file could not read as a GEDCOM file", True)
639643

gedcom-to-map/gedcomVisualGUI.py

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class VisualGedcomIds():
5454
def __init__(self):
5555

5656
self.ids = [
57-
'ID_CBMarksOn', 'ID_CBHeatMap', 'ID_CBBornMark', 'ID_CBDieMark', 'ID_LISTMapStyle',
57+
'ID_CBMarksOn', 'ID_CBHeatMap', 'ID_CBFlyTo', 'ID_CBBornMark', 'ID_CBDieMark', 'ID_LISTMapStyle',
5858
'ID_CBMarkStarOn', 'ID_RBGroupBy', 'ID_CBUseAntPath', 'ID_CBMapTimeLine',
5959
'ID_CBHomeMarker', 'ID_LISTHeatMapTimeStep', 'ID_TEXTGEDCOMinput', 'ID_TEXTResult',
6060
'ID_RBResultHTML', 'ID_TEXTMain', 'ID_TEXTName', 'ID_INTMaxMissing', 'ID_INTMaxLineWeight',
@@ -75,6 +75,7 @@ def __init__(self):
7575
self.IDs['ID_CBUseAntPath']: ('UseAntPath', 'Redraw'),
7676
self.IDs['ID_CBMapTimeLine']: ('MapTimeLine', 'Redraw'),
7777
self.IDs['ID_CBHomeMarker']: ('HomeMarker', 'Redraw'),
78+
self.IDs['ID_CBFlyTo']: ('UseBalloonFlyto', 'Redraw'),
7879
self.IDs['ID_LISTHeatMapTimeStep']: ('MapTimeLine', 'Redraw'),
7980
self.IDs['ID_TEXTGEDCOMinput']: ('GEDCOMinput', 'Reload'),
8081
self.IDs['ID_TEXTResult']: ('Result', 'Redraw'),
@@ -86,7 +87,6 @@ def __init__(self):
8687
self.IDs['ID_CBUseGPS']: ('UseGPS', 'Reload'),
8788
self.IDs['ID_CBCacheOnly']: ('CacheOnly', 'Reload'),
8889
self.IDs['ID_CBAllEntities']: ('AllEntities', 'Redraw'),
89-
# self.IDs['ID_LISTPlaceType']: ('PlaceType', 'Redraw'),
9090
self.IDs['ID_CBMapControl']: ('showLayerControl', 'Redraw'),
9191
self.IDs['ID_CBMapMini']: ('mapMini', 'Redraw'),
9292
self.IDs['ID_BTNLoad']: 'Load',
@@ -118,7 +118,7 @@ def __init__(self):
118118
self.COLORs['GRID_BACK']: ['WHITE'], # Alternate DARK SLATE GREY
119119
self.COLORs['TITLE_TEXT']: ['WHITE'],
120120
self.COLORs['TITLE_BACK']: ['KHAKI'],
121-
self.COLORs['BUSY_BACK']: ['KHAKI']
121+
self.COLORs['BUSY_BACK']: ['YELLOW']
122122

123123
}
124124
for colorToValue in self.colors:
@@ -835,11 +835,11 @@ def LayoutOptions(self, panel):
835835
box.Add(wx.StaticLine(panel), 0, wx.EXPAND)
836836

837837

838-
self.id.txtinfile = wx.StaticText(panel, -1, "Input file: ")
838+
self.id.txtinfile = wx.Button(panel, -1, "Input file: ")
839839
self.id.txtinfile.SetBackgroundColour(self.id.GetColor('BTN_DIRECTORY'))
840840
self.id.TEXTGEDCOMinput = wx.TextCtrl(panel, self.id.IDs['ID_TEXTGEDCOMinput'], "", size=(250,20))
841841
self.id.TEXTGEDCOMinput.Enable(False)
842-
self.id.txtoutfile = wx.StaticText(panel, -1, "Output file: ")
842+
self.id.txtoutfile = wx.Button(panel, -1, "Output file: ")
843843
self.id.txtoutfile.SetBackgroundColour(self.id.GetColor('BTN_DIRECTORY'))
844844
self.id.TEXTResult = wx.TextCtrl(panel, self.id.IDs['ID_TEXTResult'], "", size=(250,20))
845845
self.id.txtinfile.Bind(wx.EVT_LEFT_DOWN, self.frame.OnFileOpenDialog)
@@ -938,22 +938,23 @@ def LayoutOptions(self, panel):
938938
if False:
939939
txtMissing = wx.StaticText(kboxIn, -1, "Max generation missing: ")
940940
self.id.INTMaxMissing = wx.TextCtrl(kboxIn, self.id.IDs['ID_INTMaxMissing'], "", size=(20,20))
941-
txtLine = wx.StaticText(kboxIn, -1, "Line maximum weight: ")
942-
self.id.INTMaxLineWeight = wx.TextCtrl(kboxIn, self.id.IDs['ID_INTMaxLineWeight'], "", size=(20,20))
943941
l1 = wx.BoxSizer(wx.HORIZONTAL)
944942
l1.AddMany([txtMissing, (0,20), self.id.INTMaxMissing])
945-
l2 = wx.BoxSizer(wx.HORIZONTAL)
946-
l2.AddMany([txtLine, (0,20), self.id.INTMaxLineWeight])
943+
947944
kboxIn.AddMany([l1, (4,4,), l2])
948945
# self.id.ID_INTMaxMissing 'MaxMissing'
949-
# self.id.ID_INTMaxLineWeight 'MaxLineWeight'
950946

947+
kboxs = [wx.BoxSizer(wx.HORIZONTAL), (4,4), wx.BoxSizer(wx.HORIZONTAL)]
948+
self.id.CBFlyTo = wx.CheckBox(kbox, self.id.IDs['ID_CBFlyTo'], "FlyTo Balloon", style = wx.NO_BORDER)
949+
self.id.ID_INTMaxLineWeight = wx.SpinCtrl(kbox, self.id.IDs['ID_INTMaxLineWeight'], "", min=1, max=100, initial=20)
950+
kboxs[0].AddMany([wx.StaticText(kbox, -1, " "), self.id.CBFlyTo])
951+
kboxs[2].AddMany([self.id.ID_INTMaxLineWeight, wx.StaticText(kbox, -1, " Max Line Weight")])
952+
kboxIn.AddMany(kboxs)
951953

952954
ksizer.Add( kboxIn, wx.LEFT, kOtherBorder+10)
953955
kbox.SetSizer(ksizer)
954956
self.kbox = kbox
955957

956-
957958
#
958959
# Grid View Options
959960
#
@@ -1017,13 +1018,14 @@ def LayoutOptions(self, panel):
10171018
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, id = self.id.IDs['ID_CBHomeMarker'])
10181019
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, id = self.id.IDs['ID_CBMarkStarOn'])
10191020
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, id = self.id.IDs['ID_CBHeatMap'])
1021+
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, id = self.id.IDs['ID_CBFlyTo'])
10201022
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, id = self.id.IDs['ID_CBMapTimeLine'])
10211023
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, id = self.id.IDs['ID_CBUseAntPath'])
10221024
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, id = self.id.IDs['ID_CBUseGPS'])
10231025
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, id = self.id.IDs['ID_CBCacheOnly'])
10241026
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, id = self.id.IDs['ID_CBAllEntities'])
10251027
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, id = self.id.IDs['ID_CBGridView'])
1026-
# self.Bind(wx.EVT_CHECKLISTBOX, self.EvtListBox, id = self.id.IDs['ID_LISTPlaceType'])
1028+
self.Bind(wx.EVT_SPINCTRL, self.EvtSpinCtrl, id = self.id.IDs['ID_INTMaxLineWeight'])
10271029
self.Bind(wx.EVT_CHOICE, self.EvtListBox, id = self.id.IDs['ID_LISTMapStyle'])
10281030
self.Bind(wx.EVT_BUTTON, self.EvtButton, id = self.id.IDs['ID_BTNLoad'])
10291031
self.Bind(wx.EVT_BUTTON, self.EvtButton, id = self.id.IDs['ID_BTNUpdate'])
@@ -1196,6 +1198,16 @@ def EvtListBox(self, event):
11961198
_log.error ("Uncontrol LISTbox")
11971199

11981200

1201+
def EvtSpinCtrl(self, event):
1202+
eventid = event.GetId()
1203+
_log.debug('%s, %s, %s', event.GetString(), event.IsSelection(), event.GetSelection())
1204+
_ = event.GetEventObject()
1205+
if eventid == self.id.IDs['ID_INTMaxLineWeight']:
1206+
panel.gO.MaxLineWeight = event.GetSelection()
1207+
self.NeedRedraw()
1208+
else:
1209+
_log.error ("Uncontrol SPINbox")
1210+
11991211
def EvtSlider(self, event):
12001212

12011213
_log.debug('%s', event.GetSelection())
@@ -1339,7 +1351,8 @@ def SetupButtonState(self):
13391351
self.id.CBMapMini,
13401352
self.id.CBHeatMap,
13411353
self.id.CBUseAntPath,
1342-
self.id.RBGroupBy
1354+
self.id.RBGroupBy,
1355+
self.id.LISTHeatMapTimeStep
13431356
]
13441357
marks_controls = [
13451358
self.id.CBBornMark,
@@ -1348,7 +1361,9 @@ def SetupButtonState(self):
13481361
self.id.CBMarkStarOn,
13491362
]
13501363
kml_controls = [
1351-
1364+
self.id.CBFlyTo,
1365+
self.id.ID_INTMaxLineWeight
1366+
13521367
]
13531368

13541369
# Enable/Disable marker-dependent controls if markers are off
@@ -1376,7 +1391,8 @@ def SetupButtonState(self):
13761391
# Only enable time step if timeline is enabled
13771392
if self.gO.get('MapTimeLine'):
13781393
self.id.LISTHeatMapTimeStep.Enable()
1379-
1394+
for ctrl in kml_controls:
1395+
ctrl.Disable()
13801396

13811397
else:
13821398
# In KML mode, disable HTML controls and enable KML controls
@@ -1414,13 +1430,15 @@ def SetupOptions(self):
14141430
self.id.CBHomeMarker.SetValue(self.gO.get('HomeMarker'))
14151431
self.id.CBMarkStarOn.SetValue(self.gO.get('MarkStarOn'))
14161432
self.id.CBHeatMap.SetValue(self.gO.get('HeatMap'))
1433+
self.id.CBFlyTo.SetValue(self.gO.get('UseBalloonFlyto'))
14171434
self.id.CBMapTimeLine.SetValue(self.gO.get('MapTimeLine'))
14181435
self.id.CBUseAntPath.SetValue(self.gO.get('UseAntPath'))
14191436
self.id.CBUseGPS.SetValue(self.gO.get('UseGPS'))
14201437
self.id.CBAllEntities.SetValue(self.gO.get('AllEntities'))
14211438
self.id.CBCacheOnly.SetValue(self.gO.get('CacheOnly'))
14221439
self.id.LISTHeatMapTimeStep.SetValue(self.gO.get('HeatMapTimeStep'))
14231440
self.id.LISTMapType.SetSelection(self.id.LISTMapType.FindString(self.gO.get('MapStyle')))
1441+
self.id.ID_INTMaxLineWeight.SetValue(self.gO.get('MaxLineWeight'))
14241442

14251443

14261444
# places = self.gO.get('PlaceType')
@@ -1496,7 +1514,7 @@ def runCMDfile(self, cmdline, cmdfile, isHTML=False):
14961514
if ' ' in cmdline:
14971515
cmdline = self.gO.get('CSVcmdline').replace('$n', f'{cmdfile}')
14981516
_log.info(f'shell run `{cmdfile}`')
1499-
if gOp.cmdline.startswith('http'):
1517+
if self.gOp.cmdline.startswith('http'):
15001518
webbrowser.open(cmdline, new = 0, autoraise = True)
15011519
else:
15021520
subprocess.run(cmdline, shell=True)
@@ -1516,7 +1534,12 @@ def SaveTrace(self):
15161534
return
15171535
tracepath = os.path.splitext(self.gO.Result)[0] + ".trace.txt"
15181536
# indentpath = os.path.splitext(self.gO.Result)[0] + ".indent.txt"
1519-
trace = open(tracepath , 'w')
1537+
try:
1538+
trace = open(tracepath , 'w')
1539+
except Exception as e:
1540+
logging.error("Error: Could not open trace file %s for writing %s", tracepath, e)
1541+
BackgroundProcess.SayErrorMessage(f"Error: Could not open trace file {tracepath} for writing {e}")
1542+
return
15201543
# indent = open(indentpath , 'w')
15211544
trace.write("id\tName\tYear\tWhere\tGPS\tPath\n")
15221545
# indent.write("this is an indented file with the number of generations driven by the parents\nid\tName\tYear\tWhere\tGPS\n")
@@ -1533,7 +1556,8 @@ def SaveTrace(self):
15331556
# indent.close()
15341557
_log.info(f"Trace file saved {tracepath}")
15351558
# _log.info(f"Indent file saved {indentpath}")
1536-
BackgroundProcess.SayInfoMessage(f"Trace file saved: {tracepath}",True)
1559+
withall = "with all people" if self.gO.get('AllEntities') else ""
1560+
BackgroundProcess.SayInfoMessage(f"Trace file {withall} saved: {tracepath}",True)
15371561

15381562
def OpenBrowser(self):
15391563
if self.gO.get('ResultHTML'):

gedcom-to-map/gedcomoptions.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,21 @@ def __init__ (self):
8787
if os_name == 'Windows':
8888
self.KMLcmdline = "notepad $n"
8989
self.CSVcmdline = "$n"
90+
self.Tracecmdline = "notepad $n"
91+
9092
elif os_name == 'Darwin':
9193
self.KMLcmdline = "Numbers $n"
9294
self.CSVcmdline = OFFICECMDLINE + " --calc $n"
95+
self.Tracecmdline = "Numbers $n"
9396
elif os_name == 'Linux':
9497
self.KMLcmdline = "nano $n"
9598
self.CSVcmdline = OFFICECMDLINE + " --calc $n"
99+
self.Tracecmdline = OFFICECMDLINE + " --calc $n"
100+
96101
else:
97102
self.KMLcmdline = "notepad $n"
98103
self.CSVcmdline = "notepad $n"
104+
self.Tracecmdline = "notepad $n"
99105

100106
self.BackgroundProcess = None # Background Thread for processing set later
101107
self.heritage = None
@@ -108,7 +114,7 @@ def __init__ (self):
108114
self.html_keys = {'MarksOn':0, 'HeatMap':0, 'BornMark':0, 'DieMark':0, 'MarkStarOn':0, 'GroupBy':1,
109115
'UseAntPath':0, 'MapTimeLine':0, 'HeatMapTimeStep':1, 'HomeMarker':0, 'showLayerControl':0,
110116
'mapMini':0, 'MapStyle':2}
111-
self.core_keys = {'UseGPS':0, 'CacheOnly':0, 'AllEntities':0, 'KMLcmdline':2, 'CSVcmdline':2}
117+
self.core_keys = {'UseGPS':0, 'CacheOnly':0, 'AllEntities':0, 'KMLcmdline':2, 'CSVcmdline':2, 'Tracecmdline':2}
112118
self.logging_keys = ['models.human', 'models', 'ged4py.parser', 'ged4py', 'models.creator', 'gedcomoptions', 'gedcom.gedcomparser', 'gedcom', 'gedcom.gpslookup', 'geopy', 'render.kmlexporter', 'render', 'render.foliumexp', 'gedcomvisual', 'gedcomdialogs', 'gedcomvisualgui', '__main__']
113119

114120
self.kml_keys = {'MaxLineWeight':1, 'MaxMissing':1, 'UseBalloonFlyto':0}

gedcom-to-map/render/KmlExporter.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,7 @@ def Done(self):
5858
replacement = f"href=#{replacewith};"
5959
placemark.balloonstyle.text = placemark.balloonstyle.text.replace(original, replacement)
6060

61-
# if placemark.description and placemark.description.find("href=#") >= 0:
62-
# # Loop
63-
# start = placemark.description.find("href=#",end)+6
64-
# end = placemark.description.find(";")
65-
# tag = placemark.description[start:end]
66-
# if self.gOp.Referenced.exists(tag):
67-
# # This is a hack to get to the placemark id
68-
# replacewith = 1 + int(self.gOp.Referenced.gettag(tag) )
69-
# placemark.description = placemark.description.replace(f"href=#{tag};", f"href=#{replacewith};")
61+
7062
self.gOp.step("Saving KML")
7163
logging.info("Saved as %s", self.file_name)
7264
self.kml.save(self.file_name)
@@ -92,7 +84,22 @@ def export(self, main: Pos, lines: list[Line], ntag ="", mark="native"):
9284
styleB = self.styleB
9385
else:
9486
kml = simplekml.Kml()
95-
# kml = kmlbase.newdocument(name='Family Tree')
87+
inputfile = os.path.basename(self.gOp.GEDCOMinput) if self.gOp.GEDCOMinput else "Unknown"
88+
descript = f"Family tree generated for using {inputfile}<br>{self.gOp.Name} ({self.gOp.Main}) as starting person"
89+
descript += f"<br>Marker types are {'Birth' if self.gOp.BornMark else ''} {'Death' if self.gOp.DieMark else ''}"
90+
kmloptions = []
91+
if self.gOp.MapTimeLine:
92+
kmloptions.append("Timeline enabled.")
93+
if self.gOp.UseBalloonFlyto:
94+
kmloptions.append("Balloon Flyto enabled.")
95+
if self.gOp.AllEntities:
96+
kmloptions.append("All people are included.")
97+
if kmloptions:
98+
descript += "<br>" + " ".join(kmloptions)
99+
100+
101+
kmldoc = kml.newdocument(name='About Geomap KML', description=descript)
102+
96103
self.kml = kml
97104

98105
styleA = simplekml.Style()

0 commit comments

Comments
 (0)