# MIT License # # Copyright (c) 2024 Eugenio Parodi # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. __all__ = ['ttkCrossOpen', 'ttkCrossSave', 'ttkCrossSaveAs', 'TTkEncoding', 'ttkConnectDragOpen', 'ttkEmitDragOpen', 'ttkEmitFileOpen'] import os import importlib.util import json from TermTk import pyTTkSlot, pyTTkSignal from TermTk import TTkLog from TermTk import TTkMessageBox, TTkFileDialogPicker, TTkHelper, TTkString, TTkK, TTkColor ttkCrossOpen = None ttkCrossSave = None ttkCrossSaveAs = None ttkEmitDragOpen = None ttkEmitFileOpen = None ttkConnectDragOpen = None class TTkEncoding(str): TEXT = "text" TEXT_PLAIN = "text/plain" TEXT_PLAIN_UTF8 = "text/plain;charset=utf-8" APPLICATION = 'application' APPLICATION_JSON = 'application/json' IMAGE = 'image' IMAGE_PNG = 'image/png' IMAGE_SVG = 'image/svg+xml' IMAGE_JPG = 'image/jpeg' if importlib.util.find_spec('pyodideProxy'): TTkLog.info("Using 'pyodideProxy' as clipboard manager") import pyodideProxy ttkDragOpen = {} ttkFileOpen = pyTTkSignal(dict) def _open(path, encoding, filter, cb=None): if not cb: return ttkFileOpen.connect(cb) pyodideProxy.openFile(encoding) def _save(filePath, content, encoding, filter=None): pyodideProxy.saveFile(os.path.basename(filePath), content, encoding) def _connectDragOpen(encoding, cb): if not encoding in ttkDragOpen: ttkDragOpen[encoding] = pyTTkSignal(dict) return ttkDragOpen[encoding].connect(cb) def _emitDragOpen(encoding, data): for do in [ttkDragOpen[e] for e in ttkDragOpen if encoding.startswith(e)]: do.emit(data) def _emitFileOpen(encoding, data): ttkFileOpen.emit(data) ttkFileOpen.clear() ttkCrossOpen = _open ttkCrossSave = _save ttkCrossSaveAs = _save ttkEmitDragOpen = _emitDragOpen ttkEmitFileOpen = _emitFileOpen ttkConnectDragOpen = _connectDragOpen else: def _crossDecoder_text(fileName) : with open(fileName) as fp: return fp.read() def _crossDecoder_json(fileName) : with open(fileName) as fp: # return json.load(fp) return fp.read() def _crossDecoder_image(fileName): return None _crossDecoder = { TTkEncoding.TEXT : _crossDecoder_text , TTkEncoding.TEXT_PLAIN : _crossDecoder_text , TTkEncoding.TEXT_PLAIN_UTF8 : _crossDecoder_text , TTkEncoding.APPLICATION : _crossDecoder_json , TTkEncoding.APPLICATION_JSON : _crossDecoder_json , TTkEncoding.IMAGE : _crossDecoder_image , TTkEncoding.IMAGE_PNG : _crossDecoder_image , TTkEncoding.IMAGE_SVG : _crossDecoder_image , TTkEncoding.IMAGE_JPG : _crossDecoder_image , } def _open(path, encoding, filter, cb=None): if not cb: return def __openFile(fileName): _decoder = _crossDecoder.get(encoding,lambda _:None) content = _decoder(fileName) cb({'name':fileName, 'data':content}) filePicker = TTkFileDialogPicker(pos = (3,3), size=(100,30), caption="Open", path=path, fileMode=TTkK.FileMode.ExistingFile ,filter=filter) filePicker.pathPicked.connect(__openFile) TTkHelper.overlay(None, filePicker, 5, 5, True) def _save(filePath, content, encoding): TTkLog.info(f"Saving to: {filePath}") with open(filePath,'w') as fp: fp.write(content) def _saveAs(filePath, content, encoding, filter, cb=None): if not cb: return def _approveFile(fileName): if os.path.exists(fileName): @pyTTkSlot(TTkMessageBox.StandardButton) def _cb(btn): if btn == TTkMessageBox.StandardButton.Save: ttkCrossSave(fileName,content,encoding) elif btn == TTkMessageBox.StandardButton.Cancel: return if cb: cb() messageBox = TTkMessageBox( text= ( TTkString( f'A file named "{os.path.basename(fileName)}" already exists.\nDo you want to replace it?', TTkColor.BOLD) + TTkString( f'\n\nReplacing it will overwrite its contents.') ), icon=TTkMessageBox.Icon.Warning, standardButtons=TTkMessageBox.StandardButton.Discard|TTkMessageBox.StandardButton.Save|TTkMessageBox.StandardButton.Cancel) messageBox.buttonSelected.connect(_cb) TTkHelper.overlay(None, messageBox, 5, 5, True) else: ttkCrossSave(fileName,content,encoding) filePicker = TTkFileDialogPicker( size=(100,30), path=filePath, acceptMode=TTkK.AcceptMode.AcceptSave, caption="Save As...", fileMode=TTkK.FileMode.AnyFile , filter=filter) filePicker.pathPicked.connect(_approveFile) TTkHelper.overlay(None, filePicker, 5, 5, True) ttkCrossOpen = _open ttkCrossSave = _save ttkCrossSaveAs = _saveAs ttkEmitDragOpen = lambda a:None ttkEmitFileOpen = lambda a:None ttkConnectDragOpen = lambda a,b:None