batoolset 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. batoolset/GUI/__init__.py +0 -0
  2. batoolset/GUI/list_gui.py +513 -0
  3. batoolset/GUI/multi_image_display.py +989 -0
  4. batoolset/GUI/open.py +325 -0
  5. batoolset/GUI/overlay_hints.py +45 -0
  6. batoolset/GUI/paint2.py +1345 -0
  7. batoolset/GUI/scrollablepaint.py +1152 -0
  8. batoolset/IJ_ROIs/__init__.py +0 -0
  9. batoolset/IJ_ROIs/tools.py +40 -0
  10. batoolset/PATH/__init__.py +0 -0
  11. batoolset/PATH/tools.py +79 -0
  12. batoolset/SQLite_tools/__init__.py +0 -0
  13. batoolset/SQLite_tools/tools.py +840 -0
  14. batoolset/__init__.py +0 -0
  15. batoolset/binary/__init__.py +0 -0
  16. batoolset/binary/tools.py +123 -0
  17. batoolset/binarytools/__init__.py +0 -0
  18. batoolset/binarytools/cell_center_detector.py +290 -0
  19. batoolset/clipboard_tools/__init__.py +0 -0
  20. batoolset/clipboard_tools/tools.py +7 -0
  21. batoolset/colors/__init__.py +0 -0
  22. batoolset/colors/colorgen.py +193 -0
  23. batoolset/colors/tools.py +22 -0
  24. batoolset/command_line/__init__.py +0 -0
  25. batoolset/command_line/tools.py +18 -0
  26. batoolset/dialogs/__init__.py +0 -0
  27. batoolset/dialogs/opensave.py +228 -0
  28. batoolset/dicts/__init__.py +0 -0
  29. batoolset/dicts/tools.py +299 -0
  30. batoolset/dims/__init__.py +0 -0
  31. batoolset/dims/tools.py +83 -0
  32. batoolset/draw/__init__.py +0 -0
  33. batoolset/draw/shapes/Position.py +183 -0
  34. batoolset/draw/shapes/__init__.py +0 -0
  35. batoolset/draw/shapes/automated_alignment_drawing_refactored.py +346 -0
  36. batoolset/draw/shapes/circle2d.py +99 -0
  37. batoolset/draw/shapes/compute_optimal_size_all_merged.py +317 -0
  38. batoolset/draw/shapes/ellipse2d.py +336 -0
  39. batoolset/draw/shapes/freehand2d.py +235 -0
  40. batoolset/draw/shapes/group.py +1830 -0
  41. batoolset/draw/shapes/image2d.py +2469 -0
  42. batoolset/draw/shapes/line2d.py +575 -0
  43. batoolset/draw/shapes/point2d.py +257 -0
  44. batoolset/draw/shapes/polygon2d.py +357 -0
  45. batoolset/draw/shapes/polyline2d.py +235 -0
  46. batoolset/draw/shapes/rect2d.py +388 -0
  47. batoolset/draw/shapes/rectangle2d.py +601 -0
  48. batoolset/draw/shapes/scalebar.py +304 -0
  49. batoolset/draw/shapes/serializablefont.py +126 -0
  50. batoolset/draw/shapes/serializableguiparams.py +10 -0
  51. batoolset/draw/shapes/square2d.py +103 -0
  52. batoolset/draw/shapes/textorientation.py +45 -0
  53. batoolset/draw/shapes/tools.py +467 -0
  54. batoolset/draw/shapes/transform2D.py +350 -0
  55. batoolset/draw/shapes/txt2d.py +550 -0
  56. batoolset/draw/widgets/__init__.py +0 -0
  57. batoolset/draw/widgets/col.py +343 -0
  58. batoolset/draw/widgets/image_group.py +248 -0
  59. batoolset/draw/widgets/image_organizer.py +96 -0
  60. batoolset/draw/widgets/paint.py +184 -0
  61. batoolset/draw/widgets/vectorial.py +257 -0
  62. batoolset/figure/__init__.py +0 -0
  63. batoolset/figure/alignment.py +814 -0
  64. batoolset/figure/column.py +1117 -0
  65. batoolset/figure/fig_tools.py +285 -0
  66. batoolset/figure/minimal_debugger_scale_etc.py +139 -0
  67. batoolset/figure/panel.py +697 -0
  68. batoolset/figure/row.py +852 -0
  69. batoolset/figure/user_selection.py +287 -0
  70. batoolset/files/__init__.py +0 -0
  71. batoolset/files/tools.py +1321 -0
  72. batoolset/images/__init__.py +0 -0
  73. batoolset/images/tools.py +81 -0
  74. batoolset/img.py +5216 -0
  75. batoolset/linux/__init__.py +0 -0
  76. batoolset/linux/tools.py +72 -0
  77. batoolset/lists/__init__.py +0 -0
  78. batoolset/lists/tools.py +436 -0
  79. batoolset/luts/__init__.py +0 -0
  80. batoolset/luts/lut_minimal_test.py +1207 -0
  81. batoolset/matplolib/__init__.py +0 -0
  82. batoolset/matplolib/tools.py +44 -0
  83. batoolset/np_tools/__init__.py +0 -0
  84. batoolset/np_tools/tools.py +252 -0
  85. batoolset/np_tools/trash.py +15 -0
  86. batoolset/pandas_tools/__init__.py +0 -0
  87. batoolset/pandas_tools/tools.py +880 -0
  88. batoolset/partials/__init__.py +0 -0
  89. batoolset/partials/tools.py +83 -0
  90. batoolset/plot_tools/__init__.py +0 -0
  91. batoolset/plot_tools/tools.py +70 -0
  92. batoolset/pyqt/__init__.py +0 -0
  93. batoolset/pyqt/tools.py +691 -0
  94. batoolset/re_tools/__init__.py +0 -0
  95. batoolset/re_tools/tools.py +35 -0
  96. batoolset/serialization/__init__.py +0 -0
  97. batoolset/serialization/tools.py +1192 -0
  98. batoolset/sets/__init__.py +0 -0
  99. batoolset/sets/tools.py +109 -0
  100. batoolset/settings/__init__.py +0 -0
  101. batoolset/settings/global_settings.py +134 -0
  102. batoolset/strings/__init__.py +0 -0
  103. batoolset/strings/tools.py +225 -0
  104. batoolset/ta/__init__.py +0 -0
  105. batoolset/ta/database/__init__.py +0 -0
  106. batoolset/ta/database/advanced_sql_plotter.py +1170 -0
  107. batoolset/ta/database/my_qt_table.py +79 -0
  108. batoolset/ta/database/preview_and_edit_sqlite_db.py +405 -0
  109. batoolset/ta/database/sql.py +2141 -0
  110. batoolset/ta/database/sql_column_name_dialog.py +122 -0
  111. batoolset/ta/measurements/TAmeasures.py +2226 -0
  112. batoolset/ta/measurements/__init__.py +0 -0
  113. batoolset/ta/measurements/measurements3D/__init__.py +0 -0
  114. batoolset/ta/measurements/measurements3D/get_point_on_surface_if_centroid_is_bad.py +175 -0
  115. batoolset/ta/measurements/measurements3D/height_map_to_projection.py +82 -0
  116. batoolset/ta/measurements/measurements3D/measures3D.py +208 -0
  117. batoolset/ta/measurements/measurements3D/triangulate.py +331 -0
  118. batoolset/ta/measurements/nematic.py +562 -0
  119. batoolset/ta/measurements/nematic_measurements.py +107 -0
  120. batoolset/ta/segmentation/__init__.py +0 -0
  121. batoolset/ta/segmentation/neo_wshed.py +314 -0
  122. batoolset/ta/selections/__init__.py +0 -0
  123. batoolset/ta/selections/selection.py +329 -0
  124. batoolset/ta/tracking/__init__.py +0 -0
  125. batoolset/ta/tracking/last_tracking_based_on_matching_or_on_translation_from_mermaid_warp.py +653 -0
  126. batoolset/ta/tracking/local_to_track_correspondance.py +138 -0
  127. batoolset/ta/tracking/rapid_detection_of_vertices.py +517 -0
  128. batoolset/ta/tracking/registration.py +108 -0
  129. batoolset/ta/tracking/swap_detector_and_fixer.py +296 -0
  130. batoolset/ta/tracking/track_correction.py +238 -0
  131. batoolset/ta/tracking/tracking_error_detector_and_fixer.py +3099 -0
  132. batoolset/ta/tracking/tracking_yet_another_approach_pyramidal_registration_n_neo_swapping_correction.py +725 -0
  133. batoolset/ta/utils/TA_tools.py +43 -0
  134. batoolset/ta/utils/__init__.py +0 -0
  135. batoolset/ta/utils/rps_tools.py +1783 -0
  136. batoolset/tests/__init__.py +0 -0
  137. batoolset/tests/rps_tools.py +51 -0
  138. batoolset/tests/tools.py +10 -0
  139. batoolset/tools/__init__.py +0 -0
  140. batoolset/tools/early_stopper_class.py +9 -0
  141. batoolset/tools/guided_data_recoverer.py +110 -0
  142. batoolset/tools/logger.py +100 -0
  143. batoolset/tools/mytimer.py +31 -0
  144. batoolset/tools/prompt_color.py +160 -0
  145. batoolset/tools/qthandler.py +118 -0
  146. batoolset/uitools/__init__.py +0 -0
  147. batoolset/uitools/blinker.py +56 -0
  148. batoolset/unsafe/__init__.py +0 -0
  149. batoolset/unsafe/tools.py +115 -0
  150. batoolset/utils/__init__.py +0 -0
  151. batoolset/utils/commontools.py +158 -0
  152. batoolset/utils/loadlist.py +728 -0
  153. batoolset/version.py +10 -0
  154. batoolset/xml/__init__.py +0 -0
  155. batoolset/xml/tools.py +65 -0
  156. batoolset/zip_tools/__init__.py +0 -0
  157. batoolset/zip_tools/tools.py +76 -0
  158. batoolset-0.1.0.dist-info/LICENSE +24 -0
  159. batoolset-0.1.0.dist-info/METADATA +45 -0
  160. batoolset-0.1.0.dist-info/RECORD +162 -0
  161. batoolset-0.1.0.dist-info/WHEEL +5 -0
  162. batoolset-0.1.0.dist-info/top_level.txt +1 -0
