#!/usr/bin/python3
import sys
import os
from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QPushButton,QVBoxLayout,QLineEdit,QHBoxLayout,QComboBox,QCheckBox,QTableWidget,\
QHeaderView,QTableWidgetSelectionRange
from PyQt5 import QtGui
from PyQt5.QtCore import Qt,pyqtSignal,QObject
from appconfig.appConfigStack import appConfigStack as confStack
import subprocess
import gettext
_ = gettext.gettext
APT_SRC_DIR="/etc/apt/sources.list.d"
class QLabelDescription(QWidget):
click_on=pyqtSignal(str)
def __init__(self,label="",description="",parent=None):
super (QLabelDescription,self).__init__(parent)
widget=QWidget()
HBox=QHBoxLayout()
self.label=QLabel()
self.labelText=label
self.label.setText('{}'.format(label))
self.label.setStyleSheet("border:0px;margin:0px;")
HBox.addWidget(self.label,1)
self.btn_edit=QPushButton()
self.btn_edit.setToolTip(_("Edit {} file".format(label)))
icn=QtGui.QIcon().fromTheme('document-edit')
self.btn_edit.setIcon(icn)
self.btn_edit.clicked.connect(self.editRepo)
self.btn_edit.hide()
HBox.addWidget(self.btn_edit)
widget.setLayout(HBox)
self.description=QLabel()
self.description.setStyleSheet("border:3px solid silver;border-top:0px;border-right:0px;border-left:0px;margin-top:0px;")
self.descriptionText=description
self.description.setText('{}'.format(description))
QBox=QVBoxLayout()
QBox.addWidget(widget,1,Qt.AlignBottom)
QBox.addWidget(self.description,1,Qt.AlignTop)
self.setLayout(QBox)
self.show()
def setText(self,label,description=""):
self.labelText=label
self.label.setText('{}'.format(label))
self.descriptionText=description
self.description.setText('{}'.format(description))
def text(self):
return([self.labelText,self.descriptionText])
def showEdit(self):
self.btn_edit.show()
def stateEdit(self,state):
self.btn_edit.setEnabled(state)
if state:
self.btn_edit.setToolTip(_("Edit {} file".format(self.labelText)))
else:
self.btn_edit.setToolTip(_("Enable {} and apply to edit".format(self.labelText)))
def editRepo(self):
self.click_on.emit(self.labelText)
class customRepos(confStack):
def __init_stack__(self):
self.dbg=False
self._debug("confDefault Load")
self.menu_description=(_("Manage custom repositories"))
self.description=(_("Custom repositories"))
self.icon=('menu_new')
self.tooltip=(_("From here you can manage your custom repositories"))
self.index=2
self.enabled=True
self.defaultRepos={}
self.level='user'
self.changed=[]
#def __init__
def _load_screen(self):
box=QVBoxLayout()
info=QWidget()
infoBox=QHBoxLayout()
lbl_txt=QLabel(_("Manage extra repositories"))
lbl_txt.setAlignment(Qt.AlignTop)
infoBox.addWidget(lbl_txt,1)
icn_add=QtGui.QIcon().fromTheme('document-new')
btn_add=QPushButton()
btn_add.clicked.connect(self._addRepo)
btn_add.setIcon(icn_add)
btn_add.setToolTip(_("Add new repository"))
infoBox.addWidget(btn_add,0)
info.setLayout(infoBox)
box.addWidget(info,0)
self.table=QTableWidget(1,2)
Hheader=self.table.horizontalHeader()
Vheader=self.table.verticalHeader()
Hheader.setSectionResizeMode(0,QHeaderView.Stretch)
Vheader.setSectionResizeMode(QHeaderView.ResizeToContents)
self.table.setShowGrid(False)
self.table.setSelectionBehavior(QTableWidget.SelectRows)
self.table.setSelectionMode(QTableWidget.NoSelection)
self.table.setEditTriggers(QTableWidget.NoEditTriggers)
self.table.horizontalHeader().hide()
self.table.verticalHeader().hide()
box.addWidget(self.table)
self.setLayout(box)
self.updateScreen()
#def _load_screen
def updateScreen(self):
self.table.clearContents()
self.changed=[]
while self.table.rowCount():
self.table.removeRow(0)
config=self.getConfig()
repos=self.appConfig.n4dQuery("RepoManager","list_sources")
if (type(repos)==type("")):
#It's a string, something went wrong. Perhaps a llx16 server?
if isinstance(repos,str):
#Server is a llx16 so switch to localhost
self._debug("LLX16 server detected. Switch to localhost")
self.appConfig.n4d.server='localhost'
self.appConfig.n4d.n4dClient=None
repos=self.appConfig.n4dQuery("RepoManager","list_sources")
self.defaultRepos=repos.get('data',{}).copy()
states={}
row=0
orderedKeys=sorted(self.defaultRepos,key=str.casefold)
for repo in orderedKeys:
data=self.defaultRepos[repo]
self.table.insertRow(row)
state=data.get('enabled','false').lower()
if state=='true':
state=True
else:
state=False
description=data.get('desc','')
lbl=QLabelDescription(repo,description)
locked=data.get('protected','false')
locked=str(locked).lower()
lbl.click_on.connect(self.editRepo)
if locked=='false':
lbl.showEdit()
if not state:
lbl.stateEdit(False)
self.table.setCellWidget(row,0,lbl)
chk=QCheckBox()
chk.setStyleSheet("margin-left:50%;margin-right:50%")
chk.stateChanged.connect(lambda x:self.setChanged(chk))
chk.stateChanged.connect(self.changeState)
self.table.setCellWidget(row,1,chk)
chk.setChecked(state)
row+=1
#def _update_screen
def editRepo(self,repo,*args):
sfile=repo.replace(' ','_')
self._debug("Editing {}/{}.list".format(APT_SRC_DIR,sfile))
if not sfile.endswith(".list"):
sfile="{}.list".format(sfile)
if os.path.isfile(os.path.join(APT_SRC_DIR,sfile)) or os.path.isfile(os.path.join(APT_SRC_DIR,sfile.lower())):
if os.path.isfile(os.path.join(APT_SRC_DIR,sfile.lower())):
sfile=sfile.lower()
edit=True
try:
display=os.environ['DISPLAY']
subprocess.run(["xhost","+"])
subprocess.run(["pkexec","scite","%s/%s"%(APT_SRC_DIR,sfile)],check=True)
subprocess.run(["pkexec","scite",os.path.join(APT_SRC_DIR,sfile)],check=True)
subprocess.run(["xhost","-"])
except Exception as e:
self._debug("_edit_source_file error: %s"%e)
edit=False
if edit:
newrepos=[]
wrkfile=os.path.join(APT_SRC_DIR,sfile)
if not os.path.isfile(wrkfile):
wrkfile=wrkfile.lower()
try:
with open(wrkfile,'r') as f:
for line in f:
newrepos.append(line.strip())
except Exception as e:
self._debug("_edit_source_file failed: {}".format(e))
if sorted(self.defaultRepos[repo]['repos'])!=sorted(newrepos):
self.defaultRepos[repo]['repos']=newrepos
self.appConfig.n4dQuery("RepoManager","write_repo_json",{repo:self.defaultRepos[repo]})
self._updateRepos()
else:
self._debug("File {} not found".format(os.path.join(APT_SRC_DIR,sfile)))
#def _edit_source_file
def changeState(self):
row=self.table.currentRow()
repoWidget=self.table.cellWidget(row,0)
stateWidget=self.table.cellWidget(row,1)
if repoWidget==None:
self._debug("Item not found at {},0".format(row))
return
repo=repoWidget.text()[0]
state=False
if stateWidget.isChecked():
state=True
textState=str(state).lower()
self.defaultRepos[repo]['enabled']="{}".format(textState)
if repo not in self.changed:
self.changed.append(repo)
#def changeState(self)
def _addRepo(self):
self.stack.gotoStack(idx=4,parms="")
#def _addRepo
def writeConfig(self):
ret=True
for repo in self.changed:
self._debug("Updating {}".format(repo))
self._debug("Updating %s"%self.defaultRepos[repo])
ret=self.appConfig.n4dQuery("RepoManager","write_repo_json",{repo:self.defaultRepos[repo]})
if ret:
ret=self.appConfig.n4dQuery("RepoManager","write_repo",{repo:self.defaultRepos[repo]})
if ret==False:
self.showMsg(_("Couldn't write repo")+" {}".format(repo),'error')
else:
self.showMsg(_("Couldn't write info for")+" {}".format(repo),'error')
if ret==True:
self._updateRepos()
self.updateScreen()
#def writeConfig
def _updateRepos(self):
cursor=QtGui.QCursor(Qt.WaitCursor)
self.setCursor(cursor)
self._debug("Updating repos")
ret=self.appConfig.n4dQuery("RepoManager","update_repos")
ret=ret.get('data','')
errList=[]
for line in ret.split("\n"):
if line.startswith("E: ") or line.startswith("W:"):
for name,data in self.defaultRepos.items():
for repoLine in data.get('repos',[]):
repoItems=repoLine.split(" ")
if repoItems:
if repoItems[0] in line:
err=" *{}".format(name)
if err not in errList:
errList.append(err)
ret=("\n").join(errList)
if ret:
#self.showMsg(_("Repositories updated succesfully"))
self._debug("Error updating: {}".format(ret))
ret=_("Failed to update: ")+"\n"+"{}".format(ret)
self.showMsg("{}".format(ret),'RepoMan')
self.refresh=True
self.changes=False
else:
self.showMsg(_("Repositories updated succesfully"))
cursor=QtGui.QCursor(Qt.PointingHandCursor)
self.setCursor(cursor)
#def _updateRepos