site_graphlogo
  -   Terms of Use and Privacy
Source Code
site_graphlogo
  -   Terms of Use and Privacy
Source Code

Source Code | MANual article and metadata maintenance and generation

This program is the main Mountain Climbing Journal UI, as well as a metadata tool for triples, particularly DFDs.

Here is how the wxPython controls are laid out:

Here is the source code:

#!/usr/bin/python3
# coding=utf-8
#MANual article and metadata maintenance and generation
#Copyright (C) 2020 Tributary Software

#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; either version 2
#of the License, or (at your option) any later version.

#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.

#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#or view the license here: https://tributarysoftware.com/gpl2.txt
import wx
import getpass
import time
import os
import markdown
import codecs
import sys
import io
import socket
import pprint
import wx.lib.inspection
import re
import uuid
import wx.html2
import datetime
from natsort import natsorted
from scandir import scandir, walk
from collections import defaultdict
from pathlib import Path
from os.path import expanduser
import platform
import subprocess
import wx.grid
import string
import ast
hostname = socket.gethostname().translate({ord(c): None for c in string.whitespace})
user = getpass.getuser().translate({ord(c): None for c in string.whitespace})
last_icon='x'
mouse_up=True
class MCJButton(wx.Button):
   def __init__(self,parent,txt):
      wx.Button.__init__(self,parent,-1,txt,size=wx.Size(35,35),style=wx.BU_EXACTFIT|wx.BORDER_NONE)
      self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
      self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
      self.Bind(wx.EVT_LEFT_DCLICK, self.OnDClick)
   def OnLeftDown(self, event):
      global last_icon
      global mouse_up
      if mouse_up:
         last_icon=self.GetLabel()
         self.SetLabel('☢')
      mouse_up=False
      event.Skip()
   def OnLeftUp(self, event):
      global mouse_up
      self.SetLabel(last_icon)
      mouse_up=True
      event.Skip()
   def OnDClick(self, event):
      self.SetLabel(last_icon)
      event.Skip()
home = expanduser("~")
try:
   out=home+'/websites/site/'+sys.argv[1]+'/'
   rootdoc=home+'/websites/source/'+sys.argv[1]+'/'
   webhostport=sys.argv[2]
   webhostname=sys.argv[3]
except:
   print('man <site> <port> <hostename>')
   sys.exit()

domainurl=''
useartdates=False
if os.path.isfile(rootdoc+'details.txt'):
   with open(rootdoc+'details.txt') as f:
      domainurl=f.readline().rstrip()
      useartdates=ast.literal_eval(f.readline().rstrip())
defdocp=rootdoc
saved_article=True
editing_article=False
tagsbyart=defaultdict(list)
artsbytag=defaultdict(list)
artstitle=defaultdict(list)
arts=defaultdict(list)
titlebycats=defaultdict(list)
catlist=[]
artfullpath=''
tags=[]
ids={}
current_base=rootdoc+'0/'
current_mta_url='http://'+webhostname+':'+webhostport+'/graph/0.nav.html'
def build_cats_arts_tags():
   global ids
   global tagsbyart
   global artsbytag
   global artstitle
   global arts
   global titlebycats
   global tags
   global catlist
   tags.clear()
   tagsbyart.clear()
   artsbytag.clear()
   artstitle.clear()
   arts.clear()
   titlebycats.clear()
   catlist=[]
   for root,dirs,files in os.walk(rootdoc, followlinks=True):
      for dname in dirs:
         f=os.path.join(root,dname)
      for fname in files:
         f=os.path.join(root,fname)
         p=f.rfind('has_tag')
         loc_art=f.find('/',f.find('/',len(rootdoc)+2)+1)
         loc_cat=f.find('/',len(rootdoc)+2)
         if p!=-1:
            o=f[p+8:-3]
            artsbytag[o].append(f[len(rootdoc):p-1])
            tagsbyart[f[len(rootdoc):p-1]].append(o)
         elif os.path.isfile(f[:loc_art]+'.date.txt') and loc_art > len(rootdoc):
            with open(f[:loc_art]+'.date.txt','r') as fl:
               date=fl.read().rstrip()
               arts[date+'.'+f[len(rootdoc):loc_art].replace('/','.')]=f[len(rootdoc):loc_art]
         elif os.path.isfile(f[:loc_art]+'.title.txt') and os.path.isfile(f[:loc_cat]+'.title.txt'):
            date=''
            arts['0000-00-00'+'.'+f[len(rootdoc):loc_art].replace('/','.')]=f[len(rootdoc):loc_art]
         if os.path.isfile(f[:loc_art]+'.title.txt'):
            with open(f[:loc_art]+'.title.txt','r') as fl:
               title=fl.read().rstrip()
               artstitle[f[len(rootdoc):loc_art]]=title
         else:
            title=''
         if os.path.isfile(f[:loc_cat]+'.title.txt'):
            with open(f[:loc_cat]+'.title.txt','r') as fl:
               title=fl.read().rstrip()
               titlebycats[f[len(rootdoc):loc_cat]]=title
         else:
            title=''
   if not os.path.isdir(rootdoc+'0/tags/'):
      os.makedirs(rootdoc+'0/tags/',exist_ok=True)
   scant=scandir(rootdoc+'0/tags/')
   for tg in scant:
      if tg.name[0:1]!='.' and tg.name.find('^^')==-1:
         curtag=tg.name[:-3]
         tags.append(curtag)
   catlist.append("New")
   for c in titlebycats:
      with open(rootdoc+c+'.title.txt') as f:
         catlist.append(f.read().rstrip())
