~vincent-vandevyvre/oqapy/3.0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
# -*- coding: utf-8 -*-

# state.py
# This file is part of Oqapy serie 3
#
# Author: Vincent Vande Vyvre <vincent.vandevyvre@oqapy.eu>
# Home: http://www.oqapy.eu
# Copyright: 2014-2018 Vincent Vande Vyvre
# Licence: GPL3
#
# Define the context of the application


import threading
import logging
lgg = logging.getLogger(__name__)

from PyQt5.QtCore import QObject, Qt, QCoreApplication, pyqtSignal, QSize

class State(QObject):
    _instance = None
    _states = ['empty', 'viewing', 'sorting', 'fullscreen', 'filtering',
               'raw_viewing', 'multi_viewing']
    stateChanged = pyqtSignal(int)
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super(State, cls).__new__(cls, *args, **kwargs)
        return cls._instance

    def __init__(self, core):
        super().__init__()
        self.core = core
        self.ui = core.ui
        self.statusbar = core.ui.statusbar
        self.toolbar = core.ui.toolbar
        self.toolpanel = core.ui.toolpanel
        self.viewers = self.ui.stackedviews
        self.trailers = self.ui.stackedtrailers
        self.context = 0
        self.old_state = 0
        self.dock_visibility = self.toolpanel.isVisible()
        self.trailer_visibility = False
        self.filter_preview = False
        self.is_dual_screen = False

    @property
    def current_viewer(self):
        return self.viewers.viewing_area

    def set_current_state(self, state, force=False):
        """Sets the current state.

        Args:
        state -- index of the state;
                    0 No viewing, empty list of images
                    1 Mode viewing
                    2 Mode sorting
                    3 Mode full screen
                    4 Mode filtering
                    5 Mode RAW image edition
                    6 Mode multi views
        force -- if true reset the current state, needed at startup
        """
        lgg.info("Set current state: %s - %s" %(state, self._states[state]))
        if state == self.context and not force:
            return

        if self.context == 5 and state != 6:
            self.close_raw_editing()

        self.old_state = self.context
        if not state:
            self.set_no_images_state()

        elif state == 1:
            self.set_viewing_state()

        elif state == 2:
            self.set_sorting_state()

        elif state == 3:
            self.set_full_screen_state()

        elif state == 4:
            self.set_filtering_state(True)

        elif state == 5:
            self.set_raw_viewing_state()

        elif state == 6:
            self.set_multiviewing_state()

        self.context = state
        self.core.globalmenu.set_context(self.context)

    def set_no_images_state(self):
        lgg.info("Close source folder")
        self.trailers.clean_all()
        self.trailers.hide()
        self.toolbar.on_state_changed(0)
        self.viewers.on_state_changed(0)
        self.toolpanel.set_empty_state()
        self.statusbar.set_current_mode(0)
        self.viewers.viewing_area.clear()
        self.viewers.viewing_area.set_background()
        QCoreApplication.processEvents()

    def set_viewing_state(self):
        """Change to the viewing state.

        """
        lgg.info('Set viewing state')
        self.viewers.move_viewing_area(0)
        self.viewers.setCurrentIndex(0)
        self.trailers.setCurrentIndex(0)
        self.show_trailer(self.trailer_visibility)
        self.toolbar.on_state_changed(1)
        self.statusbar.set_current_mode(1)
        self.set_target_bar(False)
        self.toolpanel.enable_all_toolboxes(True)

    def set_sorting_state(self):
        """Change to the sorting mode.

        """
        lgg.info('Set sorting state')
        self.viewers.move_viewing_area(1)
        self.viewers.setCurrentIndex(1)
        self.trailers.setCurrentIndex(0)
        self.show_trailer(self.trailer_visibility)
        self.statusbar.set_current_mode(2)
        self.set_target_bar(True)

    def set_full_screen_state(self):
        """Change to the full screen view.

        """
        self.old_state = self.context
        if not self.old_state in (1, 5):
            # Need to change to viewing state before
            self.set_viewing_state()

        lgg.info('Set full screen state, old state: %s' % self.old_state)
        self.set_widgets(False)
        self.request_scrollBar(False)
        self.ui.showFullScreen()
        QCoreApplication.processEvents()
        self.current_viewer.setFocus(True)
        threading.Timer(0.2, self.fit_view).start()

    def exit_fullscreen(self):
        """Back from full screen mode

        """
        lgg.info('Exit full screen state, old state: %s' % self.old_state)
        self.ui.showNormal()
        self.set_widgets(True)
        QCoreApplication.processEvents()
        if self.old_state == 2:
            self.set_sorting_state()
            self.context = 2

        elif self.old_state == 5:
            self.core.set_raw_files_viewing()
            self.context = 5

        else:
            self.context = 1
        self.core.globalmenu.set_context(self.context)
        self.statusbar.set_current_mode(self.context)
        threading.Timer(0.2, self.fit_view).start()

    def set_filtering_state(self, state):
        """Sets or cancel the filtering state.

        Args:
        state -- boolean
        """
        self.enable_navigation_button(not state)
        if not state:
            lgg.info('Exit filtering state, old state: %s', self.old_state)
            self.viewers.viewing_header.set_filtered_mode(False)
            self.set_current_state(self.old_state, True)

        else:
            lgg.info('Set filtering state, current state: %s', self.context)
            self.old_state = self.context
            self.viewers.viewing_header.set_filtered_mode(True)

    def set_raw_viewing_state(self):
        lgg.info('Set raw editing state')
        self.old_state = self.context
        self.trailer_visibility = self.trailers.isVisible()
        if self.context == 2:
            self.viewers.move_viewing_area(0)
            self.viewers.setCurrentIndex(0)
            self.set_target_bar(False)

        self.trailers.setCurrentIndex(1)
        self.enable_tool_boxes(False)
        self.viewers.set_raw_header(True)
        self.toolpanel.set_raw_page_enabled(True)
        self.toolbar.on_state_changed(5)

    def close_raw_editing(self):
        lgg.info('Close raw editing state')
        self.core.rawviewer.close_rawfiles_viewing()
        self.enable_tool_boxes(True)
        self.toolpanel.raw_inquiries.clear()
        self.toolpanel.set_raw_page_enabled(False)
        self.core.trailer.is_raw_viewing = False
        self.core.trailer.on_trailer_completed()
        self.viewers.set_raw_header(False)
        self.toolbar.widget.multiviews_state_btn.setEnabled(True)
        # Avoid perpetual movement
        self.context = 0
        self.set_current_state(self.old_state)

    def set_raw_only(self, raw_only):
        self.toolpanel.set_raw_page_enabled(True)
        self.statusbar.set_raw_only(raw_only)
        self.core.globalmenu.set_raw_only(raw_only)
        if raw_only:
            self.enable_navigation_button(True)

    def set_multiviewing_state(self):
        lgg.info('Set multi viewing state')
        self.old_state = self.context
        if self.context == 2:
            self.viewers.set_sortingtab_multiviewing_mode()

        else:
            self.viewers.setCurrentIndex(3)

        self.trailer_visibility = self.trailers.isVisible()
        #self.set_target_bar(False)
        self.toolbar.on_state_changed(6)
        self.toolpanel.set_multiviewing_state()

    def close_multiviewing(self):
        lgg.info('Close multi viewing state, old state: %s' % self.old_state)
        self.enable_tool_boxes(True)
        self.core.multiviewing.clean_view()
        if self.old_state == 2:
            self.viewers.unset_sortingtab_multiviewing_mode()

    def enable_tool_boxes(self, enable):
        self.toolpanel.resize_bx.setEnabled(enable)
        self.toolpanel.crop_bx.setEnabled(enable)
        self.toolpanel.straighten_bx.setEnabled(enable)
        self.toolpanel.historic_bx.setEnabled(enable)
        self.toolpanel.contrast_bx.setEnabled(enable)
        self.toolpanel.stretching_bx.setEnabled(enable)
        self.toolpanel.denoising_bx.setEnabled(enable)
        self.toolpanel.grey_map_bx.setEnabled(enable)
        self.toolpanel.toning_bx.setEnabled(enable)
        self.toolpanel.laplace_bx.setEnabled(enable)

    def close_source_folder(self):
        if self.context == 6:
            self.close_multiviewing()
        self.set_no_images_state()

    def show_trailer(self, state=None):
        """Show - hide the trailer.

        Args:
        state -- if None, the old state is used, if True, the trailer is shown
                 otherwise it is hidden
        """
        if self.context == 4:
            self.show_raw_trailer(state)
            return

        lgg.info('Show trailer state: %s current: %s' 
                    % (state, self.context))
        if state is None:
            state = not self.trailers.isVisible()

        self.trailers.setVisible(state)

    def set_target_bar(self, visible):
        for i in range(self.core.cfg.get(('sorting', 'number'))):
            self.ui.targetarea.targets_buttons[i].setVisible(visible)

    def set_widgets(self, b):
        """Hide or show widgets when set or unset the full screen mode.

        Args:
        b -- True or False
        """
        self.toolpanel.setVisible(b)
        self.statusbar.widget.setVisible(b)
        self.toolbar.widget.setVisible(b)
        self.viewers.viewing_header.setVisible(b)
        if b:
            b = self.trailer_visibility

        self.trailers.setVisible(b)

    def enable_navigation_button(self, mode):
        """Enables the navigation and rotation buttons.

        Args:
        mode -- boolean, if True the buttons are enabled
        """
        self.toolbar.activate_navigation_widgets(mode)

    def freeze_tool_boxes(self, caller, freeze=True):
        lgg.info('Freeze tool boxes, caller: %s' %(caller))
        boxes = self.toolpanel.get_tool_boxes()
        if caller is not None:
            caller = caller.parent()

        for box in boxes:
            if box != caller:
                box.setEnabled(not freeze)

    def disable_undo_buttons(self, tool):
        lgg.info('Disable cancel buttons, caller: {0}'.format(tool))
        # Disable all undo buttons
        boxes = self.toolpanel.get_tool_boxes()
        for box in boxes:
            try:
                widget = box.layout.itemAt(1).widget()
            except AttributeError:
                # Case of box is splitter
                continue

            try:
                widget.cancel_btn.setEnabled(False)
            except AttributeError:
                # No cancel button
                continue

        # Enable undo button for the last change
        if tool is not None:
            if hasattr(tool, "cancel_btn"):
                # old style tool box
                tool.cancel_btn.setEnabled(True)

            elif hasattr(tool, "widget"):
                # new style tool box
                tool.widget.cancel_btn.setEnabled(True)

    def enable_raw_tools(self, enable):
        pass

    def request_scrollBar(self, b=None):
        """Show - hide scrollBars.

        Args:
        b -- boolean
        """
        if b is None:
            b = self.show_scrollbars

        if b:
            self.current_viewer.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
            self.current_viewer.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)

        else:
            self.current_viewer.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            self.current_viewer.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        self.show_scrollbars = b

    def fit_view(self):
        """Fit the current image to the viewer size.

        """
        # We can't call directly the function because we are into a thread
        self.toolbar.widget.zoom_tools.zoom_fit_btn.click()