python-lottie  0.7.0+dev66cafb9
A framework to work with lottie files and telegram animated stickers (tgs)
import_export.py
Go to the documentation of this file.
1 import threading
2 from functools import reduce
3 from PyQt5 import QtCore, QtWidgets, QtGui
4 from PyQt5.QtCore import Qt
5 
6 from ..exporters.base import exporters
7 from ..importers.base import importers
8 from ..parsers.baseporter import IoProgressReporter, ExtraOption
9 
10 
12  def __init__(self):
13  self.dialogsdialogs = {}
14  self.threadsthreads = {}
15  self.locklock = threading.Lock()
16  self.idid = 0
17 
18  @classmethod
19  def set_global(cls):
20  IoProgressReporter.instance = cls()
21 
22  def gen_id(self, parent):
23  self.idid += 1
24  with self.locklock:
25  dialog = QtWidgets.QProgressDialog(parent)
26  dialog.setCancelButton(None)
27  dialog.setWindowModality(Qt.ApplicationModal)
28  self.dialogsdialogs[self.idid] = dialog
29  return self.idid
30 
31  def get_thread_dialog(self):
32  with self.locklock:
33  id = threading.current_thread().ident
34  return self.dialogsdialogs[self.threadsthreads[id]]
35 
36  def setup(self, title, id):
37  with self.locklock:
38  tid = threading.current_thread().ident
39  self.threadsthreads[tid] = id
40  dialog = self.dialogsdialogs[id]
41 
42  dialog.setWindowTitle(title)
43  dialog.hide()
44 
45  def report_progress(self, title, value, total):
46  dialog = self.get_thread_dialogget_thread_dialog()
47  dialog.show()
48  dialog.setValue(value)
49  dialog.setMaximum(total)
50  dialog.setLabelText(title)
51 
52  def report_message(self, message):
53  dialog = self.get_thread_dialogget_thread_dialog()
54  dialog.show()
55  dialog.setRange(0, 0)
56  dialog.setLabelText(message)
57 
58  def cleanup(self):
59  with self.locklock:
60  id = threading.current_thread().ident
61  dialog = self.dialogsdialogs.pop(self.threadsthreads.pop(id))
62  dialog.hide()
63  dialog.deleteLater()
64 
65 
67  def __init__(self, porter):
68  self.porterporter = porter
69  self.file_filterfile_filter = "%s (%s)" % (porter.name, " ".join("*.%s" % e for e in porter.extensions))
70  self._dialog_dialog = None
71  self.widgetswidgets = {}
72 
73  def _build_dialog(self):
74  self._dialog_dialog = QtWidgets.QDialog()
75  self._dialog_dialog.setWindowTitle("Export to %s" % self.porterporter.name)
76  layout = QtWidgets.QFormLayout()
77  self._dialog_dialog.setLayout(layout)
78 
79  for go in self.porterporter.generic_options:
80  self._generic_option_generic_option(layout, go)
81 
82  for option in self.porterporter.extra_options:
83  self._add_option_add_option(layout, option)
84 
85  button_box = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel)
86  button_box.accepted.connect(self._dialog_dialog.accept)
87  button_box.rejected.connect(self._dialog_dialog.reject)
88  layout.addRow(button_box)
89 
90  def _add_option(self, layout, option: ExtraOption):
91  if option.dest in self.widgetswidgets:
92  return
93  label = QtWidgets.QLabel(option.name.replace("_", " ").title())
94 
95  default = option.kwargs.get("default", None)
96  option_type = option.kwargs.get("type", str)
97 
98  if option.kwargs.get("action") == "store_true":
99  widget = QtWidgets.QCheckBox()
100  widget.setChecked(False)
101  getter = widget.isChecked
102  elif option.kwargs.get("action") == "store_false":
103  widget = QtWidgets.QCheckBox()
104  labtext = label.text()
105  if labtext.startswith("No "):
106  label.setText(labtext[3:])
107  widget.setChecked(True)
108  getter = widget.isChecked
109  elif "choices" in option.kwargs:
110  widget = QtWidgets.QComboBox()
111  for choice in option.kwargs["choices"]:
112  widget.addItem(str(choice))
113  if default:
114  widget.setCurrentText(str(default))
115  getter = lambda: option_type(widget.currentText())
116  elif option_type is int:
117  widget = QtWidgets.QSpinBox()
118  widget.setMinimum(-1000)
119  widget.setMaximum(1000)
120  if default is not None:
121  widget.setValue(int(default))
122  getter = widget.value
123  else:
124  widget = QtWidgets.QLineEdit()
125  if default is not None:
126  widget.setText(str(default))
127  getter = widget.text
128 
129  help = option.kwargs.get("help", "")
130  widget.setWhatsThis(help)
131  widget.setToolTip(help)
132 
133  widget.setObjectName(option.dest)
134  self.widgetswidgets[option.dest] = getter
135  layout.addRow(label, widget)
136 
137  @property
138  def needs_dialog(self):
139  return self.porterporter.generic_options or self.porterporter.extra_options
140 
141  @property
142  def dialog(self):
143  if not self._dialog_dialog:
144  self._build_dialog_build_dialog()
145  return self._dialog_dialog
146 
147  def get_options(self):
148  return {
149  name: getter()
150  for name, getter in self.widgetswidgets.items()
151  }
152 
153  def prompt_options(self, parent):
154  if self.needs_dialogneeds_dialog:
155  self.dialogdialog.setParent(parent)
156  self.dialogdialog.setWindowFlags(Qt.Dialog)
157  if self.dialogdialog.exec_() != QtWidgets.QDialog.DialogCode.Accepted:
158  return None
159 
160  return self.get_optionsget_options()
161 
162  def _generic_option(self, layout, go):
163  pass
164 
165 
166 class GuiExporter(GuiBasePorter):
167  def _generic_option(self, layout, go):
168  if go == "pretty":
169  self._add_option(layout, ExtraOption("pretty", action="store_true", help="Pretty print"))
170  if go == "frame":
171  self._add_option(layout, ExtraOption("frame", type=int, help="Frame to extract"))
172 
173  @property
174  def exporter(self):
175  return self.porterporter
176 
177 
179  @property
180  def importer(self):
181  return self.porterporter
182 
183 
184 class ExportThread(QtCore.QThread):
185  def __init__(self, parent, exporter, animation, file_name, options):
186  super().__init__()
187  self.idid = IoProgressReporter.instance.gen_id(parent)
188  self.animationanimation = animation
189  self.exporterexporter = exporter
190  self.file_namefile_name = file_name
191  self.optionsoptions = options
192 
193  def run(self):
194  IoProgressReporter.instance.setup("Export to %s" % self.exporterexporter.name, self.idid)
195  try:
196  self.exporterexporter.process(self.animationanimation, self.file_namefile_name, **self.optionsoptions)
197  except Exception:
198  IoProgressReporter.instance.report_message("Error on export")
199  IoProgressReporter.instance.cleanup()
200 
201 
202 gui_exporters = list(map(GuiExporter, exporters))
203 gui_importers = list(map(GuiImporter, importers))
204 
205 
206 def get_open_filename(parent, title, dirname):
207  extensions = reduce(lambda a, b: a | b, (set(gi.importer.extensions) for gi in gui_importers))
208  all_files = "All Supported Files (%s)" % " ".join("*.%s" % ex for ex in extensions)
209  filters = all_files + ";;" + ";;".join(ge.file_filter for ge in gui_importers)
210  file_name, filter = QtWidgets.QFileDialog.getOpenFileName(
211  parent, title, dirname, filters
212  )
213  if file_name:
214  if filter == all_files:
215  importer = gui_importer_from_filename(file_name)
216  if importer:
217  return file_name, importer
218  else:
219  for importer in gui_importers:
220  if importer.file_filter == filter:
221  return file_name, importer
222 
223  return None, None
224 
225 
226 def get_save_filename(parent, title, dirname):
227  extensions = reduce(lambda a, b: a | b, (set(gi.exporter.extensions) for gi in gui_exporters))
228  all_files = "All Supported Files (%s)" % " ".join("*.%s" % ex for ex in extensions)
229  filters = all_files + ";;" + ";;".join(ge.file_filter for ge in gui_exporters)
230  file_name, filter = QtWidgets.QFileDialog.getSaveFileName(
231  parent, title, dirname, filters
232  )
233 
234  if file_name:
235  if filter == all_files:
236  exporter = gui_exporter_from_filename(file_name)
237  if exporter:
238  return file_name, exporter
239  else:
240  for exporter in gui_exporters:
241  if exporter.file_filter == filter:
242  return file_name, exporter
243 
244  return None, None
245 
246 
247 def start_export(parent, exporter, animation, file_name, options):
248  thread = ExportThread(parent, exporter, animation, file_name, options)
249  thread.start()
250  return thread
251 
252 
254  importer = importers.get_from_filename(filename)
255  for gip in gui_importers:
256  if gip.importer is importer:
257  return gip
258  return None
259 
260 
262  exporter = exporters.get_from_filename(filename)
263  for gip in gui_exporters:
264  if gip.exporter is exporter:
265  return gip
266  return None
def __init__(self, parent, exporter, animation, file_name, options)
def _add_option(self, layout, ExtraOption option)
def report_progress(self, title, value, total)
def gui_importer_from_filename(filename)
def get_save_filename(parent, title, dirname)
def start_export(parent, exporter, animation, file_name, options)
def get_open_filename(parent, title, dirname)
def gui_exporter_from_filename(filename)