class edt_frm(wx.Frame):
   def __init__(self):
      wx.Frame.__init__(self, None,wx.ID_ANY,'Mountain Climbing Journal',size=(wx.GetDisplaySize()[0],wx.GetDisplaySize()[1]-70))
      build_cats_arts_tags()
      self.SetBackgroundColour('#BBBBBB')
      #self.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL,wx.NORMAL, False, u'Helvetica'))
      font = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT)
      font.SetPointSize(13)
      self.SetFont(font)
      mcj_pnl=wx.Panel(self)
      mui_siz= wx.BoxSizer()
      mcj_nbk=wx.Notebook(mcj_pnl)
      mui_siz.Add(mcj_nbk,1, wx.EXPAND|wx.ALL,2)
      mcj_pnl.SetSizer(mui_siz)
      mje_pnl=wx.Panel(mcj_nbk)
      mjt_pnl=wx.Panel(mcj_nbk)
      mjv_pnl=wx.Panel(mcj_nbk)
      mta_tre = wx.TreeCtrl(mjt_pnl, -1, wx.DefaultPosition, wx.DefaultSize,
                         wx.TR_HAS_BUTTONS
                         | wx.TR_EDIT_LABELS
                         )
      isz = (16,16)
      ver_tre = wx.TreeCtrl(mjv_pnl, -1, wx.DefaultPosition, wx.DefaultSize,
                         wx.TR_HAS_BUTTONS
                         | wx.TR_EDIT_LABELS
                         )
      isz = (16,16)
      il = wx.ImageList(isz[0], isz[1])
      fldridx     = il.Add(wx.ArtProvider.GetBitmap(wx.ART_FOLDER,      wx.ART_OTHER, isz))
      fileidx     = il.Add(wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, isz))
      ver_tre.SetImageList(il)
      mta_tre.SetImageList(il)
      ver_tre.il = il
      mta_tre.il = il
      rootm= rootdoc+'0/'
      #thanks to Γ–rjan Persson
      #https://wiki.wxpython.org/TreeControls#Lazy_Evaluation_Directory_Browser_Example
      ids= {rootm : mta_tre.AddRoot(rootm)}
      bits=re.compile('^(\d+)$')
      for (dirpath, dirnames, filenames) in os.walk(rootm):
         for dirname in dirnames:
            fullpath = os.path.join(dirpath, dirname)
            try:
               m = bits.match(dirname)
               label=m.group(1)
               ids[fullpath] = mta_tre.AppendItem(ids[dirpath], dirname)
            except:
               six=9
      root = ver_tre.AddRoot("0")
      ver_tre.SetItemData(root, None)
      ver_tre.SetItemImage(root, fldridx, wx.TreeItemIcon_Normal)
      for x in titlebycats:
         child = ver_tre.AppendItem(root, x[2:]+' - '+titlebycats[x])
         ver_tre.SetItemData(child, None)
         ver_tre.SetItemImage(child, fldridx, wx.TreeItemIcon_Normal)
         for y in sorted(arts,reverse=True):
            lstslash=arts[y].rfind('/')
            if arts[y][:lstslash]==x:
               last = ver_tre.AppendItem(child, arts[y][lstslash+1:]+' - '+artstitle[arts[y]])
               ver_tre.SetItemData(last, None)
               ver_tre.SetItemImage(last, fldridx, wx.TreeItemIcon_Normal)
      cfg_pnl = wx.Panel(mje_pnl)
      brw_pnl = wx.Panel(mje_pnl)
      tag_pnl = wx.Panel(mje_pnl)
      adt_txt = wx.TextCtrl(brw_pnl,size=wx.Size(130,35),style = wx.TE_PROCESS_ENTER)
      aph_txt = wx.TextCtrl(cfg_pnl,style = wx.TE_READONLY)
      mkd_txt = wx.TextCtrl(cfg_pnl,style = wx.TE_MULTILINE)
      attr=wx.TextAttr()
      attr.SetLeftIndent(22,subIndent=0)
      mkd_txt.SetDefaultStyle(attr)
      tgg_txt = wx.TextCtrl(tag_pnl,size=wx.Size(160,35),style = wx.TE_PROCESS_ENTER)
      ttl_txt = wx.TextCtrl(cfg_pnl,style = wx.TE_PROCESS_ENTER)
      sid_txt = wx.TextCtrl(mjt_pnl,size=wx.Size(50,35))
      cpr_txt = wx.TextCtrl(mjt_pnl,size=wx.Size(200,35))
      pxt_txt = wx.TextCtrl(mjt_pnl,style = wx.TE_MULTILINE)
      slb_txt = wx.TextCtrl(mjt_pnl,style = wx.TE_MULTILINE)
      oxt_txt = wx.TextCtrl(mjt_pnl,style = wx.TE_MULTILINE)
      pid_txt = wx.TextCtrl(mjt_pnl)
      sxt_txt = wx.TextCtrl(mjt_pnl,style = wx.TE_MULTILINE)
      plb_txt = wx.TextCtrl(mjt_pnl,style = wx.TE_MULTILINE)
      olb_txt = wx.TextCtrl(mjt_pnl,style = wx.TE_MULTILINE)
      oid_txt = wx.TextCtrl(mjt_pnl,size=wx.Size(200,35))
      tag_lsb = wx.ListBox(tag_pnl,style=wx.LB_MULTIPLE)
      vps_grd = wx.grid.Grid(mjv_pnl,-1,wx.DefaultPosition,size=wx.Size(-1,140))
      vps_txt = wx.TextCtrl(mjv_pnl,style = wx.TE_MULTILINE)
      pth_txt = wx.TextCtrl(mjv_pnl)
      fwd_btn = MCJButton(brw_pnl,"β†’")
      bak_btn = MCJButton(brw_pnl,"←")
      apl_btn = MCJButton(brw_pnl,"πŸ’Ύ")
      hom_btn = MCJButton(brw_pnl,"🏠")
      spl_btn = MCJButton(brw_pnl,"πŸ” ")
      vps_btn = MCJButton(mjv_pnl,"βœ”οΈ")
      svp_btn = MCJButton(mjt_pnl,"βœ”οΈ")
      can_btn = MCJButton(mjv_pnl,"🚫")
      cnc_btn = MCJButton(brw_pnl,"🚫")
      dvp_btn = MCJButton(mjt_pnl,"❌")
      cat_cho = wx.Choice(brw_pnl,size=wx.Size(-1,35),choices=catlist)
      mai_web = wx.html2.WebView.New(brw_pnl)
      mta_web = wx.html2.WebView.New(mjt_pnl)
      sub_stx = wx.StaticText(mjt_pnl,label="Subject:")
      cpr_stx = wx.StaticText(mjt_pnl,label="Contains:")
      pre_stx = wx.StaticText(mjt_pnl,label="Predicate:")
      obj_stx = wx.StaticText(mjt_pnl,label="Object:")
      bms_vsz=wx.BoxSizer(wx.VERTICAL)
      bmp_vsz=wx.BoxSizer(wx.VERTICAL)
      bmo_vsz=wx.BoxSizer(wx.VERTICAL)
      bmb_hsz= wx.BoxSizer(wx.HORIZONTAL)
      cfg_vsz= wx.BoxSizer(wx.VERTICAL)
      brw_vsz = wx.BoxSizer(wx.VERTICAL)
      msc_hsz=wx.BoxSizer(wx.HORIZONTAL)
      bcb_hsz = wx.BoxSizer(wx.HORIZONTAL)
      tag_vsz= wx.BoxSizer(wx.VERTICAL)
      tcl_hsz=wx.BoxSizer(wx.HORIZONTAL)
      ver_hsz=wx.BoxSizer(wx.HORIZONTAL)
      ver_vsz=wx.BoxSizer(wx.VERTICAL)
      vfd_vsz=wx.BoxSizer(wx.VERTICAL)
      vfd_hsz=wx.BoxSizer(wx.HORIZONTAL)
      bmo_hsz=wx.BoxSizer(wx.HORIZONTAL)
      ver_hsz.Add(ver_vsz, 1,wx.EXPAND| wx.ALL, 1)
      ver_hsz.Add(vfd_vsz, 1,wx.EXPAND| wx.ALL, 1)
      ver_vsz.Add(ver_tre, 1,wx.EXPAND| wx.ALL, 1)
      vfd_vsz.Add(vps_grd, 1,wx.EXPAND| wx.ALL, 1)
      vfd_vsz.Add(vps_txt, 2,wx.EXPAND| wx.ALL, 1)
      vfd_vsz.Add(vfd_hsz, 1,wx.EXPAND| wx.ALL, 1)
      vfd_hsz.Add(vps_btn, 0,wx.LEFT|wx.RIGHT, 1)
      vfd_hsz.Add(can_btn, 0,wx.LEFT|wx.RIGHT, 1)
      bmo_hsz.Add(svp_btn, 0,wx.LEFT|wx.RIGHT, 1)
      bmo_hsz.Add(dvp_btn, 0,wx.LEFT|wx.RIGHT, 1)
      vfd_hsz.Add(pth_txt, 1, wx.ALL, 1)
      fxx= wx.SizerFlags(1)
      cfg_vsz.Add(msc_hsz, 0, wx.EXPAND|wx.RIGHT, 1)
      cfg_vsz.Add(mkd_txt, 1,wx.EXPAND| wx.ALL, 1)
      fxx.Proportion(0).Border(wx.LEFT|wx.RIGHT, 1)
      bcb_hsz.AddMany([(cat_cho,fxx),(adt_txt,fxx),(bak_btn,fxx),
                        (fwd_btn,fxx),(apl_btn,fxx),(hom_btn,fxx),(spl_btn,fxx),(cnc_btn,fxx)])
      msc_hsz.Add(aph_txt, 3, wx.ALL, 1)
      msc_hsz.Add(ttl_txt, 2, wx.ALL, 1)
      fxx.Proportion(1).Expand().Border(wx.ALL,1)
      bmb_hsz.AddMany([(bms_vsz),(slb_txt,fxx),(sxt_txt,fxx),(bmp_vsz),
         (plb_txt,fxx),(pxt_txt,fxx),(bmo_vsz),(olb_txt,fxx), (oxt_txt,fxx)])
      bms_vsz.AddMany([(sub_stx,fxx),(sid_txt,fxx),(cpr_stx,fxx),(cpr_txt,fxx)])
      bmp_vsz.AddMany([(pre_stx,fxx),(pid_txt,fxx)])
      bmo_vsz.AddMany([(obj_stx,fxx),(oid_txt,fxx),(bmo_hsz)])
      mjv_pnl.SetSizer(ver_hsz)
      brw_vsz.Add(bcb_hsz, 0, wx.ALL, 1)
      brw_vsz.Add(mai_web, 4, wx.EXPAND|wx.ALL, 1)
      brw_pnl.SetSizer(brw_vsz)
      tcl_hsz.Add(tgg_txt,0, wx.EXPAND|wx.ALL, 1)
      tag_vsz.Add(tcl_hsz, 0, wx.EXPAND|wx.ALL, 0)
      tag_vsz.Add(tag_lsb, 1,wx.ALL | wx.EXPAND, 1)
      tag_pnl.SetSizer(tag_vsz)
      cfg_pnl.SetSizer(cfg_vsz)
      mcj_nbk.AddPage(mje_pnl,"Edit")
      mcj_nbk.AddPage(mjt_pnl,"Tree")
      mcj_nbk.AddPage(mjv_pnl,"Versions")
      mcj_pnl.SetBackgroundColour(wx.Colour('lime green'))
      edt_hsz=wx.BoxSizer(wx.HORIZONTAL)
      edt_hsz.Add(cfg_pnl,2,wx.EXPAND)
      edt_hsz.Add(brw_pnl,3,wx.EXPAND)
      edt_hsz.Add(tag_pnl,0,wx.EXPAND)
      mje_pnl.SetSizer(edt_hsz)
      tre_vsz=wx.BoxSizer(wx.VERTICAL)
      tre_hsz=wx.BoxSizer(wx.HORIZONTAL)
      tre_hsz.Add(mta_tre, 1, wx.EXPAND|wx.ALL, 3)
      tre_hsz.Add(mta_web, 4, wx.EXPAND|wx.ALL, 3)
      tre_vsz.Add(bmb_hsz,1,wx.EXPAND)
      tre_vsz.Add(tre_hsz,4,wx.EXPAND)
      mjt_pnl.SetSizer(tre_vsz)
      mjt_pnl.SetBackgroundColour(wx.Colour('gold'))
      edt_hsz.Layout()
      tre_vsz.Layout()
      ver_hsz.Layout()
      self.Centre()
      mta_web.LoadURL(current_mta_url)
      brw_pnl.Layout()
      mkd_txt.MacCheckSpelling(True)
      tag_lsb.Clear()
      mjv_pnl.Bind(wx.EVT_BUTTON,lambda event: apply_version(),vps_btn)
      mjv_pnl.Bind(wx.EVT_BUTTON,lambda event: cancel_version(),can_btn)
      brw_pnl.Bind(wx.EVT_BUTTON,lambda event: home_page(),hom_btn)
      brw_pnl.Bind(wx.EVT_BUTTON,lambda event: spell_page(),spl_btn)
      brw_pnl.Bind(wx.EVT_BUTTON,lambda event: cancel_main(),cnc_btn)
      brw_pnl.Bind(wx.EVT_BUTTON,lambda event: mai_web.CanGoBack() and mai_web.GoBack(), bak_btn)
      brw_pnl.Bind(wx.EVT_BUTTON,lambda event: mai_web.CanGoForward() and mai_web.GoForward(), fwd_btn)
      cfg_pnl.Bind(wx.EVT_TEXT,lambda event: md_changed(), mkd_txt)
      brw_pnl.Bind(wx.EVT_BUTTON,lambda event: apply_page(), apl_btn)
      tag_pnl.Bind(wx.EVT_LISTBOX_DCLICK, lambda event: tag_change(), tag_lsb)
      self.Bind(wx.EVT_TEXT_ENTER, lambda event: tag_txt(), tgg_txt)
      self.Bind(wx.EVT_CHOICE, lambda event: change_cat(), cat_cho)
      mjv_pnl.Bind(wx.EVT_TREE_SEL_CHANGED, lambda event: change_tre(event), ver_tre)
      mjv_pnl.Bind(wx.grid.EVT_GRID_SELECT_CELL, lambda event: change_grd(event), vps_grd)
      brw_pnl.Bind(wx.html2.EVT_WEBVIEW_NAVIGATING, lambda event: page_about(event), mai_web)
      mjt_pnl.Bind(wx.html2.EVT_WEBVIEW_NAVIGATING, lambda event: page_tree(event), mta_web)
      mjt_pnl.Bind(wx.EVT_TREE_SEL_CHANGED, lambda event: changemta_tre(event), mta_tre)
      mjt_pnl.Bind(wx.EVT_BUTTON, lambda event: save_mta(), svp_btn)
      mjt_pnl.Bind(wx.EVT_BUTTON, lambda event: delete_mta(), dvp_btn)
      brw_pnl.Bind(wx.html2.EVT_WEBVIEW_LOADED, lambda event: page_loaded(event), mai_web)
      mcj_pnl.SetBackgroundColour(wx.Colour('lime green'))
      vps_grd.CreateGrid(200,3)
      vps_grd.SetColLabelValue(0, "Timestamp")
      vps_grd.SetColSize(0,300)
      vps_grd.SetColLabelValue(1, "User")
      vps_grd.SetColSize(1,80)
      vps_grd.SetColLabelValue(2, "Computer")
      vps_grd.SetColSize(2,100)
      def spell_page():
         rsproc=subprocess.run(['xterm -e /usr/bin/aspell -c '+aph_txt.GetValue()+'narrative.md'], shell=True,capture_output=True,text=True)
         print(rsproc)
      def save_mta():
         with open(current_base+'/'+sid_txt.GetValue()+'.title.txt','w') as f:
            f.write(slb_txt.GetValue())
         if pid_txt.GetValue()=='<->':
            pred='/has_specified_inp_and_out/'
         elif pid_txt.GetValue()=='->':
            pred='/has_specified_output/'
         elif pid_txt.GetValue()=='<-':
            pred='/has_specified_input/'
         if not os.path.isdir(current_base+'/'+sid_txt.GetValue()+pred):
            os.makedirs(current_base+'/'+sid_txt.GetValue()+pred,exist_ok=True)
         with open(current_base+'/'+sid_txt.GetValue()+'.details.txt','w') as f:
            f.write(sxt_txt.GetValue())
         with open(current_base+'/'+sid_txt.GetValue()+'.contains.txt','w') as f:
            f.write(cpr_txt.GetValue())
         with open(current_base+'/'+oid_txt.GetValue()+'.details.txt','w') as f:
            f.write(oxt_txt.GetValue())
         bits=re.compile('^(\d+)$')
         print(current_base)
         m = bits.match(oid_txt.GetValue())
         try:
            label=m.group(1)
            with open(current_base+'/'+oid_txt.GetValue()+'.title.txt','w') as f:
               f.write(olb_txt.GetValue())
         except:
            with open(current_base+'/'+oid_txt.GetValue()+'.txt','w') as f:
               f.write(olb_txt.GetValue())
         os.system('cd '+current_base+'/'+sid_txt.GetValue()+pred+';ln -s ../../'+oid_txt.GetValue()+'.txt ./'+oid_txt.GetValue()+'.txt')
         pl=plb_txt.GetValue()
         if pl!='':
            with open(current_base+'/'+sid_txt.GetValue()+pred+oid_txt.GetValue()+'.predlabel.txt','w') as f:
               f.write(pl)
         px=pxt_txt.GetValue()
         if px!='':
            with open(current_base+'/'+sid_txt.GetValue()+pred+oid_txt.GetValue()+'.details.txt','w') as f:
               f.write(px)
      def delete_mta():
         if pid_txt.GetValue()=='<->':
            pred='/has_specified_inp_and_out/'
         elif pid_txt.GetValue()=='->':
            pred='/has_specified_output/'
         elif pid_txt.GetValue()=='<-':
            pred='/has_specified_input/'
         os.system('cd '+current_base+'/'+sid_txt.GetValue()+pred+';rm '+oid_txt.GetValue()+'.txt')
      def page_tree(event):
         url_now=event.GetURL()
         item=url_now[url_now.find(webhostport)+len(webhostport):-1]
         if current_mta_url!=url_now:
            curr_obj=url_now[url_now[:-1].rfind('/')+1:-1]
            if sid_txt.GetValue()=='' and curr_obj.find('about')==-1:
               mjt_pnl.SetBackgroundColour(wx.Colour('firebrick'))
               sid_txt.SetValue(curr_obj)
               if os.path.isfile(rootdoc+'0'+item+'.contains.txt'):
                  with open(rootdoc+'0'+item+'.contains.txt') as f:
                     cpr_txt.SetValue(f.read())
               if os.path.isfile(rootdoc+'0'+item+'.title.txt'):
                  with open(rootdoc+'0'+item+'.title.txt') as f:
                     slb_txt.SetValue(f.read())
               if os.path.isfile(rootdoc+'0'+item+'.details.txt'):
                  with open(rootdoc+'0'+item+'.details.txt') as f:
                     sxt_txt.SetValue(f.read())
            elif oid_txt.GetValue()=='':
               mjt_pnl.SetBackgroundColour(wx.Colour('grey'))
               oid_txt.SetValue(curr_obj)
               if os.path.isfile(rootdoc+'0'+item+'.txt'):
                  with open(rootdoc+'0'+item+'.txt') as f:
                     olb_txt.SetValue(f.read())
               elif os.path.isfile(rootdoc+'0'+item+'.title.txt'):
                  with open(rootdoc+'0'+item+'.title.txt') as f:
                     olb_txt.SetValue(f.read())
               if os.path.isfile(rootdoc+'0'+item+'.details.txt'):
                  with open(rootdoc+'0'+item+'.details.txt') as f:
                     oxt_txt.SetValue(f.read())
               base=rootdoc+'0'+item[:item.rfind('/')]
               preds= [('/has_specified_inp_and_out/','<->'),('/has_specified_input/','<-'),('/has_specified_output/','->')]
               for pred in preds:
                  if os.path.isfile(base+'/'+sid_txt.GetValue()+pred[0]+oid_txt.GetValue()+'.txt'):
                     pid_txt.SetValue(pred[1])
                  if os.path.isfile(base+'/'+sid_txt.GetValue()+pred[0]+oid_txt.GetValue()+'.details.txt'):
                     with open(base+'/'+sid_txt.GetValue()+pred[0]+oid_txt.GetValue()+'.details.txt') as f:
                        pxt_txt.SetValue(f.read())
                  if os.path.isfile(base+'/'+sid_txt.GetValue()+pred[0]+oid_txt.GetValue()+'.predlabel.txt'):
                     with open(base+'/'+sid_txt.GetValue()+pred[0]+oid_txt.GetValue()+'.predlabel.txt') as f:
                        plb_txt.SetValue(f.read())
            else:
               mjt_pnl.SetBackgroundColour(wx.Colour('gold'))
               sid_txt.SetValue('')
               oid_txt.SetValue('')
               pid_txt.SetValue('')
               slb_txt.SetValue('')
               olb_txt.SetValue('')
               plb_txt.SetValue('')
               sxt_txt.SetValue('')
               oxt_txt.SetValue('')
               pxt_txt.SetValue('')
               current_base='/dev/null'
            event.Veto()
      def apply_version():
         new_version=vps_txt.GetValue()
         version_path=pth_txt.GetValue()
         if len(new_version)>2 and len(version_path)>len(rootdoc):
            with open(version_path,'w') as f:
               f.write(new_version)
      def cancel_main():
         global catlist
         global artfullpath
         global tags
         global saved_article
         global editing_article
         catlist=[]
         artfullpath=''
         tags=[]
         saved_article=True
         mcj_pnl.SetBackgroundColour(wx.Colour('lime green'))
         editing_article=False
         mai_web.SetPage('','/')
         mkd_txt.Clear()
         aph_txt.Clear()
         tag_lsb.Clear()
         ttl_txt.Clear()
         adt_txt.Clear()
      def cancel_version():
         vps_grd.ClearGrid()
         vps_txt.Clear()
         pth_txt.Clear()
         versions=[]
      def change_grd(event):
         row=event.GetRow()
         grid_timestamp=vps_grd.GetCellValue(row,0)
         grid_user=vps_grd.GetCellValue(row,1)
         grid_hostname=vps_grd.GetCellValue(row,2)
         tree_parent=ver_tre.GetItemText(ver_tre.GetItemParent(ver_tre.GetSelection()))
         tree_child=ver_tre.GetItemText(ver_tre.GetSelection())
         tree_category=tree_parent[:tree_parent.find(' - ')]
         tree_article=tree_child[:tree_child.find(' - ')]
         ver_path=rootdoc+'0/'+tree_category+'/'+tree_article+'/'+grid_timestamp+'^^'+grid_user+'^^'+grid_hostname+'^^narrative.md'
         if os.path.isfile(ver_path):
            with open(ver_path) as f:
               vps_txt.Clear()
               vps_txt.write(f.read())
               pth_txt.Clear()
               pth_txt.write(rootdoc+'0/'+tree_category+'/'+tree_article+'/narrative.md')
         else:
            vps_txt.Clear()
            pth_txt.Clear()
      def changemta_tre(event):
         global current_mta_url
         global current_base
         current_base='/dev/null'
         for id in ids:
            if ids[id]==event.GetItem():
               current_base=id
               current_mta_urlt='http://'+webhostname+':'+webhostport+'/graph/'+id[len(rootdoc):].replace('/','.')+'.nav.html'
               current_mta_url=current_mta_urlt.replace('..','.')
               mta_web.LoadURL(current_mta_url)
      def change_tre(event):
         vps_grd.ClearGrid()
         vps_txt.Clear()
         pth_txt.Clear()
         versions=[]
         eitm=event.GetItem()
         try:
            parent=ver_tre.GetItemText(ver_tre.GetItemParent(event.GetItem()))
            if parent!='0':
               child=ver_tre.GetItemText(eitm)
               art='0/'+parent[:parent.find(' - ')]+'/'+child[:child.find(' - ')]
               scanc=scandir(rootdoc+art)
               for c in scanc:
                  if c.name.find('^^')!=-1 and c.name.find('.md')!=-1:
                     versions.append(c.name)
               i=0
               for c in sorted(versions,reverse=True):
                  parts=c.split('^^')
                  vps_grd.SetCellValue(i,0,parts[0])
                  vps_grd.SetReadOnly(i,0,isReadOnly=True)
                  vps_grd.SetCellValue(i,1,parts[1])
                  vps_grd.SetReadOnly(i,1,isReadOnly=True)
                  vps_grd.SetCellValue(i,2,parts[2])
                  vps_grd.SetReadOnly(i,2,isReadOnly=True)
                  i+=1
         except:
            vps_grd.ClearGrid()
            vps_txt.Clear()
            pth_txt.Clear()
            versions=[]
      def md_changed():
         global saved_article
         global editing_article
         if editing_article:
            saved_article=False
            mcj_pnl.SetBackgroundColour(wx.Colour('red'))
         else:
            editing_article=True
      def change_cat():
         global editing_article
         global saved_article
         global artnum
         global artfullpath
         last_cat=cat_cho.GetString(cat_cho.GetCurrentSelection())
         if saved_article or not editing_article and last_cat !='New':
            saved_article=True
            mcj_pnl.SetBackgroundColour(wx.Colour('lime green'))
            editing_article=False
            mai_web.SetPage('','/')
            mkd_txt.Clear()
            aph_txt.Clear()
            tag_lsb.Clear()
            ttl_txt.Clear()
            adt_txt.Clear()
            artfullpath=''
            self.GetTopLevelParent().SetFocus()
            aa=[]
            cc=''
            scanc=scandir(rootdoc+'0/')
            for c in scanc:
               if os.path.isfile(rootdoc+'0/'+c.name+'.title.txt') and c.name.find('^^')==-1:
                  with open(rootdoc+'0/'+c.name+'.title.txt') as f:
                     fs=f.read().rstrip()
                     if fs==last_cat:
                        cc=c.name
                        scana=scandir(rootdoc+'0/'+c.name+'/')
                        for na in scana:
                           if na.name[-9:]=='title.txt' and na.name.find('^^')==-1:
                              aa.append(na.name[:-10])
            f=False
            prv=0
            j=0
            for a in natsorted(aa):
               if (int(a)-prv!=1) and f:
                  j=int(a)-1
                  break
               prv=int(a)
               f=True
               j=int(a)+1
            artnum=str(j)
            adt_txt.write(datetime.date.isoformat(datetime.datetime.now()))
            aph_txt.write(rootdoc+'0/'+cc+'/'+str(j)+'/')
            mkd_txt.write(' '+'\n--\nComment:\n')
            os.makedirs(rootdoc+'0/'+cc+'/'+str(j)+'/')
            with open(rootdoc+'0/'+cc+'/'+str(j)+'/narrative.md','w') as fl:
              fl.write('')
            artfullpath=rootdoc+'0/'+cc+'/'+str(j)+'/'
            editing_article=True
            saved_article=False
            mcj_pnl.SetBackgroundColour(wx.Colour('red'))
            #build_cats_arts_tags()
         else:
            cat_cho.SetSelection(0)
      def home_page():
         self.GetTopLevelParent().SetFocus()
         mai_web.LoadURL('http://'+webhostname+':'+webhostport+'/')
      def apply_page():
         self.GetTopLevelParent().SetFocus()
         global arttags
         global saved_article
         global editing_article
         build_cats_arts_tags()
         arttags=tagsbyart[artnum]
         curmd=mkd_txt.GetValue().split('\n--\nComment:\n')
         mkd_txt.Clear()
         mkd_txt.write(curmd[0].rstrip()+'\n--\nComment:\n')
         if len(curmd[1])>5:
            if os.path.isdir(artfullpath+'0/')==False:
               os.mkdir(artfullpath+'0/')
            with open(artfullpath+'0/narrative.md','a+') as f:
               f.write('**'+datetime.date.isoformat(datetime.datetime.now())+'** :\n\n'+curmd[1].rstrip()+'\n'+'\n')
         if useartdates:
            with open(artfullpath[:-1]+'.date.txt','w') as f:
               currdate=adt_txt.GetValue()
               if len(currdate)==10:
                  f.write(currdate)
         with open(artfullpath[:-1]+'.title.txt','w') as f:
            currtitle=ttl_txt.GetValue()
            if len(currtitle)>1:
               f.write(currtitle)
         with open(artfullpath+'narrative.md','w') as f:
            if len(curmd[0])>10:
               f.write(curmd[0])
               saved_article=True
               mcj_pnl.SetBackgroundColour(wx.Colour('lime green'))
               editing_article=False
         ts=datetime.datetime.utcnow().isoformat(sep='T', timespec='milliseconds').replace(':','').replace('-','').replace(' ','')+'Z'
         with open(artfullpath+ts+'^^'+user+'^^'+hostname+'^^'+'narrative.md','w') as f:
            f.write(curmd[0])
         with open(artfullpath+'narrative.md') as f:
            if curmd[0]==f.read():
               six=9
            else:
               with open(rootdoc+'../../recovery/'+datetime.date.isoformat(datetime.datetime.now())+'_'+str(uuid.uuid4())+'.md','w') as rec:
                  rec.write(curmd[0])
         cat_cho.SetSelection(0)
      def set_article_tags(article):
         global arttags
         arttags=tagsbyart[article]
         build_cats_arts_tags()
         for i in tag_lsb.GetSelections():
            tag_lsb.Deselect(i)
         for tg in tagsbyart[article]:
            tag_lsb.SetSelection(tag_lsb.FindString(tg))
      def refresh_tag_list():
         build_cats_arts_tags()
         tag_lsb.Clear()
         alli=[]
         for lines in sorted(tags):
            alli.append(lines)
         try:
            tag_lsb.InsertItems(alli,0)
         except:
            six=9
      def tag_txt():
         open(rootdoc+'0/tags/'+tgg_txt.GetLineText(0)+'.md', 'a').close()
         refresh_tag_list()
         os.utime(artfullpath+'narrative.md', None)
      def tag_change():
         six=9
         for i in range(0,tag_lsb.GetCount()):
            if tag_lsb.IsSelected(i):
               seltag=tag_lsb.GetString(i)
               if os.path.isfile(artfullpath+'has_tag/'+tag_lsb.GetString(i)+'.md'):
                  print ('we already have selection: '+tag_lsb.GetString(i))
                  os.remove(artfullpath+'has_tag/'+tag_lsb.GetString(i)+'.md')
               elif not os.path.isfile(artfullpath+'has_tag/'+tag_lsb.GetString(i)+'.md'):
                  print ('we did not have selection,  so making it: '+tag_lsb.GetString(i))
                  os.system('mkdir -p '+artfullpath+'has_tag/ ;cd '+artfullpath+'has_tag/;ln -s ../../../tags/'+tag_lsb.GetString(i)+'.md ./'+tag_lsb.GetString(i)+'.md')
         set_article_tags(artnum)
      def page_about(event):
         if saved_article:
            curr=event.GetURL()
            if mcj_nbk.GetSelection()==0:
               try:
                  pg=re.search(re.escape('http://'+webhostname+':'+webhostport+'/(.+)/',curr).group(1))
               except:
                  six=9
         else:
            event.Veto()
      def page_loaded(event):
         fl=False
         refresh_tag_list()
         global live_article
         global saved_article
         global editing_article
         global artnum
         global artfullpath
         pg=''
         nxtu=event.GetURL()
         try:
            pg=re.search(re.escape('http://'+webhostname+':'+webhostport)+'/(\d+/\d+)/',nxtu).group(1)
         except:
            fl=True
            artnum=''
            artfullpath=''
            aph_txt.Clear()
            ttl_txt.Clear()
            mkd_txt.Clear()
            cat_cho.SetSelection(0)
         if not fl:
            artnum='0/'+pg
            set_article_tags(artnum)
            cat=artnum[:artnum.find('/',artnum.find('/')+1)]
            artfullpath=rootdoc+artnum+'/'
            aph_txt.Clear()
            aph_txt.write(artfullpath)
            if os.path.isfile(artfullpath+'narrative.md'):
               with io.open(artfullpath+'narrative.md',encoding='utf8') as f:
                  narrative=f.read().rstrip()
            else:
               narrative='put article in here'
            mkd_txt.Clear()
            mkd_txt.write(narrative+'\n--\nComment:\n')
            live_article=True
            with open(artfullpath[:-1]+'.title.txt') as f:
               ttl_txt.Clear()
               ttl_txt.write(f.read().rstrip().replace('\n',' '))
            if os.path.isfile(artfullpath[:-1]+'.date.txt'):
               adt_txt.Clear()
               with open(artfullpath[:-1]+'.date.txt') as f:
                  adt_txt.write(f.read().encode('utf8'))
         else:
            print('tree')
         editing_article=False
         saved_article=True
         mcj_pnl.SetBackgroundColour(wx.Colour('lime green'))
class Browse(wx.App):
    def OnInit(self):
        self.frame = edt_frm()
        self.SetTopWindow(self.frame)
        self.frame.Show()
        #wx.lib.inspection.InspectionTool().Show()
        return True
if __name__ == '__main__':
   app = Browse()
   app.MainLoop()

raw source