/
ScriteDocumentView.qml
2829 lines (2480 loc) · 119 KB
/
ScriteDocumentView.qml
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
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/****************************************************************************
**
** Copyright (C) TERIFLIX Entertainment Spaces Pvt. Ltd. Bengaluru
** Author: Prashanth N Udupa (prashanth.udupa@teriflix.com)
**
** This code is distributed under GPL v3. Complete text of the license
** can be found here: https://www.gnu.org/licenses/gpl-3.0.txt
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
import QtQml 2.15
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Dialogs 1.3
import QtQuick.Layouts 1.15
import Qt.labs.settings 1.0
import QtQuick.Controls 2.15
import QtQuick.Controls.Material 2.15
import io.scrite.components 1.0
Item {
id: documentUI
width: 1350
height: 700
readonly property url helpUrl: "https://www.scrite.io/index.php/help/"
enabled: !Scrite.document.loading
FontMetrics {
id: sceneEditorFontMetrics
readonly property SceneElementFormat format: Scrite.document.formatting.elementFormat(SceneElement.Action)
readonly property int lettersPerLine: globalScreenplayEditorToolbar.editInFullscreen ? 70 : 60
readonly property int marginLetters: 5
readonly property real paragraphWidth: Math.ceil(lettersPerLine*averageCharacterWidth)
readonly property real paragraphMargin: Math.ceil(marginLetters*averageCharacterWidth)
readonly property real pageWidth: Math.ceil(paragraphWidth + 2*paragraphMargin)
font: format ? format.font2 : Scrite.document.formatting.defaultFont2
}
property bool canShowNotebookInStructure: width > 1600
property bool showNotebookInStructure: workspaceSettings.showNotebookInStructure && canShowNotebookInStructure
onShowNotebookInStructureChanged: {
Scrite.app.execLater(workspaceSettings, 100, function() {
mainTabBar.currentIndex = mainTabBar.currentIndex % (showNotebookInStructure ? 2 : 3)
})
}
AppFeature {
id: structureAppFeature
feature: Scrite.StructureFeature
}
AppFeature {
id: notebookAppFeature
feature: Scrite.NotebookFeature
}
AppFeature {
id: scritedAppFeature
feature: Scrite.ScritedFeature
}
AppFeature {
id: crgraphAppFeature
feature: Scrite.RelationshipGraphFeature
}
Settings {
id: applicationSettings
fileName: Scrite.app.settingsFilePath
category: "Application"
property bool enableAnimations: true
property bool useSoftwareRenderer: false
property string theme: "Material"
onEnableAnimationsChanged: applyAnimationSettings()
Component.onCompleted: applyAnimationSettings()
function applyAnimationSettings() {
modalDialog.animationsEnabled = enableAnimations
statusText.enableAnimations = enableAnimations
}
}
Settings {
id: workspaceSettings
fileName: Scrite.app.settingsFilePath
category: "Workspace"
property real workspaceHeight
property real screenplayEditorWidth: -1
property bool scriptalayIntroduced: false
property bool showNotebookInStructure: true
property bool syncCurrentSceneOnNotebook: true
property bool animateStructureIcon: true
property bool animateNotebookIcon: true
property real flickScrollSpeedFactor: 1.0
property bool showScritedTab: false
property bool mouseWheelZoomsInCharacterGraph: Scrite.app.isWindowsPlatform || Scrite.app.isLinuxPlatform
property bool mouseWheelZoomsInStructureCanvas: Scrite.app.isWindowsPlatform || Scrite.app.isLinuxPlatform
property string lastOpenFolderUrl: "file:///" + StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
property string lastOpenPhotosFolderUrl: "file:///" + StandardPaths.writableLocation(StandardPaths.PicturesLocation)
property string lastOpenImportFolderUrl: "file:///" + StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
property string lastOpenExportFolderUrl: "file:///" + StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
property string lastOpenReportsFolderUrl: "file:///" + StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
property string lastOpenScritedFolderUrl: "file:///" + StandardPaths.writableLocation(StandardPaths.MoviesLocation)
property var customColors: []
}
Settings {
id: screenplayEditorSettings
fileName: Scrite.app.settingsFilePath
category: "Screenplay Editor"
property bool displayRuler: true
property bool displaySceneCharacters: true
property bool displaySceneSynopsis: true
property bool displaySceneComments: false
property int mainEditorZoomValue: -1
property int embeddedEditorZoomValue: -1
property bool includeTitlePageInPreview: true
property bool enableSpellCheck: false // until we can fix https://github.com/teriflix/scrite/issues/138
property int lastLanguageRefreshNoticeBoxTimestamp: 0
property int lastSpellCheckRefreshNoticeBoxTimestamp: 0
property bool showLanguageRefreshNoticeBox: true
property bool showSpellCheckRefreshNoticeBox: true
property bool showLoglineEditor: false
property bool allowTaggingOfScenes: false
property real spaceBetweenScenes: 0
property int commentsPanelTabIndex: 1
property bool textFormatDockVisible: true
property bool pausePageAndTimeComputation: false
property bool highlightCurrentLine: true
property bool applyUserDefinedLanguageFonts: true
}
Settings {
id: paragraphLanguageSettings
fileName: Scrite.app.settingsFilePath
category: "Paragraph Language"
property string shotLanguage: "Default"
property string actionLanguage: "Default"
property string defaultLanguage: "English"
property string dialogueLanguage: "Default"
property string characterLanguage: "Default"
property string transitionLanguage: "Default"
property string parentheticalLanguage: "Default"
}
Settings {
id: notebookSettings
fileName: Scrite.app.settingsFilePath
category: "Notebook"
property int activeTab: 0 // 0 = Relationships, 1 = Notes
property int graphLayoutMaxTime: 1000
property int graphLayoutMaxIterations: 50000
property bool showAllFormQuestions: true
}
Settings {
id: helpNotificationSettings
fileName: Scrite.app.settingsFilePath
category: "Help"
property string dayZero
function daysSinceZero() {
const today = new Date()
const dzero = dayZero === "" ? today : new Date(dayZero + "Z")
const days = Math.floor((today.getTime() - dzero.getTime()) / (24*60*60*1000))
return days
}
property string tipsShown: ""
function isTipShown(val) {
const ts = tipsShown.split(",")
return ts.indexOf(val) >= 0
}
function markTipAsShown(val) {
var ts = tipsShown.length > 0 ? tipsShown.split(",") : []
if(ts.indexOf(val) < 0)
ts.push(val)
tipsShown = ts.join(",")
}
}
Shortcut {
context: Qt.ApplicationShortcut
sequence: "Ctrl+P"
ShortcutsModelItem.group: "Application"
ShortcutsModelItem.title: "Export To PDF"
ShortcutsModelItem.shortcut: sequence
onActivated: exportTimer.formatName = "Screenplay/Adobe PDF"
}
Shortcut {
context: Qt.ApplicationShortcut
sequence: "F1"
ShortcutsModelItem.group: "Application"
ShortcutsModelItem.title: "Help"
ShortcutsModelItem.shortcut: sequence
onActivated: Qt.openUrlExternally(helpUrl)
}
Shortcut {
id: sceneCharactersToggleShortcut
context: Qt.ApplicationShortcut
sequence: "Ctrl+Alt+C"
ShortcutsModelItem.group: "Settings"
ShortcutsModelItem.title: screenplayEditorSettings.displaySceneCharacters ? "Hide Scene Characters, Tags" : "Show Scene Characters, Tags"
ShortcutsModelItem.shortcut: sequence
onActivated: screenplayEditorSettings.displaySceneCharacters = !screenplayEditorSettings.displaySceneCharacters
}
Shortcut {
id: synopsisToggleShortcut
context: Qt.ApplicationShortcut
sequence: "Ctrl+Alt+S"
ShortcutsModelItem.group: "Settings"
ShortcutsModelItem.title: screenplayEditorSettings.displaySceneSynopsis ? "Hide Synopsis" : "Show Synopsis"
ShortcutsModelItem.shortcut: sequence
onActivated: screenplayEditorSettings.displaySceneSynopsis = !screenplayEditorSettings.displaySceneSynopsis
}
Shortcut {
id: commentsToggleShortcut
context: Qt.ApplicationShortcut
sequence: "Ctrl+Alt+M"
ShortcutsModelItem.group: "Settings"
ShortcutsModelItem.title: screenplayEditorSettings.displaySceneComments ? "Hide Comments" : "Show Comments"
ShortcutsModelItem.shortcut: sequence
onActivated: screenplayEditorSettings.displaySceneComments = !screenplayEditorSettings.displaySceneComments
}
Shortcut {
id: taggingToggleShortcut
context: Qt.ApplicationShortcut
sequence: "Ctrl+Alt+G"
ShortcutsModelItem.group: "Settings"
ShortcutsModelItem.title: screenplayEditorSettings.allowTaggingOfScenes ? "Allow Tagging" : "Disable Tagging"
ShortcutsModelItem.shortcut: sequence
onActivated: screenplayEditorSettings.allowTaggingOfScenes = !screenplayEditorSettings.allowTaggingOfScenes
}
Shortcut {
id: spellCheckToggleShortcut
context: Qt.ApplicationShortcut
sequence: "Ctrl+Alt+L"
ShortcutsModelItem.group: "Settings"
ShortcutsModelItem.title: screenplayEditorSettings.enableSpellCheck ? "Disable Spellcheck" : "Enable Spellcheck"
ShortcutsModelItem.shortcut: sequence
onActivated: screenplayEditorSettings.enableSpellCheck = !screenplayEditorSettings.enableSpellCheck
}
Shortcut {
context: Qt.ApplicationShortcut
sequence: "Ctrl+Alt+A"
ShortcutsModelItem.group: "Settings"
ShortcutsModelItem.title: applicationSettings.enableAnimations ? "Disable Animations" : "Enable Animations"
ShortcutsModelItem.shortcut: sequence
onActivated: applicationSettings.enableAnimations = !applicationSettings.enableAnimations
}
Shortcut {
context: Qt.ApplicationShortcut
sequence: "Ctrl+Shift+H"
ShortcutsModelItem.group: "Settings"
ShortcutsModelItem.title: screenplayEditorSettings.highlightCurrentLine ? "Line Highlight Off" : "Line Highlight On"
ShortcutsModelItem.shortcut: sequence
onActivated: screenplayEditorSettings.highlightCurrentLine = !screenplayEditorSettings.highlightCurrentLine
}
Shortcut {
context: Qt.ApplicationShortcut
sequence: "Ctrl+M"
ShortcutsModelItem.group: "Application"
ShortcutsModelItem.title: "New Scrite Window"
ShortcutsModelItem.enabled: true
ShortcutsModelItem.shortcut: sequence
ShortcutsModelItem.visible: enabled
onActivated: Scrite.app.launchNewInstance(Scrite.window)
}
Shortcut {
context: Qt.ApplicationShortcut
sequence: "Alt+1"
ShortcutsModelItem.group: "Application"
ShortcutsModelItem.title: "Screenplay"
ShortcutsModelItem.shortcut: sequence
onActivated: mainTabBar.activateTab(0)
}
Shortcut {
context: Qt.ApplicationShortcut
sequence: "Alt+2"
ShortcutsModelItem.group: "Application"
ShortcutsModelItem.title: "Structure"
ShortcutsModelItem.shortcut: sequence
onActivated: {
mainTabBar.activateTab(1)
if(showNotebookInStructure)
Announcement.shout("190B821B-50FE-4E47-A4B2-BDBB2A13B72C", "Structure")
}
}
Shortcut {
id: notebookShortcut
context: Qt.ApplicationShortcut
sequence: "Alt+3"
ShortcutsModelItem.group: "Application"
ShortcutsModelItem.title: "Notebook"
ShortcutsModelItem.shortcut: sequence
onActivated: {
if(showNotebookInStructure) {
if(mainTabBar.currentIndex === 1)
Announcement.shout("190B821B-50FE-4E47-A4B2-BDBB2A13B72C", "Notebook")
else {
mainTabBar.activateTab(1)
Scrite.app.execLater(mainTabBar, 250, function() {
Announcement.shout("190B821B-50FE-4E47-A4B2-BDBB2A13B72C", "Notebook")
})
}
} else
mainTabBar.activateTab(2)
}
property bool notebookTabVisible: mainTabBar.currentIndex === (showNotebookInStructure ? 1 : 2)
function showBookmarkedNotes() {
showNotes("Notebook Bookmarks")
}
function showStoryNotes() {
showNotes("Notebook Story")
}
function showCharacterNotes() {
showNotes("Notebook Characters")
}
function showNotes(type) {
var nbt = showNotebookInStructure ? 1 : 2
if(mainTabBar.currentIndex !== nbt) {
mainTabBar.activateTab(nbt)
Scrite.app.execLater(mainTabBar, 250, function() {
Announcement.shout("190B821B-50FE-4E47-A4B2-BDBB2A13B72C", type)
})
} else
Announcement.shout("190B821B-50FE-4E47-A4B2-BDBB2A13B72C", type)
}
}
Shortcut {
context: Qt.ApplicationShortcut
sequence: "Ctrl+Shift+K"
onActivated: notebookShortcut.showBookmarkedNotes()
ShortcutsModelItem.group: notebookShortcut.notebookTabVisible ? "Notebook" : "Application"
ShortcutsModelItem.title: "Bookmarked Notes"
ShortcutsModelItem.enabled: enabled
ShortcutsModelItem.shortcut: sequence
}
Shortcut {
context: Qt.ApplicationShortcut
sequence: "Ctrl+Shift+R"
onActivated: notebookShortcut.showCharacterNotes()
ShortcutsModelItem.group: notebookShortcut.notebookTabVisible ? "Notebook" : "Application"
ShortcutsModelItem.title: "Charater Notes"
ShortcutsModelItem.enabled: enabled
ShortcutsModelItem.shortcut: sequence
}
Shortcut {
context: Qt.ApplicationShortcut
sequence: "Ctrl+Shift+Y"
onActivated: notebookShortcut.showStoryNotes()
ShortcutsModelItem.group: notebookShortcut.notebookTabVisible ? "Notebook" : "Application"
ShortcutsModelItem.title: "Story Notes"
ShortcutsModelItem.enabled: enabled
ShortcutsModelItem.shortcut: sequence
}
Shortcut {
context: Qt.ApplicationShortcut
sequence: "Alt+4"
enabled: workspaceSettings.showScritedTab
ShortcutsModelItem.group: "Application"
ShortcutsModelItem.title: "Scrited"
ShortcutsModelItem.shortcut: sequence
ShortcutsModelItem.enabled: enabled
onActivated: mainTabBar.activateTab(3)
}
Connections {
target: Scrite.document
function onJustReset() {
instanceSettings.firstSwitchToStructureTab = true
appBusyOverlay.refCount = appBusyOverlay.refCount+1
screenplayAdapter.initialLoadTreshold = 25
Scrite.app.execLater(screenplayAdapter, 250, function() {
screenplayAdapter.sessionId = Scrite.document.sessionId
appBusyOverlay.refCount = Math.max(appBusyOverlay.refCount-1,0)
})
}
function onJustLoaded() {
instanceSettings.firstSwitchToStructureTab = true
var firstElement = Scrite.document.screenplay.elementAt(Scrite.document.screenplay.firstSceneIndex())
if(firstElement) {
var editorHints = firstElement.editorHints
if(editorHints) {
screenplayAdapter.initialLoadTreshold = -1
screenplayEditorSettings.displaySceneCharacters = editorHints.displaySceneCharacters
screenplayEditorSettings.displaySceneSynopsis = editorHints.displaySceneSynopsis
return
}
}
}
}
ScreenplayAdapter {
id: screenplayAdapter
property string sessionId
source: {
if(Scrite.document.sessionId !== sessionId)
return null
if(mainTabBar.currentIndex === 0)
return Scrite.document.screenplay
if(Scrite.document.screenplay.currentElementIndex < 0) {
var index = Scrite.document.structure.currentElementIndex
var element = Scrite.document.structure.elementAt(index)
if(element) {
if(element.scene.addedToScreenplay) {
Scrite.document.screenplay.currentElementIndex = element.scene.screenplayElementIndexList[0]
return Scrite.document.screenplay
}
return element.scene
}
}
return Scrite.document.screenplay
}
}
ScreenplayTextDocument {
id: screenplayTextDocument
screenplay: Scrite.document.loading || paused ? null : (editor ? screenplayAdapter.screenplay : null)
formatting: Scrite.document.loading || paused ? null : (editor ? Scrite.document.printFormat : null)
property bool paused: screenplayEditorSettings.pausePageAndTimeComputation
onPausedChanged: Qt.callLater( function() {
screenplayEditorSettings.pausePageAndTimeComputation = screenplayTextDocument.paused
})
syncEnabled: true
sceneNumbers: false
titlePage: false
sceneIcons: false
listSceneCharacters: false
includeSceneSynopsis: false
printEachSceneOnANewPage: false
secondsPerPage: Scrite.document.printFormat.secondsPerPage
property Item editor
property bool overlayRefCountModified: false
onUpdateScheduled: {
if(mainUndoStack.screenplayEditorActive || mainUndoStack.sceneEditorActive) {
appBusyOverlay.refCount = appBusyOverlay.refCount+1
overlayRefCountModified = true
}
}
onUpdateFinished: {
if(overlayRefCountModified)
appBusyOverlay.refCount = Math.max(appBusyOverlay.refCount-1,0)
overlayRefCountModified = false
}
Component.onCompleted: Scrite.app.registerObject(screenplayTextDocument, "screenplayTextDocument")
}
Rectangle {
id: appToolBarArea
anchors.left: parent.left
anchors.right: parent.right
height: 53
color: primaryColors.c50.background
visible: !pdfViewer.active
enabled: visible
Row {
id: appToolBar
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 5
visible: appToolBarArea.width >= 1280
onVisibleChanged: {
if(enabled && !visible)
mainTabBar.activateTab(0)
}
function saveQuestionText() {
if(Scrite.document.fileName === "")
return "Do you want to save this document first?"
return "Do you want to save changes to <strong>" + Scrite.app.fileName(Scrite.document.fileName) + "</strong> first?"
}
spacing: documentUI.width >= 1440 ? 2 : 0
ToolButton3 {
id: fileNewButton
iconSource: "../icons/action/description.png"
text: "New"
shortcut: "Ctrl+N"
shortcutText: "N"
onClicked: {
if(Scrite.document.autoSave && Scrite.document.fileName !== "")
Scrite.document.save()
if(Scrite.document.modified)
askQuestion({
"question": appToolBar.saveQuestionText(),
"okButtonText": "Yes",
"cancelButtonText": "No",
"abortButtonText": "Cancel",
"callback": function(val) {
if(val) {
if(Scrite.document.fileName !== "")
Scrite.document.save()
else {
cmdSave.doClick()
return
}
}
contentLoader.allowContent = false
Scrite.document.reset()
contentLoader.allowContent = true
Scrite.app.execLater(fileNewButton, 250, newFromTemplate)
}
}, fileNewButton)
else
newFromTemplate()
}
ShortcutsModelItem.group: "File"
ShortcutsModelItem.title: text
ShortcutsModelItem.shortcut: shortcut
}
ToolButton3 {
id: fileOpenButton
iconSource: "../icons/file/folder_open.png"
text: "Open"
shortcut: "Ctrl+O"
shortcutText: "O"
down: recentFilesMenu.visible
onClicked: recentFilesMenu.open()
function doOpen(filePath) {
if(filePath === Scrite.document.fileName)
return
if(Scrite.document.autoSave && Scrite.document.fileName !== "")
Scrite.document.save()
if(Scrite.document.modified)
askQuestion({
"question": appToolBar.saveQuestionText(),
"okButtonText": "Yes",
"cancelButtonText": "No",
"abortButtonText": "Cancel",
"callback": function(val) {
if(val) {
if(Scrite.document.fileName !== "")
Scrite.document.save()
else {
cmdSave.doClick()
return
}
}
recentFilesMenu.close()
if(filePath === "#TEMPLATE")
Scrite.app.execLater(fileOpenButton, 250, newFromTemplate)
else
fileDialog.launch("OPEN", filePath)
}
}, fileOpenButton)
else {
recentFilesMenu.close()
if(filePath === "#TEMPLATE")
Scrite.app.execLater(fileOpenButton, 250, newFromTemplate)
else
fileDialog.launch("OPEN", filePath)
}
}
Connections {
target: Scrite.app
function onOpenFileRequest(filePath) { fileOpenButton.doOpen(filePath) }
}
ShortcutsModelItem.group: "File"
ShortcutsModelItem.title: text
ShortcutsModelItem.shortcut: shortcut
Item {
anchors.top: parent.bottom
anchors.left: parent.left
Settings {
fileName: Scrite.app.settingsFilePath
category: "RecentFiles"
property alias files: recentFilesMenu.recentFiles
}
Menu2 {
id: recentFilesMenu
width: recentFiles.length > 1 ? 400 : 200
Connections {
target: Scrite.document
function onJustLoaded() { Qt.callLater( ()=> {
if(Scrite.document.fileName !== "")
recentFilesMenu.add(Scrite.document.fileName)
} )
}
}
property int nrRecentFiles: recentFiles.length
property var recentFiles: []
function add(filePath) {
if(filePath === "")
return
var r = recentFiles
if(r.length > 0 && r[r.length-1] === filePath)
return
for(var i=0; i<r.length; i++) {
if(r[i] === filePath)
r.splice(i,1);
}
r.push(filePath)
if(r.length > 10)
r.splice(0, r.length-10)
recentFiles = r
}
function prepareRecentFilesList() {
var newFiles = []
var filesDropped = false
recentFilesMenu.recentFiles.forEach(function(filePath) {
var fi = Scrite.app.fileInfo(filePath)
if(fi.exists)
newFiles.push(filePath)
else
filesDropped = true
})
if(filesDropped)
recentFilesMenu.recentFiles = newFiles
}
onAboutToShow: prepareRecentFilesList()
MenuItem2 {
text: "Open..."
onClicked: fileOpenButton.doOpen()
}
MenuItem2 {
text: "Restore"
enabled: Scrite.vault.documentCount > 0
onClicked: {
modalDialog.closeable = false
modalDialog.closeOnEscape = true
modalDialog.popupSource = fileOpenButton
modalDialog.sourceComponent = documentVaultDialogBox
modalDialog.active = true
}
Rectangle {
width: parent.width; height: 1
anchors.bottom: parent.bottom
color: primaryColors.borderColor
}
}
FontMetrics {
id: recentFilesFontMetrics
}
Repeater {
model: recentFilesMenu.recentFiles
MenuItem2 {
property string filePath: recentFilesMenu.recentFiles[recentFilesMenu.nrRecentFiles-index-1]
property var fileInfo: Scrite.app.fileInfo(filePath)
text: recentFilesFontMetrics.elidedText(fileInfo.baseName, Qt.ElideMiddle, recentFilesMenu.width)
ToolTip.text: filePath
ToolTip.visible: hovered
onClicked: fileOpenButton.doOpen(filePath)
}
}
}
}
}
ToolButton3 {
id: backupOpenButton
iconSource: "../icons/file/backup_open.png"
text: "Open Backup"
visible: Scrite.document.backupFilesModel.count > 0
onClicked: {
modalDialog.closeable = false
modalDialog.closeOnEscape = true
modalDialog.popupSource = backupOpenButton
modalDialog.sourceComponent = backupsDialogBoxComponent
modalDialog.active = true
}
ToolTip.text: "Open any of the " + Scrite.document.backupFilesModel.count + " backup(s) available for this file."
Text {
id: backupCountHint
font.pixelSize: parent.height * 0.2
font.bold: true
text: Scrite.document.backupFilesModel.count
padding: 2
color: primaryColors.highlight.text
anchors.bottom: parent.bottom
anchors.right: parent.right
}
}
ToolButton3 {
id: cmdSave
iconSource: "../icons/content/save.png"
text: "Save"
shortcut: "Ctrl+S"
shortcutText: "S"
enabled: Scrite.document.modified && !Scrite.document.readOnly
onClicked: doClick()
function doClick() {
if(Scrite.document.fileName === "")
fileDialog.launch("SAVE")
else {
fileDialog.mode = "SAVE"
Scrite.document.save()
}
}
ShortcutsModelItem.group: "File"
ShortcutsModelItem.title: text
ShortcutsModelItem.enabled: enabled
ShortcutsModelItem.shortcut: shortcut
}
ToolButton3 {
text: "Save As"
shortcut: "Ctrl+Shift+S"
shortcutText: "Shift+S"
iconSource: "../icons/content/save_as.png"
onClicked: fileDialog.launch("SAVE")
enabled: Scrite.document.structure.elementCount > 0 ||
Scrite.document.structure.noteCount > 0 ||
Scrite.document.structure.annotationCount > 0 ||
Scrite.document.screenplay.elementCount > 0
ShortcutsModelItem.group: "File"
ShortcutsModelItem.title: text
ShortcutsModelItem.shortcut: shortcut
}
ToolButton3 {
id: openFromLibrary
iconSource: "../icons/action/library.png"
text: "<img src=\"qrc:/images/library_woicon_inverted.png\" height=\"30\" width=\"107\">\t "
shortcut: "Ctrl+Shift+O"
shortcutText: "Shift+O"
function go() {
modalDialog.closeable = false
modalDialog.popupSource = openFromLibrary
modalDialog.sourceComponent = openFromLibraryComponent
modalDialog.active = true
}
onClicked: {
if(Scrite.document.autoSave && Scrite.document.fileName !== "")
Scrite.document.save()
if(Scrite.document.modified)
askQuestion({
"question": appToolBar.saveQuestionText(),
"okButtonText": "Yes",
"cancelButtonText": "No",
"abortButtonText": "Cancel",
"callback": function(val) {
if(val) {
if(Scrite.document.fileName !== "")
Scrite.document.save()
else {
cmdSave.doClick()
return
}
}
Scrite.app.execLater(openFromLibrary, 250, function() { openFromLibrary.go() })
}
}, fileNewButton)
else
openFromLibrary.go()
}
ShortcutsModelItem.group: "File"
ShortcutsModelItem.title: "<img src=\"qrc:/images/library_woicon.png\" height=\"30\" width=\"107\">"
ShortcutsModelItem.shortcut: shortcut
}
Rectangle {
width: 1
height: parent.height
color: primaryColors.separatorColor
opacity: 0.5
}
/*
Most users already know that Ctrl+Z is undo and Ctrl+Y is redo.
Therefore simply listing these shortcuts in shortcuts dockwidget
should be sufficient to establish their existence. Showing these
toolbuttons is robbing us of some really good screenspace.
*/
QtObject {
ShortcutsModelItem.group: "Edit"
ShortcutsModelItem.title: "Undo"
ShortcutsModelItem.enabled: Scrite.app.canUndo && !Scrite.document.readOnly // enabled
ShortcutsModelItem.shortcut: "Ctrl+Z" // shortcut
}
QtObject {
ShortcutsModelItem.group: "Edit"
ShortcutsModelItem.title: "Redo"
ShortcutsModelItem.enabled: Scrite.app.canRedo && !Scrite.document.readOnly // enabled
ShortcutsModelItem.shortcut: Scrite.app.isMacOSPlatform ? "Ctrl+Shift+Z" : "Ctrl+Y" // shortcut
}
ToolButton3 {
id: importExportButton
iconSource: "../icons/file/import_export.png"
text: "Import, Export & Reports"
onClicked: importExportMenu.visible = true
down: importExportMenu.visible
Item {
anchors.top: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
Menu2 {
id: importExportMenu
Menu2 {
id: importMenu
title: "Import"
Repeater {
model: Scrite.document.supportedImportFormats
MenuItem2 {
id: importMenuItem
text: modelData
onClicked: click()
function click() {
if(Scrite.document.autoSave && Scrite.document.fileName !== "")
Scrite.document.save()
if(Scrite.document.modified)
askQuestion({
"question": "Do you want to save your current project first?",
"okButtonText": "Yes",
"cancelButtonText": "No",
"callback": function(val) {
if(val) {
if(Scrite.document.fileName !== "")
Scrite.document.save()
else {
cmdSave.doClick()
return
}
}
fileDialog.launch("IMPORT " + modelData)
}
}, importMenuItem)
else
fileDialog.launch("IMPORT " + modelData)
}
}
}
}
Menu2 {
id: exportMenu
title: "Export"
width: 250
Component {
id: menuItemComponent
MenuItem2 {
property string format
text: {
var fields = format.split("/")
return fields[fields.length-1]
}
function click() { exportTimer.formatName = format }
onClicked: click()
}
}
Component {
id: menuSeparatorComponent
MenuSeparator { }
}
Component.onCompleted: {
var formats = Scrite.document.supportedExportFormats
for(var i=0; i<formats.length; i++) {
var format = formats[i]
if(format === "")
exportMenu.addItem(menuSeparatorComponent.createObject(exportMenu))
else
exportMenu.addItem(menuItemComponent.createObject(exportMenu, {"format": format}))
}
}
}
Menu2 {
id: reportsMenu
title: "Reports"
enabled: Scrite.document.screenplay.elementCount > 0
width: 300
Repeater {
model: Scrite.document.supportedReports
MenuItem2 {
leftPadding: 15
rightPadding: 15
topPadding: 5
bottomPadding: 5
width: reportsMenu.width
height: 65
contentItem: Column {
id: menuContent
width: reportsMenu.width - 30
spacing: 5
Text {
font.bold: true
font.pixelSize: 16
text: modelData.name
}
Text {
text: modelData.description
width: parent.width
wrapMode: Text.WordWrap
font.pixelSize: 12
font.italic: true
}
}
function click() {
reportGeneratorTimer.reportArgs = modelData.name
}
onTriggered: click()
}
}
}
}
Timer {
id: exportTimer
objectName: "ScriteDocumentView.exportTimer"
property string formatName
repeat: false
interval: 10
onFormatNameChanged: {
if(formatName !== "")
start()
}
onTriggered: {
if(formatName !== "") {
modalDialog.closeable = false
modalDialog.arguments = formatName
modalDialog.sourceComponent = exporterConfigurationComponent
modalDialog.popupSource = importExportButton
modalDialog.active = true
}
formatName = ""