1115 lines
36 KiB
Python
Executable File
1115 lines
36 KiB
Python
Executable File
"""
|
|
* Author: "PepDebian(peppermintosteam@proton.me)
|
|
*
|
|
* License: SPDX-License-Identifier: GPL-3.0-or-later
|
|
*
|
|
* Standard SSB manager
|
|
"""
|
|
|
|
import subprocess
|
|
import os
|
|
import stat
|
|
import sqlite3
|
|
import tkinter as tk
|
|
from tkinter import END
|
|
import shutil
|
|
import requests
|
|
import favicon
|
|
import bs4
|
|
from tkinter import Frame
|
|
from tkinter import filedialog
|
|
from tkinter.filedialog import askopenfile
|
|
import ttkbootstrap as ttk
|
|
import bsconf
|
|
|
|
|
|
# setup the window
|
|
pwin = bsconf.bbstyle
|
|
# ttk.Window(themename="darkly")
|
|
pwin.title('Peppermint Kumo')
|
|
pwin.tk.call('wm', 'iconphoto', pwin._w,
|
|
tk.PhotoImage(
|
|
file='/opt/pypep/kumosm.png'))
|
|
pwin['bg'] = '#000000'
|
|
####
|
|
# set the database connection string
|
|
####
|
|
dcon = sqlite3.connect('/opt/pypep/dbpep/welval.db')
|
|
pcur = dcon.cursor()
|
|
####
|
|
# Create the update table
|
|
####
|
|
pcur.execute(""" CREATE TABLE IF NOT EXISTS kumoapp (id integer PRIMARY
|
|
KEY AUTOINCREMENT, usrname text, appname text, lnk text,
|
|
iconpath text, public text, menu text);""")
|
|
|
|
|
|
def mkenew():
|
|
"""Make a new records in the kummoapp database"""
|
|
usr = txtcappuser.get()
|
|
nameapp = txtcappname.get()
|
|
addlnk = txtcappaddrs.get()
|
|
pathapp = txtcapppath.get()
|
|
menuapp = cmboc.get()
|
|
if cbpub_v.get() == 1:
|
|
# set the queries public
|
|
appinsert = """ INSERT INTO kumoapp(usrname, appname, lnk, iconpath,
|
|
menu, public) VALUES(?,?,?,?,?, 'yes');"""
|
|
pcur.execute(appinsert, (usr, nameapp, addlnk, pathapp, menuapp,))
|
|
dcon.commit()
|
|
else:
|
|
# set the queries not public
|
|
appinsert = """ INSERT INTO kumoapp(usrname, appname, lnk, iconpath,
|
|
menu, public) VALUES(?,?,?,?,?, 'no');"""
|
|
pcur.execute(appinsert, (usr, nameapp, addlnk, pathapp, menuapp,))
|
|
dcon.commit()
|
|
|
|
|
|
def dben():
|
|
"""Set the logged in user entry to disabled"""
|
|
txtcappuser.config(state="disabled")
|
|
|
|
|
|
def inptcm():
|
|
"""set the combobox value"""
|
|
db = sqlite3.connect('/opt/pypep/dbpep/welval.db')
|
|
cursor = db.execute('SELECT appname FROM kumoapp')
|
|
result = []
|
|
for row in cursor.fetchall():
|
|
result.append(row[0])
|
|
return result
|
|
|
|
|
|
def ssbwritepub():
|
|
"""Write the public py file that will be the SSB """
|
|
nmg = txtcappname.get()
|
|
nm = "".join(nmg.split())
|
|
pth = "/opt/pypep/"
|
|
wurl = txtcappaddrs.get()
|
|
ico = txtcapppath.get()
|
|
setburl = ' baseurl = "' + wurl + '"\n'
|
|
setburltb = ' baseurl = "' + wurl + '"\n'
|
|
seturl = ' url = QUrl((baseurl))\n'
|
|
settle = ' self.setWindowTitle("' + nm + '")\n'
|
|
setico = ' self.setWindowIcon(QIcon(' + ico + '))\n'
|
|
htmlp = "'html.parser'"
|
|
f = open(pth + nm + ".py", 'x')
|
|
f.write('#!/usr/bin/env python3\n')
|
|
f.write('\n')
|
|
f.write('from PyQt5.QtCore import *\n')
|
|
f.write('from PyQt5.QtWidgets import *\n')
|
|
f.write('from PyQt5.QtGui import *\n')
|
|
f.write('from PyQt5.QtWebEngineWidgets import *\n')
|
|
f.write('from bs4 import BeautifulSoup\n')
|
|
f.write('import requests\n')
|
|
f.write('\n')
|
|
f.write('class TabWidget(QTabWidget):\n')
|
|
f.write(' """Set tup the tab and windows layout"""\n')
|
|
f.write(' def __init__(self, *args, **kwargs):\n')
|
|
f.write(' QTabWidget.__init__(self, *args, **kwargs)\n')
|
|
f.write(settle)
|
|
f.write(setico)
|
|
f.write(' self.setTabsClosable(True)\n')
|
|
f.write(' self.tabCloseRequested.connect( self.close_current_tab )\n')
|
|
f.write(' self.setDocumentMode(True)\n')
|
|
f.write(' width = 600\n')
|
|
f.write(' height = 500\n')
|
|
f.write(' self.setMinimumSize(width, height)\n')
|
|
f.write(setburl)
|
|
f.write(seturl)
|
|
f.write(' reqs = requests.get(baseurl)\n')
|
|
f.write(' sp = BeautifulSoup(reqs.text, ' + htmlp + ')\n')
|
|
f.write(' tlt = sp.title.string\n')
|
|
f.write(' view = HtmlView(self)\n')
|
|
f.write(' view.load(url)\n')
|
|
f.write(' ix = self.addTab(view, tlt)\n')
|
|
f.write(' def close_current_tab(self, i):\n')
|
|
f.write(' if self.count()<2:\n')
|
|
f.write(' return\n')
|
|
f.write(' self.removeTab(i)\n')
|
|
f.write('\n')
|
|
f.write('class HtmlView(QWebEngineView):\n')
|
|
f.write(' def __init__(self, *args, **kwargs):\n')
|
|
f.write(' QWebEngineView.__init__(self, *args, **kwargs)\n')
|
|
f.write(' self.tab = self.parent()\n')
|
|
f.write('\n')
|
|
f.write(' def createWindow(self, windowType):\n')
|
|
f.write(' if windowType == QWebEnginePage.WebBrowserTab:\n')
|
|
f.write(' webView = HtmlView(self.tab)\n')
|
|
f.write(setburltb)
|
|
f.write(' reqs = requests.get(baseurl)\n')
|
|
f.write(' sp = BeautifulSoup(reqs.text, ' + htmlp + ')\n')
|
|
f.write(' tlt = sp.title.string\n')
|
|
f.write(' ix = self.tab.addTab(webView, tlt)\n')
|
|
f.write(' self.tab.setCurrentIndex(ix)\n')
|
|
f.write(' return webView\n')
|
|
f.write(' return QWebEngineView.createWindow(self, windowType)\n')
|
|
f.write('\n')
|
|
f.write('if __name__ == "__main__":\n')
|
|
f.write(' import sys\n')
|
|
f.write(' app = QApplication(sys.argv)\n')
|
|
f.write(' main = TabWidget()\n')
|
|
f.write(' main.show()\n')
|
|
f.write(' sys.exit(app.exec_())\n')
|
|
f.close
|
|
# make the .py executable
|
|
ft = os.stat(pth + nm + ".py")
|
|
os.chmod(pth + nm + ".py", ft.st_mode |
|
|
stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
|
|
|
|
def ssbwritepvt():
|
|
"""Write the private py file that will be SSB """
|
|
nmg = txtcappname.get()
|
|
nm = "".join(nmg.split())
|
|
|
|
ur = txtcappuser.get()
|
|
pth = "/home/" + ur + "/.local/share/"
|
|
|
|
wurl = txtcappaddrs.get()
|
|
ico = txtcapppath.get()
|
|
setburl = ' baseurl = "' + wurl + '"\n'
|
|
setburltb = ' baseurl = "' + wurl + '"\n'
|
|
seturl = ' url = QUrl((baseurl))\n'
|
|
settle = ' self.setWindowTitle("' + nm + '")\n'
|
|
setico = ' self.setWindowIcon(QIcon(' + ico + '))\n'
|
|
htmlp = "'html.parser'"
|
|
f = open(pth + nm + ".py", 'x')
|
|
f.write('#!/usr/bin/env python3\n')
|
|
f.write('\n')
|
|
f.write('from PyQt5.QtCore import *\n')
|
|
f.write('from PyQt5.QtWidgets import *\n')
|
|
f.write('from PyQt5.QtGui import *\n')
|
|
f.write('from PyQt5.QtWebEngineWidgets import *\n')
|
|
f.write('from bs4 import BeautifulSoup\n')
|
|
f.write('import requests\n')
|
|
f.write('\n')
|
|
f.write('class TabWidget(QTabWidget):\n')
|
|
f.write(' """Set tup the tab and windows layout"""\n')
|
|
f.write(' def __init__(self, *args, **kwargs):\n')
|
|
f.write(' QTabWidget.__init__(self, *args, **kwargs)\n')
|
|
f.write(settle)
|
|
f.write(setico)
|
|
f.write(' self.setTabsClosable(True)\n')
|
|
f.write(' self.tabCloseRequested.connect( self.close_current_tab )\n')
|
|
f.write(' self.setDocumentMode(True)\n')
|
|
f.write(' width = 600\n')
|
|
f.write(' height = 500\n')
|
|
f.write(' self.setMinimumSize(width, height)\n')
|
|
f.write(setburl)
|
|
f.write(seturl)
|
|
f.write(' reqs = requests.get(baseurl)\n')
|
|
f.write(' sp = BeautifulSoup(reqs.text, ' + htmlp + ')\n')
|
|
f.write(' tlt = sp.title.string\n')
|
|
f.write(' view = HtmlView(self)\n')
|
|
f.write(' view.load(url)\n')
|
|
f.write(' ix = self.addTab(view, tlt)\n')
|
|
f.write(' def close_current_tab(self, i):\n')
|
|
f.write(' if self.count()<2:\n')
|
|
f.write(' return\n')
|
|
f.write(' self.removeTab(i)\n')
|
|
f.write('\n')
|
|
f.write('class HtmlView(QWebEngineView):\n')
|
|
f.write(' def __init__(self, *args, **kwargs):\n')
|
|
f.write(' QWebEngineView.__init__(self, *args, **kwargs)\n')
|
|
f.write(' self.tab = self.parent()\n')
|
|
f.write('\n')
|
|
f.write(' def createWindow(self, windowType):\n')
|
|
f.write(' if windowType == QWebEnginePage.WebBrowserTab:\n')
|
|
f.write(' webView = HtmlView(self.tab)\n')
|
|
f.write(setburltb)
|
|
f.write(' reqs = requests.get(baseurl)\n')
|
|
f.write(' sp = BeautifulSoup(reqs.text, ' + htmlp + ')\n')
|
|
f.write(' tlt = sp.title.string\n')
|
|
f.write(' ix = self.tab.addTab(webView, tlt)\n')
|
|
f.write(' self.tab.setCurrentIndex(ix)\n')
|
|
f.write(' return webView\n')
|
|
f.write(' return QWebEngineView.createWindow(self, windowType)\n')
|
|
f.write('\n')
|
|
f.write('if __name__ == "__main__":\n')
|
|
f.write(' import sys\n')
|
|
f.write(' app = QApplication(sys.argv)\n')
|
|
f.write(' main = TabWidget()\n')
|
|
f.write(' main.show()\n')
|
|
f.write(' sys.exit(app.exec_())\n')
|
|
f.close
|
|
# make the .py executable
|
|
ft = os.stat(pth + nm + ".py")
|
|
os.chmod(pth + nm + ".py", ft.st_mode |
|
|
stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
|
|
|
|
def desktopwritepub():
|
|
"""this will write the .desktop file to usr/share/application folder """
|
|
nmg = txtcappname.get()
|
|
nm = "".join(nmg.split())
|
|
wurl = txtcappaddrs.get()
|
|
ico = txtcapppath.get()
|
|
cloc = cmboc.get()
|
|
# remove extra quotes from the string
|
|
icouse = ico.lstrip("'").rstrip("'")
|
|
pth = "/usr/share/applications/"
|
|
f = open(pth + nm + ".desktop", 'x')
|
|
f.write('[Desktop Entry]\n')
|
|
f.write('Version=1.0\n')
|
|
f.write('Name=' + nm + '\n')
|
|
f.write('Comment=Kumo SSB\n')
|
|
f.write('Exec=/opt/pypep/' + nm + '.py\n')
|
|
f.write('Icon=' + icouse + '\n')
|
|
f.write('Path=/opt/pypep/\n')
|
|
f.write('Terminal=false\n')
|
|
f.write('Type=Application\n')
|
|
f.write('Categories=' + cloc + '\n')
|
|
f.close
|
|
|
|
|
|
def desktopwritepvt():
|
|
"""this will write the .desktop file to .local/share/application folder """
|
|
nmg = txtcappname.get()
|
|
nm = "".join(nmg.split())
|
|
ur = txtcappuser.get()
|
|
wurl = txtcappaddrs.get()
|
|
ico = txtcapppath.get()
|
|
cloc = cmboc.get()
|
|
# remove extra quotes from the string
|
|
icouse = ico.lstrip("'").rstrip("'")
|
|
pth = "/home/" + ur + "/.local/share/applications/"
|
|
f = open(pth + nm + ".desktop", 'x')
|
|
f.write('[Desktop Entry]\n')
|
|
f.write('Version=1.0\n')
|
|
f.write('Name=' + nm + '\n')
|
|
f.write('Comment=Kumo SSB\n')
|
|
f.write('Exec=/home/' + ur + '/.local/share/' + nm + '.py\n')
|
|
f.write('Icon=' + icouse + '\n')
|
|
f.write('Path=/home/' + ur + '/.local/share/\n')
|
|
f.write('Terminal=false\n')
|
|
f.write('Type=Application\n')
|
|
f.write('Categories=' + cloc + '\n')
|
|
f.close
|
|
|
|
|
|
def ssbewritepub():
|
|
"""Write the public py file that will be the SSB """
|
|
nmg = txtcappnameed.get()
|
|
nm = "".join(nmg.split())
|
|
pth = "/opt/pypep/"
|
|
wurl = txtcappaddrsed.get()
|
|
ico = txtcapppathed.get()
|
|
setburl = ' baseurl = "' + wurl + '"\n'
|
|
setburltb = ' baseurl = "' + wurl + '"\n'
|
|
seturl = ' url = QUrl((baseurl))\n'
|
|
settle = ' self.setWindowTitle("' + nm + '")\n'
|
|
setico = ' self.setWindowIcon(QIcon(' + ico + '))\n'
|
|
htmlp = "'html.parser'"
|
|
f = open(pth + nm + ".py", 'x')
|
|
f.write('#!/usr/bin/env python3\n')
|
|
f.write('\n')
|
|
f.write('from PyQt5.QtCore import *\n')
|
|
f.write('from PyQt5.QtWidgets import *\n')
|
|
f.write('from PyQt5.QtGui import *\n')
|
|
f.write('from PyQt5.QtWebEngineWidgets import *\n')
|
|
f.write('from bs4 import BeautifulSoup\n')
|
|
f.write('import requests\n')
|
|
f.write('\n')
|
|
f.write('class TabWidget(QTabWidget):\n')
|
|
f.write(' """Set tup the tab and windows layout"""\n')
|
|
f.write(' def __init__(self, *args, **kwargs):\n')
|
|
f.write(' QTabWidget.__init__(self, *args, **kwargs)\n')
|
|
f.write(settle)
|
|
f.write(setico)
|
|
f.write(' self.setTabsClosable(True)\n')
|
|
f.write(' self.tabCloseRequested.connect( self.close_current_tab )\n')
|
|
f.write(' self.setDocumentMode(True)\n')
|
|
f.write(' width = 600\n')
|
|
f.write(' height = 500\n')
|
|
f.write(' self.setMinimumSize(width, height)\n')
|
|
f.write(setburl)
|
|
f.write(seturl)
|
|
f.write(' reqs = requests.get(baseurl)\n')
|
|
f.write(' sp = BeautifulSoup(reqs.text, ' + htmlp + ')\n')
|
|
f.write(' tlt = sp.title.string\n')
|
|
f.write(' view = HtmlView(self)\n')
|
|
f.write(' view.load(url)\n')
|
|
f.write(' ix = self.addTab(view, tlt)\n')
|
|
f.write(' def close_current_tab(self, i):\n')
|
|
f.write(' if self.count()<2:\n')
|
|
f.write(' return\n')
|
|
f.write(' self.removeTab(i)\n')
|
|
f.write('\n')
|
|
f.write('class HtmlView(QWebEngineView):\n')
|
|
f.write(' def __init__(self, *args, **kwargs):\n')
|
|
f.write(' QWebEngineView.__init__(self, *args, **kwargs)\n')
|
|
f.write(' self.tab = self.parent()\n')
|
|
f.write('\n')
|
|
f.write(' def createWindow(self, windowType):\n')
|
|
f.write(' if windowType == QWebEnginePage.WebBrowserTab:\n')
|
|
f.write(' webView = HtmlView(self.tab)\n')
|
|
f.write(setburltb)
|
|
f.write(' reqs = requests.get(baseurl)\n')
|
|
f.write(' sp = BeautifulSoup(reqs.text, ' + htmlp + ')\n')
|
|
f.write(' tlt = sp.title.string\n')
|
|
f.write(' ix = self.tab.addTab(webView, tlt)\n')
|
|
f.write(' self.tab.setCurrentIndex(ix)\n')
|
|
f.write(' return webView\n')
|
|
f.write(' return QWebEngineView.createWindow(self, windowType)\n')
|
|
f.write('\n')
|
|
f.write('if __name__ == "__main__":\n')
|
|
f.write(' import sys\n')
|
|
f.write(' app = QApplication(sys.argv)\n')
|
|
f.write(' main = TabWidget()\n')
|
|
f.write(' main.show()\n')
|
|
f.write(' sys.exit(app.exec_())\n')
|
|
f.close
|
|
# make the .py executable
|
|
ft = os.stat(pth + nm + ".py")
|
|
os.chmod(pth + nm + ".py", ft.st_mode |
|
|
stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
|
|
|
|
def ssbewritepvt():
|
|
"""Write the private py file that will be SSB """
|
|
nmg = txtcappnameed.get()
|
|
nm = "".join(nmg.split())
|
|
|
|
ur = txtcappuser.get()
|
|
pth = "/home/" + ur + "/.local/share/"
|
|
wurl = txtcappaddrsed.get()
|
|
ico = txtcapppathed.get()
|
|
setburl = ' baseurl = "' + wurl + '"\n'
|
|
setburltb = ' baseurl = "' + wurl + '"\n'
|
|
seturl = ' url = QUrl((baseurl))\n'
|
|
settle = ' self.setWindowTitle("' + nm + '")\n'
|
|
setico = ' self.setWindowIcon(QIcon(' + ico + '))\n'
|
|
htmlp = "'html.parser'"
|
|
f = open(pth + nm + ".py", 'x')
|
|
f.write('#!/usr/bin/env python3\n')
|
|
f.write('\n')
|
|
f.write('from PyQt5.QtCore import *\n')
|
|
f.write('from PyQt5.QtWidgets import *\n')
|
|
f.write('from PyQt5.QtGui import *\n')
|
|
f.write('from PyQt5.QtWebEngineWidgets import *\n')
|
|
f.write('from bs4 import BeautifulSoup\n')
|
|
f.write('import requests\n')
|
|
f.write('\n')
|
|
f.write('class TabWidget(QTabWidget):\n')
|
|
f.write(' """Set tup the tab and windows layout"""\n')
|
|
f.write(' def __init__(self, *args, **kwargs):\n')
|
|
f.write(' QTabWidget.__init__(self, *args, **kwargs)\n')
|
|
f.write(settle)
|
|
f.write(setico)
|
|
f.write(' self.setTabsClosable(True)\n')
|
|
f.write(' self.tabCloseRequested.connect( self.close_current_tab )\n')
|
|
f.write(' self.setDocumentMode(True)\n')
|
|
f.write(' width = 600\n')
|
|
f.write(' height = 500\n')
|
|
f.write(' self.setMinimumSize(width, height)\n')
|
|
f.write(setburl)
|
|
f.write(seturl)
|
|
f.write(' reqs = requests.get(baseurl)\n')
|
|
f.write(' sp = BeautifulSoup(reqs.text, ' + htmlp + ')\n')
|
|
f.write(' tlt = sp.title.string\n')
|
|
f.write(' view = HtmlView(self)\n')
|
|
f.write(' view.load(url)\n')
|
|
f.write(' ix = self.addTab(view, tlt)\n')
|
|
f.write(' def close_current_tab(self, i):\n')
|
|
f.write(' if self.count()<2:\n')
|
|
f.write(' return\n')
|
|
f.write(' self.removeTab(i)\n')
|
|
f.write('\n')
|
|
f.write('class HtmlView(QWebEngineView):\n')
|
|
f.write(' def __init__(self, *args, **kwargs):\n')
|
|
f.write(' QWebEngineView.__init__(self, *args, **kwargs)\n')
|
|
f.write(' self.tab = self.parent()\n')
|
|
f.write('\n')
|
|
f.write(' def createWindow(self, windowType):\n')
|
|
f.write(' if windowType == QWebEnginePage.WebBrowserTab:\n')
|
|
f.write(' webView = HtmlView(self.tab)\n')
|
|
f.write(setburltb)
|
|
f.write(' reqs = requests.get(baseurl)\n')
|
|
f.write(' sp = BeautifulSoup(reqs.text, ' + htmlp + ')\n')
|
|
f.write(' tlt = sp.title.string\n')
|
|
f.write(' ix = self.tab.addTab(webView, tlt)\n')
|
|
f.write(' self.tab.setCurrentIndex(ix)\n')
|
|
f.write(' return webView\n')
|
|
f.write(' return QWebEngineView.createWindow(self, windowType)\n')
|
|
f.write('\n')
|
|
f.write('if __name__ == "__main__":\n')
|
|
f.write(' import sys\n')
|
|
f.write(' app = QApplication(sys.argv)\n')
|
|
f.write(' main = TabWidget()\n')
|
|
f.write(' main.show()\n')
|
|
f.write(' sys.exit(app.exec_())\n')
|
|
f.close
|
|
# make the .py executable
|
|
ft = os.stat(pth + nm + ".py")
|
|
os.chmod(pth + nm + ".py", ft.st_mode |
|
|
stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
|
|
|
|
def desktopewritepub():
|
|
"""this will write the .desktop file to usr/share/application folder """
|
|
nmg = txtcappnameed.get()
|
|
nm = "".join(nmg.split())
|
|
wurl = txtcappaddrsed.get()
|
|
ico = txtcapppathed.get()
|
|
cloc = txtcmenulocaled.get()
|
|
# remove extra quotes from the string
|
|
icouse = ico.lstrip("'").rstrip("'")
|
|
pth = "/usr/share/applications/"
|
|
f = open(pth + nm + ".desktop", 'x')
|
|
f.write('[Desktop Entry]\n')
|
|
f.write('Version=1.0\n')
|
|
f.write('Name=' + nm + '\n')
|
|
f.write('Comment=Kumo SSB\n')
|
|
f.write('Exec=/opt/pypep/' + nm + '.py\n')
|
|
f.write('Icon=' + icouse + '\n')
|
|
f.write('Path=/opt/pypep/\n')
|
|
f.write('Terminal=false\n')
|
|
f.write('Type=Application\n')
|
|
f.write('Categories=' + cloc + '\n')
|
|
f.close
|
|
|
|
|
|
def desktopewritepvt():
|
|
"""this will write the .desktop file to usr/share/application folder """
|
|
nmg = txtcappnameed.get()
|
|
nm = "".join(nmg.split())
|
|
ur = txtcappuser.get()
|
|
wurl = txtcappaddrsed.get()
|
|
ico = txtcapppathed.get()
|
|
cloc = txtcmenulocaled.get()
|
|
# remove extra quotes from the string
|
|
icouse = ico.lstrip("'").rstrip("'")
|
|
pth = "/home/" + ur + "/.local/share/applications/"
|
|
f = open(pth + nm + ".desktop", 'x')
|
|
f.write('[Desktop Entry]\n')
|
|
f.write('Version=1.0\n')
|
|
f.write('Name=' + nm + '\n')
|
|
f.write('Comment=Kumo SSB\n')
|
|
f.write('Exec=/home/' + ur + '/.local/share/' + nm + '.py\n')
|
|
f.write('Icon=' + icouse + '\n')
|
|
f.write('Path=/home/' + ur + '/.local/share/\n')
|
|
f.write('Terminal=false\n')
|
|
f.write('Type=Application\n')
|
|
f.write('Categories=' + cloc + '\n')
|
|
f.close
|
|
|
|
|
|
def opf():
|
|
"""Browse system for icon for new"""
|
|
file = filedialog.askopenfilename(
|
|
title="Select an icon.",
|
|
initialdir="/usr/share/pixmaps/",
|
|
filetypes=[
|
|
("png file",
|
|
"*.png"),
|
|
("jpg file",
|
|
"*.jpg"),
|
|
("icon file",
|
|
"*.ico")]
|
|
)
|
|
pth = f"'{file}'"
|
|
txtcapppath.delete(0, END)
|
|
txtcapppath.insert(0, pth)
|
|
|
|
|
|
def opfedit():
|
|
"""Browse system for icon for new"""
|
|
file = filedialog.askopenfilename(
|
|
initialdir="/usr/share/pixmaps/",
|
|
filetypes=[
|
|
("png file",
|
|
"*.png"),
|
|
("jpg file",
|
|
"*.jpg"),
|
|
("icon file",
|
|
"*.ico")])
|
|
pth = f"'{file}'"
|
|
txtcapppathed.delete(0, END)
|
|
txtcapppathed.insert(0, pth)
|
|
|
|
|
|
def favi():
|
|
"""Try to get the Website Favicon"""
|
|
nm = txtcappname.get()
|
|
wurl = txtcappaddrs.get()
|
|
pth = "'/usr/share/pixmaps/" + nm + ".png'"
|
|
icons = favicon.get(wurl)
|
|
icon = icons[0]
|
|
response = requests.get(icon.url, stream=True)
|
|
with open("/usr/share/pixmaps/" + nm + '.{}'.format(icon.format), 'wb') as image:
|
|
for chunk in response.iter_content(1024):
|
|
image.write(chunk)
|
|
txtcapppath.delete(0, END)
|
|
txtcapppath.insert(0, pth)
|
|
|
|
|
|
def closeme():
|
|
"""Close the Application"""
|
|
pwin.destroy()
|
|
|
|
|
|
def pubset():
|
|
"""If Public is set decide where to put the webapp"""
|
|
if cbpub_v.get() == 1:
|
|
ssbwritepub()
|
|
desktopwritepub()
|
|
else:
|
|
ssbwritepvt()
|
|
desktopwritepvt()
|
|
|
|
|
|
def installapp():
|
|
"""turn things on and off if the app is to be installed"""
|
|
if cbinst_v.get() == 1:
|
|
txtcapppath.configure(state="normal")
|
|
btnlkf1.configure(state="normal")
|
|
btnlkfavi1.configure(state="normal")
|
|
cbpub.configure(state="normal")
|
|
cmboc.configure(state="normal")
|
|
else:
|
|
txtcapppath.delete(0, END)
|
|
txtcapppath.configure(state="disabled")
|
|
btnlkf1.configure(state="disabled")
|
|
btnlkfavi1.configure(state="disabled")
|
|
cbpub.configure(state="disabled")
|
|
cmboc.configure(state="disabled")
|
|
|
|
|
|
def biatg():
|
|
"""Bring it all together for the new records"""
|
|
mkenew()
|
|
pubset()
|
|
closeme()
|
|
print('done')
|
|
|
|
|
|
def delapp():
|
|
"""what should happen if the app is to be deleted"""
|
|
if cbdel_v.get() == 1:
|
|
getinfo()
|
|
txtcappnameed.configure(state="disabled")
|
|
txtcappaddrsed.configure(state="disabled")
|
|
txtcapppathed.configure(state="disabled")
|
|
txtcmenulocaled.configure(state="disabled")
|
|
btngo.configure(state="disabled")
|
|
btnlkf2.configure(state="disabled")
|
|
cmbo.configure(state="disabled")
|
|
else:
|
|
getinfo()
|
|
txtcappnameed.configure(state="normal")
|
|
txtcappaddrsed.configure(state="normal")
|
|
txtcapppathed.configure(state="normal")
|
|
txtcmenulocaled.configure(state="normal")
|
|
btngo.configure(state="normal")
|
|
btnlkf2.configure(state="normal")
|
|
cmbo.configure(state="normal")
|
|
|
|
|
|
def delprofilecache():
|
|
"""This will delete th profile cache of the ssb"""
|
|
appn = txtcappnameed.get()
|
|
nm = "".join(appn.split())
|
|
usr = txtcappuser.get()
|
|
# set the base path for the home folder
|
|
spath = "/home/" + usr + "/.local/share/"
|
|
chkfolder = os.path.isdir(spath + nm + ".py/")
|
|
if not chkfolder:
|
|
print("No Folder to Delete")
|
|
else:
|
|
# remove the qtwebview profile for the ssb
|
|
shutil.rmtree(spath + nm + ".py/")
|
|
print("Removed Cache")
|
|
|
|
|
|
def delappproc():
|
|
"""The is the full delete method for both private and public"""
|
|
# get the input and combo values
|
|
menuapp = cmbo.get()
|
|
usr = txtcappuser.get()
|
|
appn = txtcappnameed.get()
|
|
# query data
|
|
sqdval = """ DELETE FROM kumoapp WHERE appname=? AND usrname=? """
|
|
pbval = """ SELECT Count(*) from kumoapp WHERE appname=? AND usrname=? AND public = 'yes' """
|
|
# run the pval query nd fect the result
|
|
pcur.execute(pbval, (menuapp, usr))
|
|
pubresult = pcur.fetchone()
|
|
# These things will delete stuff that is publicly set
|
|
nm = "".join(appn.split())
|
|
# set the base path for the opt folder
|
|
fldpy = "/opt/pypep/"
|
|
# set the base path for the applications folder
|
|
fldapp = "/usr/share/applications/"
|
|
# set the base path for the home folder
|
|
spath = "/home/" + usr + "/.local/share/"
|
|
# if the delete app option is actiive do these things.
|
|
if int(pubresult[0]) > 0:
|
|
if os.path.isfile(fldpy + nm + ".py"):
|
|
# if the python file exists delete it if not pass
|
|
os.remove(fldpy + nm + ".py")
|
|
print("Deleted Public Python file")
|
|
else:
|
|
print("Nothing to Delete")
|
|
if os.path.isfile(fldapp + nm + ".desktop"):
|
|
# If the .desktop file exists delete it if not pass
|
|
os.remove(fldapp + nm + ".desktop")
|
|
print("Deleted Public Shortcut")
|
|
# Delete the cache profile
|
|
delprofilecache()
|
|
else:
|
|
print("Nothing to delete")
|
|
|
|
# Delete the record from the database
|
|
pcur.execute(sqdval, (menuapp, usr))
|
|
# commit the changes to the database
|
|
dcon.commit()
|
|
print("Public Deleted")
|
|
else:
|
|
# These will delete things that are private
|
|
if os.path.isfile(spath + nm + ".py"):
|
|
os.remove(spath + nm + ".py")
|
|
print("Deleted private Python file")
|
|
if os.path.isfile(spath + "applications/" + nm + ".desktop"):
|
|
os.remove(spath + "applications/" + nm + ".desktop")
|
|
print("Delete Private desktop file")
|
|
# Delete the cache profile
|
|
delprofilecache()
|
|
|
|
# Delete the record from the database
|
|
pcur.execute(sqdval, (menuapp, usr))
|
|
# commit the changes to the database
|
|
dcon.commit()
|
|
print("Private Deleted")
|
|
|
|
|
|
def saveupdate():
|
|
""" save the changes to the updated application or delete it """
|
|
if cbdel_v.get() == 1:
|
|
# Call the Delete Function
|
|
delappproc()
|
|
# kill the app
|
|
closeme()
|
|
else:
|
|
# Callt the Update Process
|
|
updateproc()
|
|
# kill the app
|
|
closeme()
|
|
|
|
|
|
def pastetxt():
|
|
"""Right click menu for Paste text to stuff"""
|
|
txtcappaddrs.event_generate(("<<Paste>>"))
|
|
|
|
|
|
def cmenu(event):
|
|
"""when to open the rightclick menu"""
|
|
try:
|
|
rcmen.tk_popup(event.x_root, event.y_root)
|
|
finally:
|
|
rcmen.grab_release()
|
|
|
|
|
|
def getinfo():
|
|
"""This will get enfor from the db and the forms as needed"""
|
|
# The query variables
|
|
menuapp = cmbo.get()
|
|
usr = txtcappuser.get()
|
|
# get data
|
|
nval = """ SELECT appname FROM kumoapp WHERE appname=? AND usrname=? """
|
|
lval = """ SELECT lnk FROM kumoapp WHERE appname = ? AND usrname=? """
|
|
pval = """ SELECT iconpath FROM kumoapp WHERE appname = ? AND usrname=? """
|
|
mval = """ SELECT menu FROM kumoapp WHERE appname = ? AND usrname=? """
|
|
# run the queries
|
|
pcur.execute(nval, (menuapp, usr))
|
|
nput = pcur.fetchone()
|
|
pcur.execute(lval, (menuapp, usr))
|
|
lput = pcur.fetchone()
|
|
pcur.execute(pval, (menuapp, usr))
|
|
pput = pcur.fetchone()
|
|
pcur.execute(mval, (menuapp, usr))
|
|
mput = pcur.fetchone()
|
|
# set the textbox vaues.
|
|
txtcappnameed.delete(0, END)
|
|
txtcappnameed.insert(0, nput)
|
|
txtcappaddrsed.delete(0, END)
|
|
txtcappaddrsed.insert(0, lput)
|
|
txtcapppathed.delete(0, END)
|
|
txtcapppathed.insert(0, pput)
|
|
txtcmenulocaled.delete(0, END)
|
|
txtcmenulocaled.insert(0, mput)
|
|
|
|
|
|
def getlaunch():
|
|
"""this will get info to get ready for launching the applications"""
|
|
# The Query Variables
|
|
lnchapp = cmboappl.get()
|
|
usr = txtcappuser.get()
|
|
# get the date to be used
|
|
lnval = """ SELECT lnk FROM kumoapp WHERE appname = ? AND usrname=? """
|
|
pnval = """ SELECT iconpath FROM kumoapp WHERE appname = ? AND usrname=? """
|
|
# run the queries
|
|
pcur.execute(lnval, (lnchapp, usr))
|
|
lnput = pcur.fetchone()
|
|
pcur.execute(pnval, (lnchapp, usr))
|
|
pnput = pcur.fetchone()
|
|
# turn on stuff
|
|
txtcappaddrsl.configure(state="normal")
|
|
txtcapppathl.configure(state="normal")
|
|
# set the textbox values
|
|
txtcappaddrsl.delete(0, END)
|
|
txtcappaddrsl.insert(0, lnput)
|
|
txtcapppathl.delete(0, END)
|
|
txtcapppathl.insert(0, pnput)
|
|
# turn off stuff
|
|
txtcappaddrsl.configure(state="disabled")
|
|
txtcapppathl.configure(state="disabled")
|
|
|
|
|
|
def launchapp():
|
|
"""This function will run the slected applition selected"""
|
|
# set the variables
|
|
appn = cmboappl.get()
|
|
usr = usr = txtcappuser.get()
|
|
# get the data
|
|
pbval = """ SELECT Count(*) from kumoapp WHERE appname=? AND usrname=? AND public = 'yes' """
|
|
# run the pval query and fetch the result
|
|
pcur.execute(pbval, (appn, usr))
|
|
pubresult = pcur.fetchone()
|
|
# set the base path for the opt folder
|
|
fldpy = "/opt/pypep/"
|
|
# set the base path for the home folder
|
|
spath = "/home/" + usr + "/.local/share/"
|
|
if int(pubresult[0]) > 0:
|
|
# demote the user so it will launch the ssb
|
|
os.setuid(1000)
|
|
os.system('python3 ' + fldpy + appn + ".py")
|
|
print("Launch the Public App")
|
|
else:
|
|
print("Launch the private App")
|
|
|
|
|
|
def updateproc():
|
|
"""This is the complete update process to update the db and refresh the filesystems"""
|
|
# get the input and combo values
|
|
menuapp = cmbo.get()
|
|
usr = txtcappuser.get()
|
|
appn = txtcappnameed.get()
|
|
alnk = txtcappaddrsed.get()
|
|
apth = txtcapppathed.get()
|
|
mloc = txtcmenulocaled.get()
|
|
|
|
# query data
|
|
sqdval = """ UPDATE kumoapp SET appname=?, lnk=?, iconpath=?, menu=? WHERE appname=? AND usrname=? """
|
|
pbval = """ SELECT Count(*) from kumoapp WHERE appname=? AND usrname=? AND public = 'yes' """
|
|
# run the pval query and fetch the result
|
|
pcur.execute(pbval, (menuapp, usr))
|
|
pubresult = pcur.fetchone()
|
|
# set the app name
|
|
nm = "".join(appn.split())
|
|
# set the base path for the opt folder
|
|
fldpy = "/opt/pypep/"
|
|
# set the base path for the applications folder
|
|
fldapp = "/usr/share/applications/"
|
|
# set the base path for the home folder
|
|
spath = "/home/" + usr + "/.local/share/"
|
|
if int(pubresult[0]) > 0:
|
|
if os.path.isfile(fldpy + nm + ".py"):
|
|
# if the python file exists delete it if not pass
|
|
os.remove(fldpy + nm + ".py")
|
|
print("Deleted Public Python file")
|
|
else:
|
|
print("Nothing to Do")
|
|
if os.path.isfile(fldapp + nm + ".desktop"):
|
|
# If the .desktop file exists delete it if not pass
|
|
os.remove(fldapp + nm + ".desktop")
|
|
print("Deleted Public Shortcut")
|
|
pcur.execute(sqdval, (appn, alnk, apth, mloc, menuapp, usr))
|
|
# commit the changes to the database
|
|
dcon.commit()
|
|
getinfo()
|
|
ssbewritepub()
|
|
desktopewritepub()
|
|
else:
|
|
print("Nothing to do")
|
|
print("Public Update ")
|
|
else:
|
|
# These will delete things that are private
|
|
if os.path.isfile(spath + nm + ".py"):
|
|
os.remove(spath + nm + ".py")
|
|
print("Deleted private Python file")
|
|
if os.path.isfile(spath + "applications/" + nm + ".desktop"):
|
|
os.remove(spath + "applications/" + nm + ".desktop")
|
|
print("Delete private desktop file")
|
|
# Delete the cache profile
|
|
delprofilecache()
|
|
# Update the record from the database
|
|
pcur.execute(sqdval, (appn, alnk, apth, mloc, menuapp, usr))
|
|
# commit the changes to the database
|
|
dcon.commit()
|
|
getinfo()
|
|
desktopewritepvt()
|
|
ssbewritepvt()
|
|
print("Private Updated")
|
|
|
|
|
|
####
|
|
# make the notebook stuff
|
|
####
|
|
pnb = ttk.Notebook(pwin, bootstyle="danger")
|
|
pnb.pack(pady=10, expand=True)
|
|
fnb1 = ttk.Frame(pnb, width=450, height=400)
|
|
fnb2 = ttk.Frame(pnb, width=450, height=400)
|
|
fnb3 = ttk.Frame(pnb, width=450, height=400)
|
|
fnb1.pack(fill='both', expand=True)
|
|
fnb2.pack(fill='both', expand=True)
|
|
fnb3.pack(fill='both', expand=True)
|
|
pnb.add(fnb1, text='Create')
|
|
pnb.add(fnb2, text='Manage')
|
|
pnb.add(fnb3, text='Apps')
|
|
|
|
# create the menu bar
|
|
rcmen = tk.Menu(fnb1, tearoff=0)
|
|
rcmen.add_command(label="Paste", command=pastetxt)
|
|
|
|
#####
|
|
# Text Boxes and Labels on the Create tab
|
|
#####
|
|
gusr = tk.StringVar()
|
|
gusr.set(os.getlogin())
|
|
lblcappuser = ttk.Label(fnb1, text="Logged in User:")
|
|
lblcappuser.place(x=330, y=25)
|
|
txtcappuser = ttk.Entry(fnb1, bootstyle="danger", width=10, text=gusr)
|
|
txtcappuser.place(x=330, y=50)
|
|
|
|
lblcappname = ttk.Label(fnb1, text="Enter the name of App:")
|
|
lblcappname.place(x=10, y=25)
|
|
txtcappname = ttk.Entry(fnb1, bootstyle="danger", width=20,)
|
|
txtcappname.place(x=10, y=50)
|
|
|
|
lblcappaddrs = ttk.Label(
|
|
fnb1, text="Enter URL for App: for example - https://www.youraddress.com ")
|
|
lblcappaddrs.place(x=10, y=100)
|
|
txtcappaddrs = ttk.Entry(fnb1, bootstyle="danger", width=45,)
|
|
txtcappaddrs.place(x=10, y=125)
|
|
|
|
lblcapppath = ttk.Label(fnb1, text="Icon Location:")
|
|
lblcapppath.place(x=10, y=195)
|
|
txtcapppath = ttk.Entry(fnb1, bootstyle="danger", width=25, state='disabled')
|
|
txtcapppath.place(x=10, y=220)
|
|
|
|
cbinst_v = tk.IntVar()
|
|
cbinst = ttk.Checkbutton(
|
|
fnb1,
|
|
text="Install App - enable this if you want the app on your Menu",
|
|
bootstyle="danger-round-toggle",
|
|
variable=cbinst_v,
|
|
command=installapp)
|
|
cbinst.place(x=10, y=170)
|
|
|
|
cbpub_v = tk.IntVar()
|
|
cbpub = ttk.Checkbutton(
|
|
fnb1,
|
|
text="Make this App Available to All Users",
|
|
bootstyle="danger-round-toggle",
|
|
variable=cbpub_v,
|
|
state='disabled')
|
|
cbpub.place(x=10, y=320)
|
|
|
|
plc = tk.StringVar()
|
|
entries = (
|
|
"AudioVideo",
|
|
"Development",
|
|
"Graphics",
|
|
"Network",
|
|
"Office",
|
|
"Settings",
|
|
"System",
|
|
"Utility")
|
|
lblcmboc = ttk.Label(fnb1, text="Where in the menu? :")
|
|
lblcmboc.place(x=10, y=255)
|
|
|
|
cmboc = ttk.Combobox(
|
|
fnb1,
|
|
bootstyle="danger",
|
|
value=entries,
|
|
textvariable=plc,
|
|
state='disabled')
|
|
cmboc.place(x=10, y=280)
|
|
|
|
btnsv = ttk.Button(
|
|
fnb1,
|
|
text="Install",
|
|
cursor="hand2",
|
|
bootstyle="light-outline",
|
|
width=5,
|
|
command=biatg)
|
|
btnsv.place(x=290, y=310)
|
|
btnex = ttk.Button(
|
|
fnb1,
|
|
text="Close",
|
|
cursor="hand2",
|
|
bootstyle="light-outline",
|
|
width=5,
|
|
command=closeme)
|
|
btnex.place(x=370, y=310)
|
|
|
|
btnlkf1 = ttk.Button(
|
|
fnb1,
|
|
text="...",
|
|
cursor="hand2",
|
|
bootstyle="light-outline",
|
|
width=2,
|
|
command=opf,
|
|
state='disabled')
|
|
btnlkf1.place(x=230, y=220)
|
|
btnlkfavi1 = ttk.Button(
|
|
fnb1,
|
|
text="Favicon",
|
|
cursor="hand2",
|
|
bootstyle="light-outline",
|
|
width=7,
|
|
command=favi,
|
|
state='disabled')
|
|
btnlkfavi1.place(x=300, y=220)
|
|
|
|
|
|
#####
|
|
# Inteface on the manage tab
|
|
#####
|
|
lblcmbo = ttk.Label(fnb2, text="Select the App to Manage:")
|
|
lblcmbo.place(x=10, y=30)
|
|
cmbo = ttk.Combobox(fnb2, bootstyle="danger")
|
|
cmbo.place(x=10, y=50)
|
|
cmbo['values'] = (inptcm())
|
|
|
|
|
|
lblcappnameed = ttk.Label(fnb2, text="Edit App Name:")
|
|
lblcappnameed.place(x=10, y=90)
|
|
txtcappnameed = ttk.Entry(fnb2, bootstyle="danger", width=20,)
|
|
txtcappnameed.place(x=10, y=110)
|
|
|
|
lblcappaddrsed = ttk.Label(fnb2, text="Edit App URL:")
|
|
lblcappaddrsed.place(x=10, y=150)
|
|
txtcappaddrsed = ttk.Entry(fnb2, bootstyle="danger", width=45)
|
|
txtcappaddrsed.place(x=10, y=170)
|
|
|
|
lblcapppathed = ttk.Label(fnb2, text="Icon Location:")
|
|
lblcapppathed.place(x=10, y=210)
|
|
txtcapppathed = ttk.Entry(fnb2, bootstyle="danger", width=30)
|
|
txtcapppathed.place(x=10, y=230)
|
|
|
|
lblcmenulocaled = ttk.Label(fnb2, text="Menu Location:")
|
|
lblcmenulocaled.place(x=10, y=275)
|
|
txtcmenulocaled = ttk.Entry(fnb2, bootstyle="danger", width=25)
|
|
txtcmenulocaled.place(x=10, y=300)
|
|
|
|
|
|
btnsved = ttk.Button(
|
|
fnb2,
|
|
text="Save",
|
|
cursor="hand2",
|
|
bootstyle="light-outline",
|
|
width=6,
|
|
command=saveupdate)
|
|
btnsved.place(x=270, y=350)
|
|
|
|
btngo = ttk.Button(
|
|
fnb2,
|
|
text="Go",
|
|
cursor="hand2",
|
|
bootstyle="light-outline",
|
|
width=3,
|
|
command=getinfo)
|
|
btngo.place(x=220, y=50)
|
|
|
|
btnexed = ttk.Button(
|
|
fnb2,
|
|
text="Close",
|
|
cursor="hand2",
|
|
bootstyle="light-outline",
|
|
width=6,
|
|
command=closeme)
|
|
btnexed.place(x=360, y=350)
|
|
|
|
btnlkf2 = ttk.Button(
|
|
fnb2,
|
|
text="...",
|
|
cursor="hand2",
|
|
bootstyle="light-outline",
|
|
width=2,
|
|
command=opfedit)
|
|
btnlkf2.place(x=270, y=230)
|
|
|
|
cbdel_v = tk.IntVar()
|
|
cbdel = ttk.Checkbutton(
|
|
fnb2,
|
|
text="Delete App",
|
|
bootstyle="danger-round-toggle",
|
|
variable=cbdel_v,
|
|
command=delapp)
|
|
cbdel.place(x=280, y=60)
|
|
|
|
|
|
####
|
|
# App Launcher tab.
|
|
####
|
|
|
|
lblcmboappl = ttk.Label(fnb3, text="Select App:")
|
|
lblcmboappl.place(x=10, y=30)
|
|
|
|
cmboappl = ttk.Combobox(fnb3, bootstyle="danger")
|
|
cmboappl.place(x=10, y=50)
|
|
cmboappl['values'] = (inptcm())
|
|
|
|
|
|
lblcappaddrsl = ttk.Label(fnb3, text="URL:")
|
|
lblcappaddrsl.place(x=10, y=90)
|
|
txtcappaddrsl = ttk.Entry(fnb3, bootstyle="danger", width=45)
|
|
txtcappaddrsl.place(x=10, y=110)
|
|
|
|
lblcapppathl = ttk.Label(fnb3, text="Icon Location:")
|
|
lblcapppathl.place(x=10, y=150)
|
|
txtcapppathl = ttk.Entry(fnb3, bootstyle="danger", width=25)
|
|
txtcapppathl.place(x=10, y=170)
|
|
|
|
lblapplmsg = ttk.Label(
|
|
fnb3,
|
|
wraplength=400,
|
|
text="Select the App you want to launch. This is an easy way to run"
|
|
" your application without installing a SSB App. After you have"
|
|
" selected the app you want to launch click the Run button")
|
|
lblapplmsg.place(x=10, y=220)
|
|
|
|
btnlnch = ttk.Button(
|
|
fnb3,
|
|
text="Run",
|
|
cursor="hand2",
|
|
bootstyle="light-outline",
|
|
width=5,
|
|
command=launchapp)
|
|
btnlnch.place(x=290, y=310)
|
|
|
|
btnexl = ttk.Button(
|
|
fnb3,
|
|
text="Close",
|
|
cursor="hand2",
|
|
bootstyle="light-outline",
|
|
width=5,
|
|
command=closeme)
|
|
btnexl.place(x=370, y=310)
|
|
|
|
btngolnch = ttk.Button(
|
|
fnb3,
|
|
text="Go",
|
|
cursor="hand2",
|
|
bootstyle="light-outline",
|
|
width=3,
|
|
command=getlaunch)
|
|
btngolnch.place(x=220, y=50)
|
|
|
|
|
|
# get the context menu
|
|
pwin.bind("<Button-3>", cmenu)
|
|
dben()
|
|
pwin.mainloop()
|