File without changes
@@ -0,0 +1,513 @@
1
+ # support list for writing or not stuff
2
+ import os
3
+ from batoolset.settings.global_settings import set_UI # set the UI to qtpy
4
+ set_UI()
5
+ from qtpy import QtCore, QtWidgets
6
+ from qtpy.QtCore import Qt,Signal
7
+ from qtpy.QtWidgets import QWidget, QAbstractItemView, QListWidget, QVBoxLayout, QListWidgetItem, QToolBar, \
8
+ QToolButton, \
9
+ QLabel, QAction
10
+ import pyperclip as clip
11
+ from batoolset.dialogs.opensave import saveFileDialog
12
+ from batoolset.utils.loadlist import loadlist, save_list_to_file
13
+ import os
14
+ import platform
15
+ import subprocess
16
+ from batoolset.files.tools import smart_name_parser
17
+ import qtawesome as qta
18
+ from natsort import natsorted
19
+ from batoolset.tools.logger import TA_logger
20
+ logger = TA_logger()
21
+
22
+
23
+ __DEBUG__ = True
24
+
25
+ IMAGES_2D = ['.tif', '.tiff', '.jpg', '.jpeg', '.png', '.tga', '.bmp']
26
+ STACKS = ['.tif', '.tiff', '.lif', '.czi', '.lif', '.lsm']
27
+ LISTS = ['.lst', '.txt']
28
+ FASTA = ['.fa','.fna','.fasta']
29
+ PYTA_DEFAULT = IMAGES_2D + LISTS
30
+
31
+ class CustomListWidget(QListWidget):
32
+ orderChanged = Signal()
33
+
34
+ def dropEvent(self, event):
35
+ super().dropEvent(event)
36
+ self.orderChanged.emit()
37
+
38
+ class ListGUI(QWidget):
39
+ orderChanged = Signal()
40
+ deletePressed = Signal() # can be used in parent to detect that this was called allowing some action to be taken (more elegant than the callback or the method overlaod in several aspects)!
41
+ # TODO define supported formats --> TODO
42
+ def __init__(self, parent=None, file_to_load=None, supported_files=None, custom_label='Please Drag and Drop files below:', default_double_click_behaviour='full_no_ext', enable_folder_DND=True, detect_list_order_change=False):
43
+ super().__init__(parent)
44
+ if detect_list_order_change:
45
+ self.list = CustomListWidget(self) # a list that contains files to read or play with
46
+ # self.list.orderChanged.connect(self.check_order_changed)
47
+ else:
48
+ self.list = QListWidget(self)
49
+ self.list.setSelectionMode(QAbstractItemView.ExtendedSelection)
50
+ # self.list.selectionModel().selectionChanged.connect(self.selectionChanged) # connect it to sel change
51
+
52
+ # self.list.selectionModel().selectionChanged.connect(self.listSelectionChanged)
53
+
54
+ self.list.itemDoubleClicked.connect(self.open_corresponding_folder)
55
+
56
+ self.enable_folder_DND = enable_folder_DND
57
+ self.default_double_click_behaviour = default_double_click_behaviour
58
+
59
+ layout = QVBoxLayout()
60
+ lab = QLabel(custom_label)
61
+ layout.addWidget(lab)
62
+ layout.addWidget(self.list)
63
+
64
+ self.setLayout(layout)
65
+ # allow support of DND
66
+ self.setAcceptDrops(True)
67
+ self.supported_files = supported_files
68
+
69
+ # status_bar = QStatusBar()
70
+ # layout.addWidget(status_bar)
71
+ # self.list_commands(**kwargs)
72
+ self.list_commands()
73
+
74
+ if file_to_load is not None:
75
+ self.load_list(file_to_load)
76
+ # if __DEBUG__:
77
+ # fake sel list
78
+ # pass
79
+
80
+ # allow move objects within the list
81
+ self.list.setDragDropMode(QAbstractItemView.InternalMove) # j'adore --> maybe put this as an option
82
+
83
+ # allows sorting of lists
84
+ # self.list.setSortingEnabled(True) # we don't want list to be sorted by default
85
+ # self.list.sortItems() # ascending by default
86
+ self.list.sortItems(QtCore.Qt.DescendingOrder) # todo MAKE it a sort button
87
+
88
+ # both lines below support objects handling directly from the list --> a gain of time
89
+ self.list.itemChanged.connect(self.item_changed)
90
+ self._object_dict = {} # dirty hack to store objects and allow for DND of objects
91
+
92
+ def item_changed(self, item):
93
+ obj = self._object_dict.get(str(item)) # Get the object from the dictionary
94
+ if obj is not None:
95
+ # Do something with the object
96
+ print("Object changed:", obj)
97
+ def check_order_changed(self):
98
+ # Implement your order changed logic here
99
+ print("Order changed!")
100
+ # self.setWindowTitle('test')
101
+
102
+ def open_corresponding_folder(self, double_clicked_item):
103
+ try:
104
+ self.open_folder(smart_name_parser(double_clicked_item.toolTip(), ordered_output=[self.default_double_click_behaviour])[0]) #'full_no_ext'
105
+ except:
106
+ # no big deal if it fails
107
+ pass
108
+
109
+ def open_folder(self, path):
110
+ if platform.system() == 'Darwin':
111
+ subprocess.Popen(['open', path])
112
+ elif platform.system() == 'Windows':
113
+ os.startfile(path)
114
+ elif platform.system() == 'Linux':
115
+ subprocess.Popen(["xdg-open", path])
116
+
117
+ def list_commands(self): #,**kwargs):
118
+
119
+ # buttons_to_hide = []
120
+ # if 'buttons_to_remove' in kwargs:
121
+ # buttons_to_hide = kwargs['buttons_to_remove']
122
+ # if isinstance(buttons_to_hide, str):
123
+ # buttons_to_hide = [buttons_to_hide]
124
+
125
+ # self.penSize = QSpinBox(objectName='penSize')
126
+ # self.penSize.setSingleStep(1)
127
+ # self.penSize.setRange(1, 256)
128
+ # self.penSize.setValue(3)
129
+ # self.penSize.valueChanged.connect(self.penSizechange)
130
+
131
+ # self.channels = QComboBox(objectName='channels')
132
+ # self.channels.addItem("merge")
133
+ # self.channels.addItem("0")
134
+ # self.channels.addItems(["1", "2", "3"])
135
+ # self.channels.currentIndexChanged.connect(self.channelChange)
136
+
137
+ self.tb = QToolBar()
138
+ #
139
+ toolButton = QToolButton()
140
+ # toolButton.setText('Draw')
141
+
142
+
143
+ save_action = QAction(qta.icon('fa5.save'), 'Save image list', self)
144
+ save_action.triggered.connect(self.save_list)
145
+ # END KEEP
146
+ toolButton.setDefaultAction(save_action)
147
+ self.tb.addWidget(toolButton)
148
+ #
149
+ # toolButton2 = QToolButton()
150
+ # toolButton2.setText('Draw')
151
+ # toolButton2.setIcon(self.style().standardIcon(QStyle.SP_DialogApplyButton))
152
+ # tb.addWidget(toolButton2)
153
+ #
154
+ # toolButton3 = QToolButton()
155
+ # toolButton3.setText('Draw')
156
+ # toolButton3.setIcon(self.style().standardIcon(QStyle.SP_DialogCancelButton))
157
+ # tb.addWidget(toolButton3)
158
+ #
159
+ # toolButton4 = QToolButton()
160
+ # toolButton4.setText('Draw')
161
+ # toolButton4.setIcon(self.style().standardIcon(QStyle.SP_DialogCloseButton))
162
+ # tb.addWidget(toolButton4)
163
+
164
+ toolButton5 = QToolButton()
165
+ # toolButton5.setText("Delete")
166
+ # toolButton5.setIcon(self.style().standardIcon(QStyle.SP_TrashIcon))
167
+ # toolButton5.addAction(dqsdqsdq)
168
+ # pkoi marche pas
169
+ # KEEP
170
+
171
+ delete_sel_action = QAction(qta.icon('mdi.delete-outline'), 'Delete selection', self)
172
+ # toolButton5.addAction(delete_sel_action) # this stuff adds a dropwdon that can be opened by pressing a long time on the button --> keep in mind cause can be useful
173
+ delete_sel_action.triggered.connect(self.removeSel)
174
+ # END KEEP
175
+ toolButton5.setDefaultAction(delete_sel_action)
176
+ self.tb.addWidget(toolButton5)
177
+
178
+ toolButton6 = QToolButton()
179
+ # toolButton6.setText("Copy")
180
+ # toolButton6.setIcon(qta.icon('fa5.copy'))
181
+ copy_action = QAction(qta.icon('fa5.copy'), 'Copy selection to the system clipboard', self)
182
+ copy_action.triggered.connect(self.sel_to_clipboard)
183
+ toolButton6.setDefaultAction(copy_action)
184
+ # toolButton6.ad#dAction(print('toto'))
185
+ self.tb.addWidget(toolButton6)
186
+
187
+ toolButton7 = QToolButton()
188
+ # toolButton7.setText("Paste")
189
+ # toolButton7.setIcon(qta.icon('fa.paste'))
190
+ paste_action = QAction(qta.icon('fa.paste'), 'Paste the system clipboard to the list', self)
191
+ paste_action.triggered.connect(self.paste_from_clipboard)
192
+ toolButton7.setDefaultAction(paste_action)
193
+ self.tb.addWidget(toolButton7)
194
+
195
+ toolButton8 = QToolButton()
196
+ sort_action = QAction(qta.icon('mdi.sort-alphabetical-ascending'), 'Sort list (using the Natsort algorithm)', self)
197
+ sort_action.triggered.connect(self.natsort_list)
198
+ toolButton8.setDefaultAction(sort_action)
199
+ self.tb.addWidget(toolButton8)
200
+
201
+ # tb.addWidget(self.channels)
202
+
203
+ # tb.addAction("Save")
204
+ # tb.addAction("sq...")
205
+ # tb.addWidget(self.penSize)
206
+
207
+ # could have show and hide mask here --> see how I can do that --> but do not delete it in fact
208
+
209
+ self.layout().addWidget(self.tb)
210
+
211
+ # disable item internal move and list addition, just selection is kept
212
+ def freeze(self, bool):
213
+ self.tb.setEnabled(not bool)
214
+ # TODO disable DND of list component
215
+ # if bool:
216
+ # self.list.setDragDropMode(QAbstractItemView.InternalMove)
217
+ # self.setAcceptDrops(True)
218
+ # else:
219
+ # self.list.setDragDropMode(QAbstractItemView.InternalMove)
220
+ self.setAcceptDrops(not bool)
221
+ # how to disable item reorder
222
+ # QGraphicsItem.ItemIsMovable
223
+ # we also prevent internal drag --> it's a way to keep the list functional
224
+
225
+
226
+
227
+ # ça ne marche pas
228
+ # print(bool)
229
+ if bool:
230
+
231
+ # print('entering o,ne')
232
+
233
+ # disable item internal move
234
+ for iii in range(self.list.count()):
235
+ item = self.list.item(iii)
236
+
237
+ # is there a bug here
238
+ if item.flags() & Qt.ItemIsDragEnabled:
239
+ item.setFlags(item.flags() ^ Qt.ItemIsDragEnabled)
240
+ # item.setFlags(item.flags() ^ Qt.ItemIsDropEnabled)
241
+
242
+ # if iii == 0:
243
+ # if item.flags() & Qt.ItemIsDragEnabled:
244
+ # print( "ItemIsDragEnabled", item)
245
+ # else:
246
+ # print("not ItemIsDragEnabled", item)
247
+
248
+ else:
249
+ # allow item internal move
250
+ # print('entering two')
251
+ for iii in range(self.list.count()):
252
+ item = self.list.item(iii)
253
+ item.setFlags(item.flags() | Qt.ItemIsDragEnabled)
254
+ # item.setFlags(item.flags() | Qt.ItemIsDropEnabled)
255
+ # if iii == 0:
256
+ # if item.flags() & Qt.ItemIsDragEnabled:
257
+ # print("ItemIsDragEnabled", item)
258
+ # else:
259
+ # print("not ItemIsDragEnabled", item)
260
+
261
+
262
+ def load_list(self, file_to_load):
263
+ files = loadlist(file_to_load)
264
+ if files is not None:
265
+ # populate the list
266
+ for file in files:
267
+ self.add_file_to_list_if_supported(file)
268
+ else:
269
+ print('list could not be loaded/invalid list --> sorry')
270
+
271
+ # def selectionChanged(self):
272
+ # print('selection changed to override')
273
+
274
+ # allow DND
275
+ def dragEnterEvent(self, event):
276
+ if not self.acceptDrops():
277
+ logger.warning('Drag and drop not supported in "Preview" mode, please select another tab.')
278
+ event.ignore()
279
+ return
280
+ if event.mimeData().hasUrls():
281
+ event.accept()
282
+ else:
283
+ event.ignore()
284
+
285
+ def dragMoveEvent(self, event):
286
+ if not self.acceptDrops():
287
+ logger.warning('Drag and drop not supported in "Preview" mode, please select another tab.')
288
+ event.ignore()
289
+ return
290
+ if event.mimeData().hasUrls():
291
+ event.setDropAction(QtCore.Qt.CopyAction)
292
+ event.accept()
293
+ else:
294
+ event.ignore()
295
+
296
+ # handle DND on drop
297
+ def dropEvent(self, event):
298
+ super().dropEvent(event)
299
+ self.orderChanged.emit()
300
+
301
+ if not self.acceptDrops():
302
+ logger.warning('Drag and drop not supported in "Preview" mode, please select another tab.')
303
+ event.ignore()
304
+ return
305
+
306
+ if event.mimeData().hasUrls():
307
+ event.setDropAction(QtCore.Qt.CopyAction)
308
+ event.accept()
309
+ urls = []
310
+ for url in event.mimeData().urls():
311
+ urls.append(url.toLocalFile())
312
+ # add all dropped items to the list
313
+ for url in urls:
314
+ # item = QListWidgetItem(os.path.basename(url), self.list)
315
+ # item.setToolTip(url)
316
+ # self.list.addItem(item)
317
+ self.add_file_to_list_if_supported(url)
318
+ else:
319
+ event.ignore()
320
+
321
+ def is_file_supported(self, file):
322
+ if self.supported_files is None:
323
+ # accept all by default
324
+ return True
325
+ if smart_name_parser(file, ordered_output=['ext'])[0].lower() in self.supported_files:
326
+ return True
327
+ return False
328
+
329
+ def add_file_to_list_no_check(self, file):
330
+ item = QListWidgetItem(os.path.basename(file), self.list)
331
+ item.setToolTip(file)
332
+ self.list.addItem(item)
333
+
334
+ def add_object_to_list_no_check(self, obj): #added this to add non file objects to the list
335
+ item = QListWidgetItem(str(obj), self.list)
336
+ item.setToolTip(str(obj))
337
+ # item.setData(Qt.UserRole, obj)
338
+ # item.setData(Qt.UserRole, str(obj))
339
+ self._object_dict[str(item)] = obj # Store a reference to the object in the dictionary
340
+ self.list.addItem(item)
341
+
342
+ def add_to_list(self, files, check_if_supported=True):
343
+ if isinstance(files, str):
344
+ if check_if_supported:
345
+ self.add_file_to_list_if_supported(files)
346
+ else:
347
+ self.add_file_to_list_no_check(files)
348
+ elif isinstance(files, list):
349
+ for file in files:
350
+ if check_if_supported:
351
+ self.add_file_to_list_if_supported(file)
352
+ else:
353
+ self.add_file_to_list_no_check(file)
354
+ else:
355
+ print('Non supported, cannot be added to list', files)
356
+
357
+ def list_files_in_directory(self, directory_path):
358
+ files = [os.path.join(directory_path,f) for f in os.listdir(directory_path) if os.path.isfile(os.path.join(directory_path, f))]
359
+ # print(files)
360
+ return files
361
+
362
+ def add_file_to_list_if_supported(self, file):
363
+ # print('checking if supported', file)
364
+ if self.is_file_supported(file) and os.path.isfile(file):
365
+ ext = smart_name_parser(file, ordered_output=['ext'])[0].lower()
366
+ if ext in LISTS:
367
+ TA_list_of_files = loadlist(file)
368
+ return self.add_to_list(TA_list_of_files, check_if_supported=True)
369
+ else:
370
+ self.add_file_to_list_no_check(file)
371
+ elif self.enable_folder_DND and os.path.isdir(file):
372
+ files = self.list_files_in_directory(file)
373
+ for file in files:
374
+ self.add_file_to_list_if_supported(file)
375
+
376
+
377
+ def get_full_list(self):
378
+ # return the complete list of files
379
+ selected_items = []
380
+ for i in range(self.list.count()):
381
+ if str(self.list.item(i)) in self._object_dict:
382
+ selected_items.append(self._object_dict[str(self.list.item(i))])
383
+ else:
384
+ selected_items.append(self.list.item(i).toolTip())
385
+ return selected_items
386
+
387
+ def get_selection(self, mode='single'):
388
+ selected_items = self.list.selectedItems()
389
+ if selected_items:
390
+ if mode == 'single':
391
+ if str(selected_items[0]) in self._object_dict:
392
+ return self._object_dict[str(selected_items[0])]
393
+ # if selected_items[0].data(Qt.UserRole):
394
+ # return selected_items[0].data(Qt.UserRole)
395
+ return selected_items[0].toolTip()
396
+ else:
397
+ sel = []
398
+ for selec in selected_items:
399
+ if str(selec) in self._object_dict:
400
+ sel.append(self._object_dict[str(selec)])
401
+ # elif selec.data(Qt.UserRole):
402
+ # sel.append(selec.data(Qt.UserRole))
403
+ else:
404
+ sel.append(selec.toolTip())
405
+ return sel
406
+ else:
407
+ return None
408
+
409
+ def get_selection_index(self, mode='single'):
410
+ try:
411
+ # selected_items = self.list.selectedIndexes() # this is a weird model index object that is largely useless
412
+ selected_items = [s.row() for s in self.list.selectedIndexes()]
413
+ # print('selected_items',selected_items)
414
+ if selected_items:
415
+ if mode == 'single':
416
+ # print('sel', selected_items[0])
417
+ return selected_items[0]
418
+ else:
419
+ # sel = []
420
+ # for selec in selected_items:
421
+ # sel.append(selec.toolTip())
422
+ return selected_items
423
+ # else:
424
+ except:
425
+ pass
426
+ return None
427
+
428
+ def save_list(self):
429
+ # on va sauver la liste ici
430
+ lst = self.get_full_list()
431
+ if lst:
432
+ path = smart_name_parser(lst[0], ordered_output='parent')
433
+ path = os.path.join(path, 'list.lst')
434
+
435
+ output_file = saveFileDialog(parent_window=self, path=path,
436
+ extensions="Lists (*.lst);;Supported Files (*.lst *.txt);;All Files (*)",
437
+ default_ext='.lst')
438
+ if output_file is not None:
439
+ # now do save the list in the folder of the parent of the first file
440
+ save_list_to_file(lst, output_file)
441
+ # print(lst, output_file)
442
+
443
+ def removeSel(self):
444
+ selected_items = self.list.selectedItems()
445
+ self.list.clearSelection() # Clear selection # required to prevent selection from changing and the software to want to update display or anything alike
446
+ if not selected_items:
447
+ self.clearList()
448
+ self.deletePressed.emit() # send the delete action to the parent
449
+ return
450
+
451
+ # Remove selected items from the list
452
+ for item in selected_items:
453
+ # Remove the item from the dictionary
454
+ if str(item) in self._object_dict:
455
+ del self._object_dict[str(item)]
456
+ for item in selected_items:
457
+ # print('looping')
458
+ self.list.takeItem(self.list.row(item))
459
+ self.deletePressed.emit() # send the delete action to the parent
460
+
461
+ # faire une copie dans le clip de la selection
462
+ def sel_to_clipboard(self):
463
+ sel = self.get_selection(mode='all')
464
+ if sel is not None:
465
+ clip.copy('\n'.join(sel))
466
+
467
+ def paste_from_clipboard(self):
468
+ files = clip.paste()
469
+ # try add this to the list
470
+ try:
471
+ # print(files)
472
+ splitted_files = files.split('\n')
473
+ # print(splitted_files)
474
+ self.add_to_list(splitted_files, check_if_supported=True)
475
+ except:
476
+ # no big deal if fails
477
+ pass
478
+
479
+ # TODO maybe add sort by time as there is even an icon for that and can be useful for my leica files !!!
480
+ # TODO copy icons if they exist on natsort ok for now it's really a detail...
481
+ def natsort_list(self):
482
+ full_list = self.get_full_list()
483
+ if full_list is not None:
484
+ self.clearList()
485
+ self.add_to_list(natsorted(full_list), check_if_supported=False)
486
+
487
+ def clearList(self):
488
+ self.list.clear()
489
+ del self._object_dict
490
+ self._object_dict = {}
491
+
492
+
493
+ if __name__ == '__main__':
494
+ # TODO add a main method so it can be called directly
495
+ # maybe just show a canvas and give it interesting props --> TODO --> really need fix that too!!!
496
+ import sys
497
+ from qtpy.QtWidgets import QApplication
498
+
499
+ # should probably have his own scroll bar embedded somewhere
500
+
501
+ app = QApplication(sys.argv)
502
+
503
+ w = ListGUI(file_to_load='/E/Sample_images/sample_images_PA/mini/list.lst')
504
+
505
+ # w.freeze(False)
506
+ # w.freeze(True)
507
+
508
+ w.show()
509
+
510
+ print('get_full_list', w.get_full_list()) # very good and useful
511
+ print('sel', w.get_selection(mode='all'))
512
+
513
+ sys.exit(app.exec_())