408 lines
15 KiB
Python
408 lines
15 KiB
Python
############################
|
|
# **** IMPORT SECTION **** #
|
|
############################
|
|
import sys
|
|
import os
|
|
import shutil
|
|
from qtpy.QtCore import *
|
|
from qtpy.QtGui import *
|
|
from qtpy.QtWidgets import *
|
|
from qtvcp.widgets.file_manager import FileManager as FM
|
|
from qtvcp.core import Info
|
|
###########################################
|
|
# **** instantiate libraries section **** #
|
|
###########################################
|
|
INFO = Info()
|
|
|
|
###################################
|
|
# **** HANDLER CLASS SECTION **** #
|
|
###################################
|
|
|
|
class HandlerClass:
|
|
|
|
########################
|
|
# **** INITIALIZE **** #
|
|
########################
|
|
# widgets allows access to widgets from the qtvcp files
|
|
# at this point the widgets and hal pins are not instantiated
|
|
def __init__(self, halcomp,widgets,paths):
|
|
self.w = widgets
|
|
self.paths = paths
|
|
self.help = HelpDialog()
|
|
|
|
##########################################
|
|
# Special Functions called from QTVCP
|
|
##########################################
|
|
|
|
# at this point:
|
|
# the widgets are instantiated.
|
|
# the HAL pins are built but HAL is not set ready
|
|
def initialized__(self):
|
|
self.w.setWindowTitle(' QtVCP Builtin Screen Code Copier')
|
|
self.w.filemanager.showList(True)
|
|
self.w.filemanager.model.setNameFilters([''])
|
|
self.w.filemanager.cb.hide()
|
|
self.w.filemanager.addButton.hide()
|
|
self.w.filemanager.delButton.hide()
|
|
self.w.filemanager.loadButton.hide()
|
|
self.w.filemanager.copy_control.hide()
|
|
self.w.filemanager.user_path = os.path.expanduser('~/linuxcnc/configs')
|
|
if os.path.exists(self.paths.RIPCONFIGDIR):
|
|
self.w.filemanager._jumpList.update([('RIP',self.paths.RIPCONFIGDIR)])
|
|
self.w.filemanager.addAction('RIP')
|
|
self.w.filemanager._jumpList.update([('Desktop',os.path.expanduser('~/Desktop'))])
|
|
self.w.filemanager.addAction('Desktop')
|
|
|
|
self.w.filemanager.updateDirectoryView(self.w.filemanager.user_path)
|
|
self.list_screen_files()
|
|
self.w.comboBox.currentIndexChanged.connect(self.selectionchange)
|
|
self.w.lineEdit.setText(self.w.comboBox.currentText())
|
|
|
|
########################
|
|
# callbacks #
|
|
########################
|
|
def selectionchange(self,i):
|
|
self.w.lineEdit.setText(self.w.comboBox.currentText())
|
|
|
|
#######################
|
|
# callbacks from form #
|
|
#######################
|
|
def applyClicked(self):
|
|
basename = self.w.lineEdit.text()
|
|
if basename == '': basename = self.w.comboBox.currentText()
|
|
|
|
# VCP panel
|
|
if self.w.radiobutton_vcp.isChecked():
|
|
path = os.path.join(self.paths.PANELDIR, self.w.comboBox.currentText())
|
|
|
|
# vismach
|
|
elif self.w.radiobutton_vismach.isChecked():
|
|
self.copyVismachFiles(self.paths.VISMACHDIR, self.w.filemanager.textLine.text(),
|
|
basename, self.w.comboBox.currentText() )
|
|
|
|
# check for vismach object directory
|
|
objname = self.w.comboBox.currentText().strip('.py')
|
|
objname = objname + '_obj'
|
|
objpath = os.path.join(self.paths.VISMACHDIR, objname)
|
|
objbasename = basename.strip('.py') + '_obj'
|
|
if os.path.exists(objpath):
|
|
self.copyVismachFiles(self.paths.VISMACHDIR, self.w.filemanager.textLine.text(),
|
|
objbasename, objname )
|
|
return
|
|
|
|
# screen
|
|
else:
|
|
path = os.path.join(self.paths.SCREENDIR, self.w.comboBox.currentText())
|
|
|
|
self.copyFilesWithCheck(path, self.w.filemanager.textLine.text(),
|
|
basename, self.w.comboBox.currentText() )
|
|
|
|
def updateCombo(self, value):
|
|
rbtn = self.w.sender()
|
|
if rbtn.isChecked() == True:
|
|
self.w.groupBoxType.setEnabled(False)
|
|
if rbtn == self.w.radiobutton_vcp:
|
|
self.list_vcp_files()
|
|
elif rbtn == self.w.radiobutton_vismach:
|
|
self.list_vismach_files()
|
|
else:
|
|
self.list_screen_files()
|
|
self.w.groupBoxType.setEnabled(True)
|
|
|
|
def helpClicked(self):
|
|
self.help.showDialog()
|
|
|
|
#####################
|
|
# general functions #
|
|
#####################
|
|
|
|
def list_screen_files(self):
|
|
self.w.comboBox.clear()
|
|
for i in sorted(self.paths.find_screen_dirs()):
|
|
self.w.comboBox.addItem(i)
|
|
|
|
def list_vcp_files(self):
|
|
self.w.comboBox.clear()
|
|
for i in sorted(self.paths.find_panel_dirs()):
|
|
self.w.comboBox.addItem(i)
|
|
|
|
def list_vismach_files(self):
|
|
self.w.comboBox.clear()
|
|
for i in sorted(self.paths.find_vismach_files()):
|
|
if '.py' in i:
|
|
self.w.comboBox.addItem(i)
|
|
|
|
def makedirs(self, dest):
|
|
if not os.path.exists(dest):
|
|
os.makedirs(dest)
|
|
|
|
def copyVismachFiles(self, src, dest, baseName, fileName):
|
|
rtn = self.confirmDialog(dest, baseName)
|
|
if not rtn: return
|
|
|
|
fromPath = os.path.join(src, fileName)
|
|
toPath = os.path.join(dest, baseName)
|
|
# make any needed directory
|
|
if not os.path.exists(os.path.dirname(toPath)):
|
|
self.makedirs(os.path.dirname(toPath))
|
|
|
|
if not os.path.exists(toPath):
|
|
if os.path.isfile(fromPath):
|
|
shutil.copy(fromPath, toPath)
|
|
# probably vismach object folder
|
|
elif os.path.isdir(fromPath):
|
|
shutil.copytree(fromPath, toPath)
|
|
|
|
def copyFilesWithCheck(self, src, dest, baseName, srcDirName):
|
|
|
|
# make a copy of the user pick destination path
|
|
ndest = os.path.join(dest)
|
|
|
|
# check for lack of standard folders in path
|
|
folder = ''
|
|
if self.w.radiobutton_vcp.isChecked():
|
|
folder = 'panels'
|
|
elif self.w.radiobutton_screen.isChecked():
|
|
folder = 'screens'
|
|
if not folder in dest:
|
|
r = self.confirmPathDialog('qtvcp/' + folder)
|
|
if r:
|
|
if not 'qtvcp' in dest:
|
|
dest = os.path.join(dest, 'qtvcp')
|
|
if not folder in dest:
|
|
dest = os.path.join(dest, folder)
|
|
# overwrite with the new path
|
|
ndest = dest
|
|
if os.path.exists(dest):
|
|
self.w.filemanager.updateDirectoryView(dest)
|
|
|
|
# confirm user wants to copy
|
|
rtn = self.confirmDialog(ndest, baseName)
|
|
if not rtn: return
|
|
|
|
# add in the basename
|
|
ndest = os.path.join(ndest, baseName)
|
|
|
|
# make any needed initial directory
|
|
if not os.path.exists(os.path.dirname(ndest)):
|
|
self.makedirs(os.path.dirname(ndest))
|
|
|
|
# update the file manager path
|
|
if os.path.exists(dest):
|
|
self.w.filemanager.updateDirectoryView(dest)
|
|
|
|
# walk the folder and copy everything
|
|
for path, dirs, filenames in os.walk(src):
|
|
if dirs == []:
|
|
destDir = path.replace(src,ndest)
|
|
self.makedirs(destDir)
|
|
else:
|
|
for directory in dirs:
|
|
destDir = path.replace(src,ndest)
|
|
self.makedirs(os.path.join(destDir, directory))
|
|
|
|
# files
|
|
for sfile in filenames:
|
|
if sfile == 'resources.py': continue
|
|
|
|
# if source directory name is in file name, rename it.
|
|
if srcDirName in os.path.splitext(sfile)[0]:
|
|
dfile = sfile.replace(srcDirName, baseName)
|
|
else:
|
|
dfile = sfile
|
|
|
|
# use original or subclassed handler?
|
|
if self.w.checkBoxSubclassHandler.isChecked() and self.w.radiobutton_screen.isChecked():
|
|
if not '_handler.py' in sfile and not '.ui' in sfile:
|
|
continue
|
|
if '_handler.py' in sfile:
|
|
# substitute subclass handler.py for original handler
|
|
here = os.path.dirname(os.path.realpath(__file__))
|
|
srcFile = os.path.join(here, 'subclass_handler.py')
|
|
destFile = os.path.join(path.replace(src, ndest), dfile)
|
|
shutil.copy(srcFile, destFile)
|
|
continue
|
|
|
|
srcFile = os.path.join(path, sfile)
|
|
destFile = os.path.join(path.replace(src, ndest), dfile)
|
|
|
|
shutil.copy(srcFile, destFile)
|
|
|
|
# last confirm before copying -check for file overwriting
|
|
def confirmDialog(self, srcPath, name):
|
|
dest = os.path.join(srcPath, name)
|
|
info = 'Copy {} Code?'.format(name)
|
|
if os.path.exists(dest):
|
|
title = "Confirm: Will Overwrite Existing Files!"
|
|
else:
|
|
title = 'Please Confirm:'
|
|
rtn = self.w.messageDialog_.showdialog(
|
|
title,
|
|
more_info=info,
|
|
details=' To Folder:\n {}'.format(dest),
|
|
display_type='YESNO',
|
|
icon=QMessageBox.Information, pinname=None,
|
|
focus_text=None,
|
|
focus_color=None,
|
|
play_alert=None,
|
|
nblock=False,
|
|
use_exec =True)
|
|
if not rtn:
|
|
return False
|
|
return True
|
|
|
|
# confirm that qtvcp/screens or panels is not needed in path
|
|
def confirmPathDialog(self, srcPath):
|
|
dest = os.path.join(srcPath)
|
|
info = "Destination does not have {} folders in path. This is the usual way for qtvcp to find them. Do you wish to add the folders".format(srcPath)
|
|
title = 'Add {} to Path?'.format(srcPath)
|
|
rtn = self.w.messageDialog_.showdialog(
|
|
title,
|
|
more_info=info,
|
|
details=' To Folder:\n {}'.format(dest),
|
|
display_type='YESNO',
|
|
icon=QMessageBox.Information, pinname=None,
|
|
focus_text=None,
|
|
focus_color=None,
|
|
play_alert=None,
|
|
nblock=False,
|
|
use_exec =True)
|
|
if not rtn:
|
|
return False
|
|
return True
|
|
|
|
|
|
class HelpDialog(QDialog):
|
|
def __init__(self, parent=None):
|
|
super(HelpDialog, self).__init__(parent)
|
|
self._title = 'Copy Help'
|
|
self.setWindowFlags(self.windowFlags() | Qt.Tool |
|
|
Qt.Dialog | Qt.WindowStaysOnTopHint |
|
|
Qt.WindowSystemMenuHint)
|
|
self.currentHelpPage=-1
|
|
self.setMinimumWidth(400)
|
|
self.setMinimumHeight(400)
|
|
self.helpPages = ['copy_help1.html','copy_help2.html',
|
|
'copy_help3.html', 'copy_help4.html']
|
|
|
|
self.buildWidget()
|
|
|
|
def buildWidget(self):
|
|
|
|
l = QVBoxLayout()
|
|
t = QTextEdit('Qtvcp Copy Help')
|
|
t.setReadOnly(True)
|
|
l.addWidget(t)
|
|
|
|
buttons = QDialogButtonBox()
|
|
|
|
closebutton = QPushButton()
|
|
closebutton.setIconSize(QSize(38, 38))
|
|
closebutton.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/standardbutton-cancel-128.png'))
|
|
closebutton.clicked.connect(lambda : self.close())
|
|
|
|
nextbutton = QPushButton()
|
|
nextbutton.setIconSize(QSize(38, 38))
|
|
nextbutton.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/right-32.png'))
|
|
nextbutton.clicked.connect(lambda : self.next(t,True))
|
|
|
|
previousbutton = QPushButton()
|
|
previousbutton.setIconSize(QSize(38, 38))
|
|
previousbutton.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/left-32.png'))
|
|
previousbutton.clicked.connect(lambda : self.next(t,False))
|
|
|
|
self.pageStepUpbutton = QPushButton()
|
|
self.pageStepUpbutton.setIconSize(QSize(38, 38))
|
|
self.pageStepUpbutton.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/up-32.png'))
|
|
self.pageStepUpbutton.clicked.connect(lambda : self.pageStep(t,False))
|
|
|
|
self.pageStepDwnbutton = QPushButton()
|
|
self.pageStepDwnbutton.setIconSize(QSize(38, 38))
|
|
self.pageStepDwnbutton.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/down-32.png'))
|
|
self.pageStepDwnbutton.clicked.connect(lambda : self.pageStep(t,True))
|
|
|
|
bBox = QDialogButtonBox(buttons)
|
|
#bBox.addButton(self.pageStepUpbutton, QDialogButtonBox.ActionRole)
|
|
#bBox.addButton(self.pageStepDwnbutton, QDialogButtonBox.ActionRole)
|
|
bBox.addButton(previousbutton, QDialogButtonBox.ActionRole)
|
|
bBox.addButton(nextbutton, QDialogButtonBox.ActionRole)
|
|
bBox.addButton(closebutton, QDialogButtonBox.DestructiveRole)
|
|
bBox.rejected.connect(self.reject)
|
|
|
|
l.addWidget(bBox)
|
|
self.setLayout(l)
|
|
|
|
try:
|
|
self.next(t)
|
|
except Exception as e:
|
|
t.setText('Qtvcp Copy Help file Unavailable:\n\n{}'.format(e))
|
|
|
|
def next(self,t,direction=None):
|
|
if direction is None:
|
|
self.currentHelpPage = 0
|
|
elif direction:
|
|
self.currentHelpPage +=1
|
|
if self.currentHelpPage > len(self.helpPages)-1:
|
|
self.currentHelpPage = len(self.helpPages)-1
|
|
else:
|
|
self.currentHelpPage -=1
|
|
if self.currentHelpPage < 0:
|
|
self.currentHelpPage = 0
|
|
try:
|
|
pagePath = os.path.join( os.path.dirname(__file__), self.helpPages[self.currentHelpPage])
|
|
file = QFile(pagePath)
|
|
file.open(QFile.ReadOnly)
|
|
html = file.readAll()
|
|
html = str(html, encoding='utf8')
|
|
html = html.replace("../images/probe_icons/","{}/probe_icons/".format(INFO.IMAGE_PATH))
|
|
t.setHtml(html)
|
|
if t.verticalScrollBar().isVisible():
|
|
t.verticalScrollBar().setPageStep(20)
|
|
self.pageStepDwnbutton.show()
|
|
self.pageStepUpbutton.show()
|
|
else:
|
|
self.pageStepDwnbutton.hide()
|
|
self.pageStepUpbutton.hide()
|
|
|
|
except Exception as e:
|
|
t.setText('Qtvcp Copy file Unavailable:\n\n{}'.format(e))
|
|
if direction is None:
|
|
return
|
|
self.show()
|
|
|
|
def pageStep(self, t, state):
|
|
if state:
|
|
t.verticalScrollBar().triggerAction (QAbstractSlider.SliderPageStepAdd)
|
|
else:
|
|
t.verticalScrollBar().triggerAction (QAbstractSlider.SliderPageStepSub)
|
|
|
|
|
|
def showDialog(self):
|
|
self.setWindowTitle(self._title);
|
|
retval = self.exec_()
|
|
|
|
#####################
|
|
# KEY BINDING CALLS #
|
|
#####################
|
|
|
|
###########################
|
|
# **** closing event **** #
|
|
###########################
|
|
|
|
##############################
|
|
# required class boiler code #
|
|
##############################
|
|
|
|
def __getitem__(self, item):
|
|
return getattr(self, item)
|
|
def __setitem__(self, item, value):
|
|
return setattr(self, item, value)
|
|
|
|
|
|
################################
|
|
# required handler boiler code #
|
|
################################
|
|
|
|
def get_handlers(halcomp,widgets,paths):
|
|
return [HandlerClass(halcomp,widgets,paths)]
|