Fuel

Changes On Branch new-workspace
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch new-workspace Excluding Merge-Ins

This is equivalent to a diff from 54059126ae to 7ebac37b32

2015-05-26
18:03
Merged new workspace check-in: 322729110f user: kostas tags: trunk
2015-05-25
12:27
Initial work on remote management check-in: 13d3a5222d user: kostas tags: remote-management
2015-05-24
18:37
Removed Create Stash from toolbar Changed "Open Containing" icon Minor cosmetic changes Closed-Leaf check-in: 7ebac37b32 user: kostas tags: new-workspace
18:19
Separated Application and Fossil settings into separate dialogs. check-in: 97d0d1e240 user: kostas tags: new-workspace
2015-04-30
17:43
Merged refactor Added missing status UPDATED_BY_MERGE Fixed parsing of file status check-in: f82fab4145 user: kostas tags: new-workspace
16:23
Renamed tableView to fileTableView Renamed treeView to workspaceTreeView Renamed tableViewStash to stashTableView Closed-Leaf check-in: 54059126ae user: kostas tags: refactor
12:15
Renamed Bridge to Fossil check-in: 77abfe4126 user: kostas tags: refactor

Changes to fuel.pro.
1
2
3
4
5

6
7
8

9
10
11
12
13
14
15
1
2
3
4

5
6
7
8
9
10
11
12
13
14
15
16




-
+



+







#-------------------------------------------------
# Fuel
#-------------------------------------------------

QT    += core gui webkit
QT    = core gui webkit

contains(QT_VERSION, ^5\\..*) {
	QT += widgets webkitwidgets
	QT -= quick multimediawidgets opengl printsupport qml multimedia positioning sensors
}

TARGET = Fuel
TEMPLATE = app

win32 {
	RC_FILE = rsrc/fuel.rc
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
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







+
+
+


-




-
+
+
+





+
+
+


-




-
+
+
+





+

-
+
+







INCLUDEPATH += src

SOURCES += src/main.cpp\
	src/MainWindow.cpp \
	src/CommitDialog.cpp \
	src/FileActionDialog.cpp \
	src/SettingsDialog.cpp \
	src/FslSettingsDialog.cpp \
	src/CloneDialog.cpp \
	src/RevisionDialog.cpp \
	src/Utils.cpp \
	src/FileTableView.cpp \
	src/CloneDialog.cpp \
	src/LoggedProcess.cpp \
	src/BrowserWidget.cpp \
	src/CustomWebView.cpp \
	src/Fossil.cpp \
    src/Workspace.cpp
	src/Workspace.cpp \
	src/SearchBox.cpp \
	src/Settings.cpp

HEADERS  += src/MainWindow.h \
	src/CommitDialog.h \
	src/FileActionDialog.h \
	src/SettingsDialog.h \
	src/FslSettingsDialog.h \
	src/CloneDialog.h \
	src/RevisionDialog.h \
	src/Utils.h \
	src/FileTableView.h \
	src/CloneDialog.h \
	src/LoggedProcess.h \
	src/BrowserWidget.h \
	src/CustomWebView.h \
	src/Fossil.h \
    src/Workspace.h
	src/Workspace.h \
	src/SearchBox.h \
	src/Settings.h

FORMS    += ui/MainWindow.ui \
	ui/CommitDialog.ui \
	ui/FileActionDialog.ui \
	ui/SettingsDialog.ui \
	ui/FslSettingsDialog.ui \
	ui/CloneDialog.ui \
	ui/BrowserWidget.ui
	ui/BrowserWidget.ui \
	ui/RevisionDialog.ui

RESOURCES += \
	rsrc/resources.qrc

CODECFORTR = UTF-8

TRANSLATIONS += \
Changes to rsrc/resources.qrc.
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
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

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

<RCC>
	<qresource prefix="/icons">
		<file>icons/Address Book-01.png</file>
		<file>icons/Adobe Illustrator CS3 Document-01.png</file>
		<file>icons/Adobe PDF Document-01.png</file>
		<file>icons/Adobe Photoshop CS3 Document-01.png</file>
		<file>icons/Battery-01.png</file>
		<file>icons/Binoculars-01.png</file>
		<file>icons/Book-01.png</file>
		<file>icons/Briefcase-01.png</file>
		<file>icons/Button Add-01.png</file>
		<file>icons/Button Blank Blue-01.png</file>
		<file>icons/Button Blank Gray-01.png</file>
		<file>icons/Button Blank Green-01.png</file>
		<file>icons/Button Blank Red-01.png</file>
		<file>icons/Button Blank Yellow-01.png</file>
		<file>icons/Button Cancel-01.png</file>
		<file>icons/Button Close-01.png</file>
		<file>icons/Button Delete-01.png</file>
		<file>icons/Button Download-01.png</file>
		<file>icons/Button Favorite-01.png</file>
		<file>icons/Button Forward-01.png</file>
		<file>icons/Button Help-01.png</file>
		<file>icons/Button Info-01.png</file>
		<file>icons/Button Log Off-01.png</file>
		<file>icons/Button Next-01.png</file>
		<file>icons/Button Pause-01.png</file>
		<file>icons/Button Play-01.png</file>
		<file>icons/Button Previous-01.png</file>
		<file>icons/Button Refresh-01.png</file>
		<file>icons/Button Reload-01.png</file>
		<file>icons/Button Reminder-01.png</file>
		<file>icons/Button Rewind-01.png</file>
		<file>icons/Button Talk Balloon-01.png</file>
		<file>icons/Button Turn Off-01.png</file>
		<file>icons/Button Turn On-01.png</file>
		<file>icons/Button Upload-01.png</file>
		<file>icons/Button Warning-01.png</file>
		<file>icons/Calculator-01.png</file>
		<file>icons/Calendar Blue-01.png</file>
		<file>icons/Calendar Green-01.png</file>
		<file>icons/Calendar Red-01.png</file>
		<file>icons/Clipboard-01.png</file>
		<file>icons/Clipboard Paste-01.png</file>
		<file>icons/Clock-01.png</file>
		<file>icons/Coin-01.png</file>
		<file>icons/Compressed File RAR-01.png</file>
		<file>icons/Compressed File SIT-01.png</file>
		<file>icons/Compressed File Zip-01.png</file>
		<file>icons/Computer Monitor-01.png</file>
		<file>icons/Computer Network-01.png</file>
		<file>icons/Document-01.png</file>
		<file>icons/Document Attach-01.png</file>
		<file>icons/Document Blank-01.png</file>
		<file>icons/Document Chart-01.png</file>
		<file>icons/Document Copy-01.png</file>
		<file>icons/Document Flow Chart-01.png</file>
		<file>icons/Document Gant Chart-01.png</file>
		<file>icons/Document Help-01.png</file>
		<file>icons/Document Line Chart-01.png</file>
		<file>icons/Document Microsoft Excel-01.png</file>
		<file>icons/Document Microsoft PowerPoint-01.png</file>
		<file>icons/Document Microsoft Word-01.png</file>
		<file>icons/Document Organization Chart-01.png</file>
		<file>icons/Document Preview-01.png</file>
		<file>icons/Document-Revert-icon.png</file>
		<file>icons/Document Text-01.png</file>
		<file>icons/Edit Document-01.png</file>
		<file>icons/Email-01.png</file>
		<file>icons/Email Attachment-01.png</file>
		<file>icons/Email Delete-01.png</file>
		<file>icons/Email Download-01.png</file>
		<file>icons/Email Forward-01.png</file>
		<file>icons/Email Inbox-01.png</file>
		<file>icons/Email Reply-01.png</file>
		<file>icons/File Audio-01.png</file>
		<file>icons/File Audio AIFF-01.png</file>
		<file>icons/File Audio MP3-01.png</file>
		<file>icons/File Audio WAV-01.png</file>
		<file>icons/File Audio WMA-01.png</file>
		<file>icons/File Delete-01.png</file>
		<file>icons/File History-01.png</file>
		<file>icons/File New-01.png</file>
		<file>icons/File Open-01.png</file>
		<file>icons/File Video 3GP-01.png</file>
		<file>icons/File Video-01.png</file>
		<file>icons/File Video AVI-01.png</file>
		<file>icons/File Video MOV-01.png</file>
		<file>icons/File Video MPEG-01.png</file>
		<file>icons/File Video WMV-01.png</file>
		<file>icons/Folder-01.png</file>
		<file>icons/Folder Add-01.png</file>
		<file>icons/Folder Compressed-01.png</file>
		<file>icons/Folder Delete-01.png</file>
		<file>icons/Folder Explorer-01.png</file>
		<file>icons/Folder Generic Blue-01.png</file>
		<file>icons/Folder Generic Green-01.png</file>
		<file>icons/Folder Generic Red-01.png</file>
		<file>icons/Folder Generic Silver-01.png</file>
		<file>icons/Folder Open-01.png</file>
		<file>icons/Folder RAR-01.png</file>
		<file>icons/Games-01.png</file>
		<file>icons/Gear-01.png</file>
		<file>icons/Highlighter Blue-01.png</file>
		<file>icons/Highlighter Green-01.png</file>
		<file>icons/Highlighter Yellow-01.png</file>
		<file>icons/Image BMP-01.png</file>
		<file>icons/Image GIF-01.png</file>
		<file>icons/Image JPEG-01.png</file>
		<file>icons/Image PNG-01.png</file>
		<file>icons/Image TIFF-01.png</file>
		<file>icons/Lock Lock-01.png</file>
		<file>icons/Lock Unlock-01.png</file>
		<file>icons/My Documents-01.png</file>
		<file>icons/My Ebooks-01.png</file>
		<file>icons/My Music-01.png</file>
		<file>icons/My Pictures.png</file>
		<file>icons/My Videos-01.png</file>
		<file>icons/My Websites-01.png</file>
		<file>icons/Network Firewall-01.png</file>
		<file>icons/Network MAC-01.png</file>
		<file>icons/Network PC-01.png</file>
		<file>icons/Network Refresh-01.png</file>
		<file>icons/Pen Blue-01.png</file>
		<file>icons/Pen Green-01.png</file>
		<file>icons/Pen Red-01.png</file>
		<file>icons/Save-01.png</file>
		<file>icons/Text Edit.png</file>
		<file>icons/USB-01.png</file>
		<file>icons/User Administrator Blue-01.png</file>
		<file>icons/User Administrator Green-01.png</file>
		<file>icons/User Administrator Red-01.png</file>
		<file>icons/User Chat-01.png</file>
		<file>icons/User Clients-01.png</file>
		<file>icons/User Coat Blue-01.png</file>
		<file>icons/User Coat Green-01.png</file>
		<file>icons/User Coat Red-01.png</file>
		<file>icons/User Executive Blue-01.png</file>
		<file>icons/User Executive Green-01.png</file>
		<file>icons/User Executive Red-01.png</file>
		<file>icons/User Group-01.png</file>
		<file>icons/User Preppy Blue-01.png</file>
		<file>icons/User Preppy Green-01.png</file>
		<file>icons/User Preppy Red-01.png</file>
		<file>icons/Web HTML-01.png</file>
		<file>icons/Web XML-01.png</file>
		<file>icons/Window-01.png</file>
		<file>icons/Window Refresh-01.png</file>
		<file>icons/Windows-01.png</file>
		<file>icons/Windows Cascade-01.png</file>
		<file>icons/Zoom-01.png</file>
		<file>icons/Zoom In-01.png</file>
		<file>icons/Zoom Out-01.png</file>
	</qresource>
	<qresource prefix="/intl">
		<file>intl/el_GR.qm</file>
		<file>intl/de_DE.qm</file>
		<file>intl/es_ES.qm</file>
		<file>intl/fr_FR.qm</file>
		<file>intl/ru_RU.qm</file>
		<file>intl/pt_PT.qm</file>
	</qresource>
  <qresource prefix="/icons">
	<file>icons/Address Book-01.png</file>
	<file>icons/Adobe Illustrator CS3 Document-01.png</file>
	<file>icons/Adobe PDF Document-01.png</file>
	<file>icons/Adobe Photoshop CS3 Document-01.png</file>
	<file alias="icon-application">icons/Battery-01.png</file>
	<file>icons/Binoculars-01.png</file>
	<file alias="icon-item-tag">icons/Book-01.png</file>
	<file>icons/Briefcase-01.png</file>
	<file alias="icon-item-added">icons/Button Add-01.png</file>
	<file>icons/Button Blank Blue-01.png</file>
	<file alias="icon-item-unknown">icons/Button Blank Gray-01.png</file>
	<file alias="icon-item-unchanged">icons/Button Blank Green-01.png</file>
	<file alias="icon-item-conflicted">icons/Button Blank Red-01.png</file>
	<file alias="icon-item-edited">icons/Button Blank Yellow-01.png</file>
	<file>icons/Button Cancel-01.png</file>
	<file alias="icon-item-deleted">icons/Button Close-01.png</file>
	<file alias="icon-action-tag-delete">icons/Button Close-01.png</file>
	<file alias="icon-action-stop">icons/Button Close-01.png</file>
	<file>icons/Button Delete-01.png</file>
	<file alias="icon-action-pull">icons/Button Download-01.png</file>
	<file>icons/Button Favorite-01.png</file>
	<file>icons/Button Forward-01.png</file>
	<file alias="icon-item-missing">icons/Button Help-01.png</file>
	<file>icons/Button Info-01.png</file>
	<file>icons/Button Log Off-01.png</file>
	<file alias="icon-action-next">icons/Button Next-01.png</file>
	<file>icons/Button Pause-01.png</file>
	<file alias="icon-action-update">icons/Button Play-01.png</file>
	<file alias="icon-action-previous">icons/Button Previous-01.png</file>
	<file alias="icon-action-refresh">icons/Button Refresh-01.png</file>
	<file alias="icon-action-undo">icons/Button Reload-01.png</file>
	<file alias="icon-item-renamed">icons/Button Reload-01.png</file>
	<file>icons/Button Reminder-01.png</file>
	<file alias="icon-action-revert">icons/Button Rewind-01.png</file>
	<file>icons/Button Talk Balloon-01.png</file>
	<file alias="icon-action-quit">icons/Button Turn Off-01.png</file>
	<file>icons/Button Turn On-01.png</file>
	<file alias="icon-action-push">icons/Button Upload-01.png</file>
	<file>icons/Button Warning-01.png</file>
	<file>icons/Calculator-01.png</file>
	<file>icons/Calendar Blue-01.png</file>
	<file>icons/Calendar Green-01.png</file>
	<file>icons/Calendar Red-01.png</file>
	<file>icons/Clipboard-01.png</file>
	<file>icons/Clipboard Paste-01.png</file>
	<file alias="icon-action-timeline">icons/Clock-01.png</file>
	<file>icons/Coin-01.png</file>
	<file>icons/Compressed File RAR-01.png</file>
	<file>icons/Compressed File SIT-01.png</file>
	<file>icons/Compressed File Zip-01.png</file>
	<file>icons/Computer Monitor-01.png</file>
	<file>icons/Computer Network-01.png</file>
	<file alias="icon-item-file">icons/Document-01.png</file>
	<file>icons/Document Attach-01.png</file>
	<file alias="icon-action-repo-new">icons/Document Blank-01.png</file>
	<file>icons/Document Chart-01.png</file>
	<file alias="icon-item-diff">icons/Document Copy-01.png</file>
	<file alias="icon-action-merge">icons/Document Flow Chart-01.png</file>
	<file>icons/Document Gant Chart-01.png</file>
	<file>icons/Document Help-01.png</file>
	<file>icons/Document Line Chart-01.png</file>
	<file>icons/Document Microsoft Excel-01.png</file>
	<file>icons/Document Microsoft PowerPoint-01.png</file>
	<file>icons/Document Microsoft Word-01.png</file>
	<file alias="icon-item-branch">icons/Document Organization Chart-01.png</file>
	<file>icons/Document Preview-01.png</file>
	<file alias="icon-item-revert">icons/Document-Revert-icon.png</file>
	<file>icons/Document Text-01.png</file>
	<file>icons/Edit Document-01.png</file>
	<file>icons/Email-01.png</file>
	<file>icons/Email Attachment-01.png</file>
	<file>icons/Email Delete-01.png</file>
	<file>icons/Email Download-01.png</file>
	<file>icons/Email Forward-01.png</file>
	<file>icons/Email Inbox-01.png</file>
	<file>icons/Email Reply-01.png</file>
	<file>icons/File Audio-01.png</file>
	<file>icons/File Audio AIFF-01.png</file>
	<file>icons/File Audio MP3-01.png</file>
	<file>icons/File Audio WAV-01.png</file>
	<file>icons/File Audio WMA-01.png</file>
	<file alias="icon-item-delete">icons/File Delete-01.png</file>
	<file alias="icon-item-history">icons/File History-01.png</file>
	<file alias="icon-item-add">icons/File New-01.png</file>
	<file alias="icon-item-rename">icons/File Open-01.png</file>
	<file>icons/File Video 3GP-01.png</file>
	<file>icons/File Video-01.png</file>
	<file>icons/File Video AVI-01.png</file>
	<file>icons/File Video MOV-01.png</file>
	<file>icons/File Video MPEG-01.png</file>
	<file>icons/File Video WMV-01.png</file>
	<file alias="icon-item-folder">icons/Folder-01.png</file>
	<file alias="icon-action-stash-new">icons/Folder Add-01.png</file>
	<file alias="icon-action-stash-apply">icons/Folder Compressed-01.png</file>
	<file alias="icon-action-stash-delete">icons/Folder Delete-01.png</file>
	<file alias="icon-action-stash-diff">icons/Folder Explorer-01.png</file>
	<file alias="icon-action-folder-explore">icons/Folder Explorer-01.png</file>
	<file>icons/Folder Generic Blue-01.png</file>
	<file>icons/Folder Generic Green-01.png</file>
	<file>icons/Folder Generic Red-01.png</file>
	<file>icons/Folder Generic Silver-01.png</file>
	<file alias="icon-action-folder-rename">icons/Folder Open-01.png</file>
	<file>icons/Folder RAR-01.png</file>
	<file>icons/Games-01.png</file>
	<file alias="icon-action-settings">icons/Gear-01.png</file>
	<file>icons/Highlighter Blue-01.png</file>
	<file>icons/Highlighter Green-01.png</file>
	<file alias="icon-action-tag-new">icons/Highlighter Yellow-01.png</file>
	<file>icons/Image BMP-01.png</file>
	<file>icons/Image GIF-01.png</file>
	<file>icons/Image JPEG-01.png</file>
	<file>icons/Image PNG-01.png</file>
	<file>icons/Image TIFF-01.png</file>
	<file>icons/Lock Lock-01.png</file>
	<file>icons/Lock Unlock-01.png</file>
	<file alias="icon-action-repo-open">icons/My Documents-01.png</file>
	<file>icons/My Ebooks-01.png</file>
	<file>icons/My Music-01.png</file>
	<file>icons/My Pictures.png</file>
	<file>icons/My Videos-01.png</file>
	<file alias="icon-action-repo-clone">icons/My Websites-01.png</file>
	<file>icons/Network Firewall-01.png</file>
	<file alias="icon-webview">icons/Network MAC-01.png</file>
	<file alias="icon-item-remote" >icons/Network PC-01.png</file>
	<file>icons/Network Refresh-01.png</file>
	<file>icons/Pen Blue-01.png</file>
	<file>icons/Pen Green-01.png</file>
	<file>icons/Pen Red-01.png</file>
	<file alias="icon-action-commit">icons/Save-01.png</file>
	<file alias="icon-clear-log">icons/Text Edit.png</file>
	<file>icons/USB-01.png</file>
	<file>icons/User Administrator Blue-01.png</file>
	<file>icons/User Administrator Green-01.png</file>
	<file>icons/User Administrator Red-01.png</file>
	<file>icons/User Chat-01.png</file>
	<file>icons/User Clients-01.png</file>
	<file>icons/User Coat Blue-01.png</file>
	<file>icons/User Coat Green-01.png</file>
	<file>icons/User Coat Red-01.png</file>
	<file>icons/User Executive Blue-01.png</file>
	<file>icons/User Executive Green-01.png</file>
	<file>icons/User Executive Red-01.png</file>
	<file>icons/User Group-01.png</file>
	<file>icons/User Preppy Blue-01.png</file>
	<file>icons/User Preppy Green-01.png</file>
	<file>icons/User Preppy Red-01.png</file>
	<file>icons/Web HTML-01.png</file>
	<file>icons/Web XML-01.png</file>
	<file>icons/Window-01.png</file>
	<file>icons/Window Refresh-01.png</file>
	<file>icons/Windows-01.png</file>
	<file>icons/Windows Cascade-01.png</file>
	<file>icons/Zoom-01.png</file>
	<file>icons/Zoom In-01.png</file>
	<file>icons/Zoom Out-01.png</file>
  </qresource>
  <qresource prefix="/intl">
	<file>intl/el_GR.qm</file>
	<file>intl/de_DE.qm</file>
	<file>intl/es_ES.qm</file>
	<file>intl/fr_FR.qm</file>
	<file>intl/ru_RU.qm</file>
	<file>intl/pt_PT.qm</file>
  </qresource>
</RCC>
Changes to src/CommitDialog.cpp.
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
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






-
+










-
-
+
+


-
+
-
-
-
+
+
-
-







#include "CommitDialog.h"
#include <QPushButton>
#include <QShortcut>
#include "ui_CommitDialog.h"
#include "MainWindow.h" // Ugly. I know.

CommitDialog::CommitDialog(QWidget *parent, QString title, QStringList &files, const QStringList *history, bool singleLineEntry, const QString *checkBoxText, bool *checkBoxValue) :
CommitDialog::CommitDialog(QWidget *parent, const QString &title, QStringList &files, const QStringList *history, bool stashMode) :
	QDialog(parent, Qt::Sheet),
	ui(new Ui::CommitDialog)
{
	ui->setupUi(this);
	ui->plainTextEdit->clear();
	ui->listView->setModel(&itemModel);

	setWindowTitle(title);

	// Activate the appropriate control based on mode
	ui->plainTextEdit->setVisible(!singleLineEntry);
	ui->lineEdit->setVisible(singleLineEntry);
	ui->plainTextEdit->setVisible(!stashMode);
	ui->lineEdit->setVisible(stashMode);

	// Activate the checkbox if we have some text
	ui->checkBox->setVisible(checkBoxText!=0);
	ui->chkRevertFiles->setVisible(stashMode);
	if(checkBoxText && checkBoxValue)
	{
		ui->checkBox->setText(*checkBoxText);

	ui->widgetBranchOptions->setVisible(!stashMode);
		ui->checkBox->setCheckState(*checkBoxValue ? Qt::Checked : Qt::Unchecked);
	}

	// Activate the combo if we have history
	ui->comboBox->setVisible(history!=0);
	if(history)
	{
		// Generate the history combo
		foreach(const QString msg, *history)
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
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







-
+

-
+


-
-
-
-
+
-













+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







//------------------------------------------------------------------------------
CommitDialog::~CommitDialog()
{
	delete ui;
}

//------------------------------------------------------------------------------
bool CommitDialog::run(QWidget *parent, QString title, QStringList &files, QString &commitMsg, const QStringList *history, bool singleLineEntry, const QString *checkBoxText, bool *checkBoxValue)
bool CommitDialog::runCommit(QWidget* parent, QStringList& files, QString& commitMsg, const QStringList& commitMsgHistory, QString &branchName, bool &privateBranch)
{
	CommitDialog dlg(parent, title, files, history, singleLineEntry, checkBoxText, checkBoxValue);
	CommitDialog dlg(parent, tr("Commit Changes"), files, &commitMsgHistory, false);
	int res = dlg.exec();

	if(singleLineEntry)
		commitMsg = dlg.ui->lineEdit->text();
	else
		commitMsg = dlg.ui->plainTextEdit->toPlainText();
	commitMsg = dlg.ui->plainTextEdit->toPlainText();


	if(res!=QDialog::Accepted)
		return false;

	files.clear();
	for(int i=0; i<dlg.itemModel.rowCount(); ++i)
	{
		QStandardItem *si = dlg.itemModel.item(i);
		if(si->checkState()!=Qt::Checked)
			continue;
		files.append(si->text());
	}

	branchName.clear();
	if(dlg.ui->chkNewBranch->isChecked())
	{
		branchName = dlg.ui->lineBranchName->text().trimmed();
		privateBranch = dlg.ui->chkPrivateBranch->isChecked();
	}
	if(checkBoxText)
	{
		Q_ASSERT(checkBoxValue);
		*checkBoxValue = dlg.ui->checkBox->checkState() == Qt::Checked;
	}


	return true;
}

//------------------------------------------------------------------------------
bool CommitDialog::runStashNew(QWidget* parent, QStringList& stashedFiles, QString& stashName, bool& revertFiles)
{
	CommitDialog dlg(parent, tr("Stash Changes"), stashedFiles, NULL, true);
	int res = dlg.exec();

	stashName = dlg.ui->lineEdit->text();

	if(res!=QDialog::Accepted)
		return false;

	stashedFiles.clear();
	for(int i=0; i<dlg.itemModel.rowCount(); ++i)
	{
		QStandardItem *si = dlg.itemModel.item(i);
		if(si->checkState()!=Qt::Checked)
			continue;
		stashedFiles.append(si->text());
	}

	revertFiles = dlg.ui->chkRevertFiles->checkState() == Qt::Checked;
	return true;
}

//------------------------------------------------------------------------------
void CommitDialog::on_comboBox_activated(int index)
{
	Q_ASSERT(index < commitMessages.length());
138
139
140
141
142
143
144







156
157
158
159
160
161
162
163
164
165
166
167
168
169







+
+
+
+
+
+
+
		QStandardItem *si = itemModel.item(i);
		if(si->checkState()==Qt::Checked)
			++num_selected;
	}

	ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(num_selected>0);
}

//------------------------------------------------------------------------------
void CommitDialog::on_chkNewBranch_toggled(bool checked)
{
	ui->chkPrivateBranch->setEnabled(checked);
	ui->lineBranchName->setEnabled(checked);
}
Changes to src/CommitDialog.h.
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
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







-
+




-
+


-
-
+
+

+
-
+





+


-
+





#ifndef COMMITDIALOG_H
#define COMMITDIALOG_H

#include <QDialog>
#include <QStandardItemModel>

namespace Ui {
    class CommitDialog;
	class CommitDialog;
}

class CommitDialog : public QDialog
{
    Q_OBJECT
	Q_OBJECT

public:
	explicit CommitDialog(QWidget *parent, QString title, QStringList &files, const QStringList *history=0, bool singleLineEntry=false, const QString *checkBoxText=0, bool *checkBoxValue=0);
    ~CommitDialog();
	explicit CommitDialog(QWidget *parent, const QString &title, QStringList &files, const QStringList *history, bool stashMode);
	~CommitDialog();

	static bool runStashNew(QWidget* parent, QStringList& stashedFiles, QString& stashName, bool &revertFiles);
	static bool run(QWidget *parent, QString title, QStringList &files, QString &commitMsg, const QStringList *history=0, bool singleLineEntry=false, const QString *checkBoxText=0, bool *checkBoxValue=0);
	static bool runCommit(QWidget* parent, QStringList& files, QString& commitMsg, const QStringList &commitMsgHistory, QString& branchName, bool& privateBranch);

private slots:
	void on_comboBox_activated(int index);
	void on_listView_doubleClicked(const QModelIndex &index);
	void on_listView_clicked(const QModelIndex &index);
	void on_chkNewBranch_toggled(bool checked);

private:
    Ui::CommitDialog *ui;
	Ui::CommitDialog *ui;
	QStandardItemModel	itemModel;
	QStringList commitMessages;
};

#endif // COMMITDIALOG_H
Changes to src/Fossil.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16



17
18
19
20
21
22
23
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



-












+
+
+







#include "Fossil.h"
#include <QStringList>
#include <QCoreApplication>
#include <LoggedProcess.h>
#include <QTextCodec>
#include <QDebug>
#include <QDir>
#include <QTemporaryFile>
#include <QUrl>
#include "Utils.h"

static const unsigned char		UTF8_BOM[] = { 0xEF, 0xBB, 0xBF };

// 19: [5c46757d4b9765] on 2012-04-22 04:41:15
static const QRegExp			REGEX_STASH("\\s*(\\d+):\\s+\\[(.*)\\] on (\\d+)-(\\d+)-(\\d+) (\\d+):(\\d+):(\\d+)", Qt::CaseInsensitive);

// Listening for HTTP requests on TCP port 8081
static const QRegExp			REGEX_PORT(".*TCP port ([0-9]+)\\n", Qt::CaseSensitive);

///////////////////////////////////////////////////////////////////////////////
RepoStatus Fossil::getRepoStatus()
{
	QStringList res;
	int exit_code = EXIT_FAILURE;

	// We need to determine the reason why fossil has failed
46
47
48
49
50
51
52















53
54
55
56
57
58
59
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+








		if(run_ok)
		{
			if(key=="project-name")
				projectName = value;
			else if(key=="repository")
				repositoryFile = value;
			else if(key=="checkout")
			{
				// f2121dad5e4565f55ed9ef882484dd5934af565f 2015-04-26 17:27:39 UTC
				QStringList tokens = value.split(' ', QString::SkipEmptyParts);
				Q_ASSERT(tokens.length()>0);
				currentRevision = tokens[0].trimmed();
			}
			else if(key=="tags")
			{
				currentTags.clear();
				QStringList tokens = value.split(',', QString::SkipEmptyParts);
				foreach(const QString &tag, tokens)
					currentTags.append(tag);
				currentTags.sort();
			}
		}
	}

	return run_ok ? REPO_OK : REPO_NOT_FOUND;
}

//------------------------------------------------------------------------------
99
100
101
102
103
104
105






106
107
108
109
110
111
112
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135







+
+
+
+
+
+







}

//------------------------------------------------------------------------------
bool Fossil::listFiles(QStringList &files)
{
	return runFossil(QStringList() << "ls" << "-l", &files, RUNFLAGS_SILENT_ALL);
}

//------------------------------------------------------------------------------
bool Fossil::status(QStringList &result)
{
	return runFossil(QStringList() << "status", &result, RUNFLAGS_SILENT_ALL);
}

//------------------------------------------------------------------------------
bool Fossil::pushRepository()
{
	return runFossil(QStringList() << "push");
}

172
173
174
175
176
177
178
179

180
181
182
183
184
185
186
195
196
197
198
199
200
201

202
203
204
205
206
207
208
209







-
+







bool Fossil::diffFile(const QString &repoFile)
{
	// Run the diff detached
	return runFossil(QStringList() << "gdiff" << QuotePath(repoFile), 0, RUNFLAGS_DETACHED);
}

//------------------------------------------------------------------------------
bool Fossil::commitFiles(const QStringList& fileList, const QString& comment)
bool Fossil::commitFiles(const QStringList& fileList, const QString& comment, const QString &newBranchName, bool isPrivateBranch)
{
	// Do commit
	QString comment_fname;
	{
		QTemporaryFile temp_file;
		if(!temp_file.open())
			return false;
198
199
200
201
202
203
204











205
206
207
208
209
210
211
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







+
+
+
+
+
+
+
+
+
+
+







	// Write Comment
	comment_file.write(comment.toUtf8());
	comment_file.close();

	// Generate fossil parameters.
	QStringList params;
	params << "commit" << "--message-file" << QuotePath(comment_fname);

	// Commit to new branch
	if(!newBranchName.isEmpty())
	{
		params << "--branch" << newBranchName.trimmed();

		// Private branches are not synced with remotes
		if(isPrivateBranch)
			params << "--private";
	}

	params << QuotePaths(fileList);

	runFossil(params);
	QFile::remove(comment_fname);
	return true;
}

282
283
284
285
286
287
288
289

290
291
292
293
294
295






296
297
298
299
300
301
302
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







-
+






+
+
+
+
+
+







		params << "--explain";

	result.clear();
	return runFossil(params, &result);
}

//------------------------------------------------------------------------------
bool Fossil::updateRepository(QStringList &result, bool explainOnly)
bool Fossil::updateRepository(QStringList &result, const QString &revision, bool explainOnly)
{
	QStringList params;
	params << "update";

	if(explainOnly)
		params << "--nochange";

	if(revision.isEmpty())
		params << "--latest";
	else
		params << revision;


	result.clear();
	return runFossil(params, &result);
}

//------------------------------------------------------------------------------
bool Fossil::getFossilSettings(QStringList &result)
412
413
414
415
416
417
418





































































































































419
420
421
422
423
424
425
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







}

//------------------------------------------------------------------------------
bool Fossil::stashDiff(const QString& name)
{
	return runFossil(QStringList() << "stash" << "diff" << name, 0);
}

//------------------------------------------------------------------------------
bool Fossil::tagList(QStringMap& tags)
{
	tags.clear();
	QStringList tagnames;

	if(!runFossil(QStringList() << "tag" << "ls", &tagnames, RUNFLAGS_SILENT_ALL))
		return false;

	QStringList info;
	foreach(const QString &line, tagnames)
	{
		QString tag = line.trimmed();

		if(tag.isEmpty())
			continue;

		info.clear();

		if(!runFossil(QStringList() << "info" << "tag:"+tag, &info, RUNFLAGS_SILENT_ALL))
			return false;

		QStringMap props;
		ParseProperties(props, info, ':');
		Q_ASSERT(props.contains("uuid"));

		// uuid:         0e29a46f036d2e0cc89727190ad34c2dfdc5737c 2015-04-27 15:41:45 UTC
		QStringList uuid = props["uuid"].trimmed().split(' ');
		Q_ASSERT(uuid.length()>0);

		QString revision = uuid[0].trimmed();
		tags.insert(tag, revision);
	}
	return true;
}

//------------------------------------------------------------------------------
bool Fossil::tagNew(const QString& name, const QString& revision)
{
	QStringList res;

	if(!runFossil(QStringList() << "tag" << "add" << name << revision, &res))
		return false;
	return true;
}

//------------------------------------------------------------------------------
bool Fossil::tagDelete(const QString& name, const QString &revision)
{
	QStringList res;

	if(!runFossil(QStringList() << "tag" << "cancel" << "tag:"+name << revision, &res))
		return false;

	return true;
}

//------------------------------------------------------------------------------
bool Fossil::branchList(QStringList& branches, QStringList& activeBranches)
{
	branches.clear();
	activeBranches.clear();
	QStringList res;

	if(!runFossil(QStringList() << "branch" , &res, RUNFLAGS_SILENT_ALL))
		return false;

	foreach(const QString &line, res)
	{
		QString name = line.trimmed();

		if(name.isEmpty())
			continue;

		// Active branches start with a start
		int active_index = name.indexOf('*');
		bool is_active = (active_index != -1) && active_index==0;

		// Strip
		if(is_active)
		{
			name = name.mid(is_active+1).trimmed();
			activeBranches.append(name);
		}
		else
			branches.append(name);
	}

	branches.sort();
	activeBranches.sort();
	return true;
}

//------------------------------------------------------------------------------
bool Fossil::branchNew(const QString& name, const QString& revisionBasis, bool isPrivate)
{
	QStringList params;

	params <<"branch"  << "new" << name << revisionBasis;

	if(isPrivate)
		params << "--private";

	QStringList res;

	if(!runFossil(params, &res))
		return false;
	return true;
}

//------------------------------------------------------------------------------
bool Fossil::branchMerge(QStringList &res, const QString& revision, bool integrate, bool force, bool testOnly)
{
	QStringList params;

	params <<"merge";

	if(integrate)
		params << "--integrate";

	if(force)
		params << "--force";

	if(testOnly)
		params << "--dry-run";

	params << revision;

	if(!runFossil(params, &res))
		return false;
	return true;
}

//------------------------------------------------------------------------------
static QString ParseFossilQuery(QString line)
{
	// Extract question
	int qend = line.lastIndexOf('(');
	if(qend == -1)
561
562
563
564
565
566
567
568

569
570
571
572


























573
574
575
576
577
578
579
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







-
+




+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







			break;
		}

		QByteArray input;
		process.getLogAndClear(input);

		#ifdef QT_DEBUG // Log fossil output in debug builds
		if(!input.isEmpty())
		if(!input.isEmpty() && (runFlags & RUNFLAGS_DEBUG) )
			qDebug() << "[" << ++input_index << "] '" << input.data() << "'\n";
		#endif

		buffer += decoder->toUnicode(input);
#if 0 // Keep this for now to simulate bad parses
		if(runFlags & RUNFLAGS_DEBUG)
		{
			static int debug=1;
			if(debug==1)
			{
				buffer = "     4: [df2233aabe09ef] on 2013-02-03 02:51:33\n"
						 "     History\n"
						 "     5: [df2233aabe09ef] on 2013-02-15 03:55:37\n"
						 "     ";
				debug++;
			}
			else if(debug==2)
			{
				buffer = " Diff\n"
						 " ";
				debug++;
			}
			else
				buffer="";
		}
#endif
		#ifdef QT_DEBUG // breakpoint
		//if(buffer.indexOf("SQLITE_CANTOPEN")!=-1)
		//	qDebug() << "Breakpoint\n";
		#endif

		QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);

		if(buffer.isEmpty())
			continue;

		// Normalize line endings
589
590
591
592
593
594
595

596

597
598


599
600
601
602
603
604
605
788
789
790
791
792
793
794
795

796
797
798
799
800
801
802
803
804
805
806
807







+
-
+


+
+







		{
			last_line = buffer.mid(last_line_start+1); // Including the EOL

			// Detect previous line
			if(last_line_start>0)
			{
				int before_last_line_start = buffer.lastIndexOf(EOL_MARK, last_line_start-1);

				// No line before ?
				// No new-line before ?
				if(before_last_line_start==-1)
					before_last_line_start = 0; // Use entire line
				else
					++before_last_line_start; // Skip new-line

				// Extract previous line
				before_last_line = buffer.mid(before_last_line_start, last_line_start-before_last_line_start);
			}
		}
		else
			last_line = buffer;
615
616
617
618
619
620
621
622
623


624
625
626







627
628
629
630
631
632
633
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







-
-
+
+



+
+
+
+
+
+
+








		bool have_query = ends_qmark && (have_yn_query || have_yna_query || have_an_query || have_acyn_query);

		// Flush all complete lines to the log and output
		QStringList log_lines = buffer.left(last_line_start).split(EOL_MARK);
		for(int l=0; l<log_lines.length(); ++l)
		{
			// Do not output the last line if it not complete. The first one should be ok though
			if(l>0 && l==log_lines.length()-1 && buffer[buffer.length()-1] != EOL_MARK )
			// Skip last line if we have a query. This will be handled manually further down
			if(have_query && l==log_lines.length()-1)
				continue;

			QString line = log_lines[l].trimmed();

		#ifdef QT_DEBUG
			if(runFlags & RUNFLAGS_DEBUG)
			{
				qDebug() << "LINE: " << line << "\n";
			}
		#endif

			if(line.isEmpty())
				continue;

			if(output)
				output->append(line);

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








998
999
1000
1001
1002
1003
1004
1005

1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087







+
-
+
+
+
+
+
+







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+















+

+
+
+
+
+
+
+
+
	fossilUI.setProcessChannelMode(QProcess::MergedChannels);
	fossilUI.setWorkingDirectory(getCurrentWorkspace());

	log("<b>&gt; fossil ui</b><br>", true);
	log(QObject::tr("Starting Fossil browser UI. Please wait.")+"\n");
	QString fossil = getFossilPath();

	QStringList params;
	fossilUI.start(fossil, QStringList() << "server" << "--localauth" << "-P" << httpPort );
	params << "server" << "--localauth";

	if(!httpPort.isEmpty())
		params << "-P" << httpPort;

	fossilUI.start(getFossilPath(), params);

	if(!fossilUI.waitForStarted() || fossilUI.state()!=QProcess::Running)
	{
		log(QObject::tr("Could not start Fossil executable '%s'").arg(fossil)+"\n");
		return false;
	}

#ifdef Q_OS_WIN
	QTextCodec *codec = QTextCodec::codecForName("UTF-8");
#else
	QTextCodec *codec = QTextCodec::codecForLocale();
#endif

	Q_ASSERT(codec);
	QTextDecoder *decoder = codec->makeDecoder();
	Q_ASSERT(decoder);

	fossilUIPort.clear();

	// Wait for fossil to report the http port
	QString buffer;
	while(true)
	{
		QProcess::ProcessState state = fossilUI.state();
		qint64 bytes_avail = fossilUI.logBytesAvailable();

		if(state!=QProcess::Running && bytes_avail<1)
			break;

		QByteArray input;
		fossilUI.getLogAndClear(input);

		buffer += decoder->toUnicode(input);

		// Normalize line endings
		buffer = buffer.replace("\r\n", "\n");
		buffer = buffer.replace("\r", "\n");

		int index = REGEX_PORT.indexIn(buffer);
		if(index==-1)
		{
			QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
			continue;
		}

		// Extract port
		fossilUIPort = REGEX_PORT.cap(1).trimmed();

		// Done parsing
		break;
	}
	return true;
}

//------------------------------------------------------------------------------
void Fossil::stopUI()
{
	if(uiRunning())
	{
#ifdef Q_WS_WIN
		fossilUI.kill(); // QT on windows cannot terminate console processes with QProcess::terminate
#else
		fossilUI.terminate();
#endif
	}
	fossilUI.close();
	fossilUIPort.clear();
}

//------------------------------------------------------------------------------
QString Fossil::getUIHttpAddress() const
{
	if(fossilUIPort.isEmpty())
		return QString();
	return "http://127.0.0.1:"+fossilUIPort;
}
Changes to src/Fossil.h.
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
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





-
-
+
+
+












-
+
+







#ifndef FOSSIL_H
#define FOSSIL_H

class QStringList;
#include <QString>
#include <QObject>
#include <QProcess>
#include <QStringList>
#include <QObject>
#include "LoggedProcess.h"
#include "Utils.h"

typedef QMap<QString, QString> stashmap_t;

#define PATH_SEPARATOR		"/"

enum RunFlags
{
	RUNFLAGS_NONE			= 0<<0,
	RUNFLAGS_SILENT_INPUT	= 1<<0,
	RUNFLAGS_SILENT_OUTPUT	= 1<<1,
	RUNFLAGS_SILENT_ALL		= RUNFLAGS_SILENT_INPUT | RUNFLAGS_SILENT_OUTPUT,
	RUNFLAGS_DETACHED		= 1<<2
	RUNFLAGS_DETACHED		= 1<<2,
	RUNFLAGS_DEBUG			= 1<<3,
};

enum RepoStatus
{
	REPO_OK,
	REPO_NOT_FOUND,
	REPO_OLD_SCHEMA
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
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







-
+







+
+

-
+

















+
+
+
+
+
+
+
+
+
+
+
+
+
+















+
+
-
+
+




	bool openRepository(const QString &repositoryPath, const QString& workspacePath);
	bool newRepository(const QString &repositoryPath);
	bool closeRepository();
	bool pushRepository();
	bool pullRepository();
	bool cloneRepository(const QString &repository, const QUrl &url, const QUrl &proxyUrl);
	bool undoRepository(QStringList& result, bool explainOnly);
	bool updateRepository(QStringList& result, bool explainOnly);
	bool updateRepository(QStringList& result, const QString& revision, bool explainOnly);
	bool getFossilVersion(QString &version);

	bool uiRunning() const;
	bool startUI(const QString &httpPort);
	void stopUI();

	bool listFiles(QStringList &files);
	bool status(QStringList& result);

	bool diffFile(const QString &repoFile);
	bool commitFiles(const QStringList &fileList, const QString &comment);
	bool commitFiles(const QStringList &fileList, const QString &comment, const QString& newBranchName, bool isPrivateBranch);
	bool addFiles(const QStringList& fileList);
	bool removeFiles(const QStringList& fileList, bool deleteLocal);
	bool revertFiles(const QStringList& fileList);
	bool renameFile(const QString& beforePath, const QString& afterPath, bool renameLocal);
	bool getFossilSettings(QStringList& result);
	bool setFossilSetting(const QString &name, const QString &value, bool global);
	bool setRemoteUrl(const QString &url);
	bool getRemoteUrl(QString &url);

	bool stashNew(const QStringList& fileList, const QString& name, bool revert);
	bool stashList(stashmap_t &stashes);
	bool stashApply(const QString& name);
	bool stashDrop(const QString& name);
	bool stashDiff(const QString& name);

	void abortOperation() { operationAborted = true; }

	bool tagList(QStringMap& tags);
	bool tagNew(const QString& name, const QString& revision);
	bool tagDelete(const QString& name, const QString& revision);

	bool branchList(QStringList& branches, QStringList& activeBranches);
	bool branchNew(const QString& name, const QString& revisionBasis, bool isPrivate=false);
	bool branchMerge(QStringList& res, const QString& revision, bool integrate, bool force, bool testOnly);

	const QString &getCurrentRevision() const { return currentRevision; }
	const QStringList &getCurrentTags() const { return currentTags; }

	const QString &getUIHttpPort() const { return fossilUIPort; }
	QString getUIHttpAddress() const;

private:
	void log(const QString &text, bool isHTML=false)
	{
		if(uiCallback)
			uiCallback->logText(text, isHTML);
	}

	QString	getFossilPath();

	bool				operationAborted;
	UICallback			*uiCallback;
	QString				currentWorkspace;
	QString				fossilPath;		// The value from the settings
	QString				repositoryFile;
	QString				projectName;
	QString				currentRevision;
	QStringList			currentTags;
	QProcess			fossilUI;
	LoggedProcess		fossilUI;
	QString				fossilUIPort;
};


#endif // FOSSIL_H
Added src/FslSettingsDialog.cpp.








































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#include "FslSettingsDialog.h"
#include "ui_FslSettingsDialog.h"
#include "Utils.h"

#include <QDir>

///////////////////////////////////////////////////////////////////////////////
FslSettingsDialog::FslSettingsDialog(QWidget *parent, Settings &_settings) :
	QDialog(parent, Qt::Sheet),
	ui(new Ui::FslSettingsDialog),
	settings(&_settings)
{
	ui->setupUi(this);

	ui->lineUIPort->setText(settings->GetValue(FOSSIL_SETTING_HTTP_PORT).toString());

	// Global Settings
	ui->lineGDiffCommand->setText(settings->GetFossilValue(FOSSIL_SETTING_GDIFF_CMD).toString());
	ui->lineGMergeCommand->setText(settings->GetFossilValue(FOSSIL_SETTING_GMERGE_CMD).toString());
	ui->lineProxy->setText(settings->GetFossilValue(FOSSIL_SETTING_PROXY_URL).toString());

	// Repository Settings
	ui->lineRemoteURL->setText(settings->GetFossilValue(FOSSIL_SETTING_REMOTE_URL).toString());
	ui->lineIgnore->setText(settings->GetFossilValue(FOSSIL_SETTING_IGNORE_GLOB).toString());
	ui->lineIgnoreCRNL->setText(settings->GetFossilValue(FOSSIL_SETTING_CRNL_GLOB).toString());
}

//-----------------------------------------------------------------------------
FslSettingsDialog::~FslSettingsDialog()
{
	delete ui;
}

//-----------------------------------------------------------------------------
bool FslSettingsDialog::run(QWidget *parent, Settings &settings)
{
	FslSettingsDialog dlg(parent, settings);
	return dlg.exec() == QDialog::Accepted;
}

//-----------------------------------------------------------------------------
void FslSettingsDialog::on_buttonBox_accepted()
{
	settings->SetValue(FOSSIL_SETTING_HTTP_PORT, ui->lineUIPort->text());

	settings->SetFossilValue(FOSSIL_SETTING_GDIFF_CMD, ui->lineGDiffCommand->text());
	settings->SetFossilValue(FOSSIL_SETTING_GMERGE_CMD, ui->lineGMergeCommand->text());
	settings->SetFossilValue(FOSSIL_SETTING_PROXY_URL, ui->lineProxy->text());

	settings->SetFossilValue(FOSSIL_SETTING_REMOTE_URL, ui->lineRemoteURL->text());
	settings->SetFossilValue(FOSSIL_SETTING_IGNORE_GLOB, ui->lineIgnore->text());
	settings->SetFossilValue(FOSSIL_SETTING_CRNL_GLOB, ui->lineIgnoreCRNL->text());

	settings->ApplyEnvironment();
}

//-----------------------------------------------------------------------------
void FslSettingsDialog::on_btnSelectFossilGDiff_clicked()
{
	QString path = SelectExe(this, tr("Select Graphical Diff application"));
	if(!path.isEmpty())
		ui->lineGDiffCommand->setText(QDir::toNativeSeparators(path));
}

//-----------------------------------------------------------------------------
void FslSettingsDialog::on_btnSelectGMerge_clicked()
{
	QString path = SelectExe(this, tr("Select Graphical Merge application"));
	if(!path.isEmpty())
		ui->lineGMergeCommand->setText(path);
}

Added src/FslSettingsDialog.h.

































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#ifndef FSLSETTINGSDIALOG_H
#define FSLSETTINGSDIALOG_H

#include <QDialog>
#include "Settings.h"

namespace Ui {
	class FslSettingsDialog;
}

class FslSettingsDialog : public QDialog
{
	Q_OBJECT

public:
	explicit FslSettingsDialog(QWidget *parent, Settings &_settings);
	~FslSettingsDialog();

	static bool run(QWidget *parent, Settings &_settings);


private slots:
	void on_buttonBox_accepted();
	void on_btnSelectFossilGDiff_clicked();
	void on_btnSelectGMerge_clicked();

private:

	Ui::FslSettingsDialog *ui;
	Settings *settings;
};

#endif // FSLSETTINGSDIALOG_H
Changes to src/MainWindow.cpp.
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
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








-



+


+
+
+



+

+
+



















-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QDateTime>
#include <QDebug>
#include <QDesktopServices>
#include <QDrag>
#include <QDragEnterEvent>
#include <QFileDialog>
#include <QFileIconProvider>
#include <QInputDialog>
#include <QMimeData>
#include <QProgressBar>
#include <QLabel>
#include <QSettings>
#include <QShortcut>
#include "SettingsDialog.h"
#include "FslSettingsDialog.h"
#include "SearchBox.h"
#include "CommitDialog.h"
#include "FileActionDialog.h"
#include "CloneDialog.h"
#include "RevisionDialog.h"
#include "Utils.h"

#define REVISION_LATEST "Latest revision"

//-----------------------------------------------------------------------------
enum
{
	COLUMN_STATUS,
	COLUMN_FILENAME,
	COLUMN_EXTENSION,
	COLUMN_MODIFIED,
	COLUMN_PATH
};

enum
{
	TAB_LOG,
	TAB_BROWSER
};

enum
{
	REPODIRMODEL_ROLE_PATH = Qt::UserRole+1
	ROLE_WORKSPACE_ITEM = Qt::UserRole+1
};

struct WorkspaceItem
{
	enum
	{
		TYPE_UNKNOWN,
		TYPE_WORKSPACE,
		TYPE_FOLDER,
		TYPE_STASHES,
		TYPE_STASH,
		TYPE_BRANCHES,
		TYPE_BRANCH,
		TYPE_TAGS,
		TYPE_TAG,
		TYPE_REMOTES,
		TYPE_SETTINGS
	};

	WorkspaceItem()
	: Type(TYPE_UNKNOWN)
	{
	}

	WorkspaceItem(int type, const QString &value)
	: Type(type), Value(value)
	{
	}

	WorkspaceItem(const WorkspaceItem &other)
	{
		Type = other.Type;
		Value = other.Value;
	}

	int Type;
	QString Value;

	operator QVariant() const
	{
		return QVariant::fromValue(*this);
	}
};

Q_DECLARE_METATYPE(WorkspaceItem)
//-----------------------------------------------------------------------------
typedef QMap<QString, QString> QStringMap;
static QStringMap MakeKeyValues(QStringList lines)
{
	QStringMap res;

	foreach(QString l, lines)
	{
		l = l.trimmed();
		int index = l.indexOf(' ');

		QString key;
		QString value;
		if(index!=-1)
		{
			key = l.left(index).trimmed();
			value = l.mid(index).trimmed();
		}
		else
			key = l;

		res.insert(key, value);
	}
	return res;
}


///////////////////////////////////////////////////////////////////////////////
MainWindow::MainWindow(Settings &_settings, QWidget *parent, QString *workspacePath) :
	QMainWindow(parent),
	ui(new Ui::MainWindow),
	settings(_settings)
{
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
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







-
+
+
+
+
+
+





+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+

-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







	ui->fileTableView->horizontalHeader()->setMovable(true);
#else
	ui->fileTableView->horizontalHeader()->setSectionsMovable(true);
#endif
	ui->fileTableView->horizontalHeader()->setStretchLastSection(true);

	// workspaceTreeView
	ui->workspaceTreeView->setModel(&getWorkspace().getDirModel());
	ui->workspaceTreeView->setModel(&getWorkspace().getTreeModel());

	header.clear();
	header << tr("Workspace");
	getWorkspace().getTreeModel().setHorizontalHeaderLabels(header);

	connect( ui->workspaceTreeView->selectionModel(),
		SIGNAL( selectionChanged(const QItemSelection &, const QItemSelection &) ),
		SLOT( onWorkspaceTreeViewSelectionChanged(const QItemSelection &, const QItemSelection &) ),
		Qt::DirectConnection );

	// Workspace Menus
	menuWorkspace = new QMenu(this);
	ui->workspaceTreeView->addAction(ui->actionCommit);
	ui->workspaceTreeView->addAction(ui->actionOpenFolder);
	ui->workspaceTreeView->addAction(ui->actionAdd);
	ui->workspaceTreeView->addAction(ui->actionRevert);
	ui->workspaceTreeView->addAction(ui->actionDelete);
	ui->workspaceTreeView->addAction(separator);
	ui->workspaceTreeView->addAction(ui->actionRenameFolder);
	ui->workspaceTreeView->addAction(ui->actionOpenFolder);
	menuWorkspace->addAction(ui->actionCommit);
	menuWorkspace->addAction(ui->actionOpenFolder);
	menuWorkspace->addAction(ui->actionAdd);
	menuWorkspace->addAction(ui->actionRevert);
	menuWorkspace->addAction(ui->actionDelete);
	menuWorkspace->addAction(separator);
	menuWorkspace->addAction(ui->actionRenameFolder);
	menuWorkspace->addAction(ui->actionOpenFolder);

	// StashView
	ui->stashTableView->setModel(&getWorkspace().getStashModel());
	ui->stashTableView->addAction(ui->actionApplyStash);
	ui->stashTableView->addAction(ui->actionDiffStash);
	ui->stashTableView->addAction(ui->actionDeleteStash);
	ui->stashTableView->horizontalHeader()->setSortIndicatorShown(false);
	// StashMenu
	menuStashes = new QMenu(this);
	menuStashes->addAction(ui->actionCreateStash);
	menuStashes->addAction(separator);
	menuStashes->addAction(ui->actionApplyStash);
	menuStashes->addAction(ui->actionDiffStash);
	menuStashes->addAction(ui->actionDeleteStash);

	// TagsMenu
	menuTags = new QMenu(this);
	menuTags->addAction(ui->actionCreateTag);
	menuTags->addAction(separator);
	menuTags->addAction(ui->actionDeleteTag);
	menuTags->addAction(ui->actionUpdate);

	// BranchesMenu
	menuBranches = new QMenu(this);
	menuBranches->addAction(ui->actionCreateBranch);
	menuBranches->addAction(separator);
	menuBranches->addAction(ui->actionMergeBranch);
	menuBranches->addAction(ui->actionUpdate);

	// Recent Workspaces
	// Locate a sequence of two separator actions in file menu
	QList<QAction*> file_actions = ui->menuFile->actions();
	QAction *recent_sep=0;
	for(int i=0; i<file_actions.size(); ++i)
	{
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
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







+
+
+
+
+
+
+
+
+








-
+

+














+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







		recentWorkspaceActs[i]->setVisible(false);
		connect(recentWorkspaceActs[i], SIGNAL(triggered()), this, SLOT(onOpenRecent()));
		ui->menuFile->insertAction(recent_sep, recentWorkspaceActs[i]);
	}

	// TabWidget
	ui->tabWidget->setCurrentIndex(TAB_LOG);

	lblRevision = new QLabel();
	ui->statusBar->insertPermanentWidget(0, lblRevision);
	lblRevision->setVisible(true);

	lblTags = new QLabel();
	ui->statusBar->insertPermanentWidget(1, lblTags);
	lblTags->setVisible(true);


	// Construct ProgressBar
	progressBar = new QProgressBar();
	progressBar->setMinimum(0);
	progressBar->setMaximum(0);
	progressBar->setMaximumSize(170, 16);
	progressBar->setAlignment(Qt::AlignCenter);
	progressBar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
	ui->statusBar->insertPermanentWidget(0, progressBar);
	ui->statusBar->insertPermanentWidget(2, progressBar);
	progressBar->setVisible(false);


#ifdef Q_OS_MACX
	// Native applications on OSX don't have menu icons
	foreach(QAction *a, ui->menuBar->actions())
		a->setIconVisibleInMenu(false);
	foreach(QAction *a, ui->menuFile->actions())
		a->setIconVisibleInMenu(false);
#endif

	abortShortcut = new QShortcut(QKeySequence("Escape"), this);
	abortShortcut->setContext(Qt::ApplicationShortcut);
	abortShortcut->setEnabled(false);
	connect(abortShortcut, SIGNAL(activated()), this, SLOT(onAbort()));

	// Searchbox
	// Add spacer to pad to right
	QWidget* spacer = new QWidget();
	spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	ui->mainToolBar->addWidget(spacer);

	// Search shortcut
	searchShortcut = new QShortcut(QKeySequence(QKeySequence::Find), this);
	searchShortcut->setContext(Qt::ApplicationShortcut);
	searchShortcut->setEnabled(true);
	connect(searchShortcut, SIGNAL(activated()), this, SLOT(onSearch()));


	// Create SearchBox
	searchBox = new SearchBox(this);
	searchBox->setPlaceholderText(tr("Find (%0)").arg(searchShortcut->key().toString()));
	searchBox->setMaximumWidth(450);
	ui->mainToolBar->addWidget(searchBox);

	connect( searchBox,
		SIGNAL( textChanged(const QString&)),
		SLOT( onSearchBoxTextChanged(const QString&)),
		Qt::DirectConnection );

	viewMode = VIEWMODE_TREE;

	uiCallback.init(this);
	// Need to be before applySettings which sets the last workspace
	fossil().Init(&uiCallback);

	applySettings();
317
318
319
320
321
322
323

324
325
326
327
328
329
330
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409







+







		workspaceHistory.removeAll(path);
		rebuildRecent();
		return false;
	}

	// Select the Root of the tree to update the file view
	selectRootDir();
	searchBox->clear();
	return true;
}

//------------------------------------------------------------------------------
void MainWindow::on_actionOpenRepository_triggered()
{
	QString filter(tr("Fossil Files") + QString(" (*." FOSSIL_EXT  " " FOSSIL_CHECKOUT1 " " FOSSIL_CHECKOUT2 ")" ));
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
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







+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+














-
+








-
+







	openWorkspace(workspace);
}


//------------------------------------------------------------------------------
void MainWindow::enableActions(bool on)
{
	QAction *actions[] = {
	ui->actionCommit->setEnabled(on);
	ui->actionDiff->setEnabled(on);
	ui->actionAdd->setEnabled(on);
	ui->actionDelete->setEnabled(on);
	ui->actionPush->setEnabled(on);
	ui->actionPull->setEnabled(on);
	ui->actionRename->setEnabled(on);
	ui->actionHistory->setEnabled(on);
	ui->actionFossilUI->setEnabled(on);
	ui->actionRevert->setEnabled(on);
	ui->actionTimeline->setEnabled(on);
	ui->actionOpenFile->setEnabled(on);
	ui->actionOpenContaining->setEnabled(on);
	ui->actionUndo->setEnabled(on);
	ui->actionUpdate->setEnabled(on);
	ui->actionOpenFolder->setEnabled(on);
	ui->actionRenameFolder->setEnabled(on);
	ui->actionNewStash->setEnabled(on);
	ui->actionDeleteStash->setEnabled(on);
	ui->actionDiffStash->setEnabled(on);
	ui->actionApplyStash->setEnabled(on);
		ui->actionCommit,
		ui->actionDiff,
		ui->actionAdd,
		ui->actionDelete,
		ui->actionPush,
		ui->actionPull,
		ui->actionRename,
		ui->actionHistory,
		ui->actionFossilUI,
		ui->actionRevert,
		ui->actionTimeline,
		ui->actionOpenFile,
		ui->actionOpenContaining,
		ui->actionUndo,
		ui->actionUpdate,
		ui->actionOpenFolder,
		ui->actionRenameFolder,
		ui->actionCreateStash,
		ui->actionDeleteStash,
		ui->actionDiffStash,
		ui->actionApplyStash,
		ui->actionDeleteStash,
		ui->actionCreateTag,
		ui->actionDeleteTag,
		ui->actionCreateBranch,
		ui->actionMergeBranch,
	};

	for(size_t i=0; i<COUNTOF(actions); ++i)
		actions[i]->setEnabled(on);

}
//------------------------------------------------------------------------------
bool MainWindow::refresh()
{
	QString title = "Fuel";

	// Load repository info
	RepoStatus st = fossil().getRepoStatus();

	if(st==REPO_NOT_FOUND)
	{
		setStatus(tr("No workspace detected."));
		enableActions(false);
		getWorkspace().getFileModel().removeRows(0, getWorkspace().getFileModel().rowCount());
		getWorkspace().getDirModel().clear();
		getWorkspace().getTreeModel().removeRows(0, getWorkspace().getFileModel().rowCount());
		setWindowTitle(title);
		return false;
	}
	else if(st==REPO_OLD_SCHEMA)
	{
		setStatus(tr("Old repository schema detected. Consider running 'fossil rebuild'"));
		enableActions(false);
		getWorkspace().getFileModel().removeRows(0, getWorkspace().getFileModel().rowCount());
		getWorkspace().getDirModel().clear();
		getWorkspace().getTreeModel().removeRows(0, getWorkspace().getFileModel().rowCount());
		setWindowTitle(title);
		return true;
	}

	loadFossilSettings();
	scanWorkspace();
	setStatus("");
550
551
552
553
554
555
556
557

558
559








560
561
562





563
564
565
566

567
568
569
570
571
572
573
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







-
+

-
+
+
+
+
+
+
+
+



+
+
+
+
+



-
+







							ui->actionViewIgnored->isChecked(),
							ui->actionViewModified->isChecked(),
							ui->actionViewUnchanged->isChecked(),
							settings.GetFossilValue(FOSSIL_SETTING_IGNORE_GLOB).toString(),
							uiCallback,
							operationAborted
							);
	updateDirView();
	updateWorkspaceView();
	updateFileView();
	updateStashView();

	// Build default versions list
	versionList.clear();
	versionList += getWorkspace().getBranches();
	versionList += getWorkspace().getTags().keys();

	selectedTags.clear();
	selectedBranches.clear();

	setBusy(false);
	setStatus("");
	lblRevision->setText(tr("Revision: %0").arg(fossil().getCurrentRevision()));
	lblRevision->setVisible(true);

	lblTags->setText(tr("Tags: %0").arg(fossil().getCurrentTags().join(' ')));
	lblTags->setVisible(true);
}

//------------------------------------------------------------------------------
static void addPathToTree(QStandardItem &root, const QString &path)
static void addPathToTree(QStandardItem &root, const QString &path, const QIcon &folderIcon)
{
	QStringList dirs = path.split('/');
	QStandardItem *parent = &root;

	QString fullpath;
	for(QStringList::iterator it = dirs.begin(); it!=dirs.end(); ++it)
	{
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
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







-
-
+
+








-
+

+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
+
+
+

-
-
-
-
-
-
+
+
+
+
+
+
+
+

-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+











-
-
-
-
-
-
-
+
+
+
+
+
+
+
+


-
-

+
+
+





-
+
+
+
+
+
+
+






-
-
+
+





-
+





-
-
+
+



+
+
+
-
+
+
+





-
+

-
+



-
+











-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







				parent = child;
				found = true;
			}
		}

		if(!found) // Generate it
		{
			QStandardItem *child = new QStandardItem(QIcon(":icons/icons/Folder-01.png"), dir);
			child->setData(fullpath); // keep the full path to simplify selection
			QStandardItem *child = new QStandardItem(folderIcon, dir);
			child->setData(WorkspaceItem(WorkspaceItem::TYPE_FOLDER, fullpath), ROLE_WORKSPACE_ITEM);
			parent->appendRow(child);
			parent = child;
		}
		fullpath += '/';
	}
}

//------------------------------------------------------------------------------
void MainWindow::updateDirView()
void MainWindow::updateWorkspaceView()
{
	// Record expanded tree-node names, and selection
	name_modelindex_map_t name_map;
	BuildNameToModelIndex(name_map, getWorkspace().getTreeModel());
	stringset_t expanded_items;
	stringset_t selected_items;
	// Directory View
	getWorkspace().getDirModel().clear();

	QStringList header;
	header << tr("Folders");
	getWorkspace().getDirModel().setHorizontalHeaderLabels(header);

	const QItemSelection selection = ui->workspaceTreeView->selectionModel()->selection();

	for(name_modelindex_map_t::const_iterator it=name_map.begin(); it!=name_map.end(); ++it)
	{
		const QModelIndex mi = it.value();
		if(ui->workspaceTreeView->isExpanded(mi))
			expanded_items.insert(it.key());

		if(selection.contains(mi))
			selected_items.insert(it.key());
	}

	// Clear content except headers
	getWorkspace().getTreeModel().removeRows(0, getWorkspace().getTreeModel().rowCount());

	QStandardItem *root = new QStandardItem(QIcon(":icons/icons/My Documents-01.png"), fossil().getProjectName());
	root->setData(""); // Empty Path
	root->setEditable(false);
	QStandardItem *workspace = new QStandardItem(getInternalIcon(":icons/icon-item-folder"), tr("Files") );
	workspace->setData(WorkspaceItem(WorkspaceItem::TYPE_WORKSPACE, ""), ROLE_WORKSPACE_ITEM);
	workspace->setEditable(false);

	getWorkspace().getDirModel().appendRow(root);
	for(stringset_t::iterator it = getWorkspace().getPaths().begin(); it!=getWorkspace().getPaths().end(); ++it)
	{
		const QString &dir = *it;
		if(dir.isEmpty())
			continue;
	getWorkspace().getTreeModel().appendRow(workspace);
	if(viewMode == VIEWMODE_TREE)
	{
		for(stringset_t::iterator it = getWorkspace().getPaths().begin(); it!=getWorkspace().getPaths().end(); ++it)
		{
			const QString &dir = *it;
			if(dir.isEmpty())
				continue;

		addPathToTree(*root, dir);
	}
	ui->workspaceTreeView->expandToDepth(0);
	ui->workspaceTreeView->sortByColumn(0, Qt::AscendingOrder);
			addPathToTree(*workspace, dir, getInternalIcon(":icons/icon-item-folder"));
		}

		// Expand root folder
		ui->workspaceTreeView->setExpanded(workspace->index(), true);
	}

	// Branches
	QStandardItem *branches = new QStandardItem(getInternalIcon(":icons/icon-item-branch"), tr("Branches"));
	branches->setData(WorkspaceItem(WorkspaceItem::TYPE_BRANCHES, ""), ROLE_WORKSPACE_ITEM);
	branches->setEditable(false);
	getWorkspace().getTreeModel().appendRow(branches);
	foreach(const QString &branch_name, getWorkspace().getBranches())
	{
		QStandardItem *branch = new QStandardItem(getInternalIcon(":icons/icon-item-branch"), branch_name);
		branch->setData(WorkspaceItem(WorkspaceItem::TYPE_BRANCH, branch_name), ROLE_WORKSPACE_ITEM);

		bool active = fossil().getCurrentTags().contains(branch_name);
		if(active)
		{
			QFont font = branch->font();
			font.setBold(true);
			branch->setFont(font);
		}
		branches->appendRow(branch);
	}

	// Tags
	QStandardItem *tags = new QStandardItem(getInternalIcon(":icons/icon-item-tag"), tr("Tags"));
	tags->setData(WorkspaceItem(WorkspaceItem::TYPE_TAGS, ""), ROLE_WORKSPACE_ITEM);
	tags->setEditable(false);
	getWorkspace().getTreeModel().appendRow(tags);
	for(QStringMap::const_iterator it=getWorkspace().getTags().begin(); it!=getWorkspace().getTags().end(); ++it)
	{
		const QString &tag_name = it.key();


		QStandardItem *tag = new QStandardItem(getInternalIcon(":icons/icon-item-tag"), tag_name);
		tag->setData(WorkspaceItem(WorkspaceItem::TYPE_TAG, tag_name), ROLE_WORKSPACE_ITEM);

		bool active = fossil().getCurrentTags().contains(tag_name);
		if(active)
		{
			QFont font = tag->font();
			font.setBold(true);
			tag->setFont(font);
		}
		tags->appendRow(tag);
	}

	// FIXME: Unique Icon name
	// Stashes
	QStandardItem *stashes = new QStandardItem(getInternalIcon(":icons/icon-action-repo-open"), tr("Stashes"));
	stashes->setData(WorkspaceItem(WorkspaceItem::TYPE_STASHES, ""), ROLE_WORKSPACE_ITEM);
	stashes->setEditable(false);
	getWorkspace().getTreeModel().appendRow(stashes);
	for(stashmap_t::const_iterator it= getWorkspace().getStashes().begin(); it!=getWorkspace().getStashes().end(); ++it)
	{
		QStandardItem *stash = new QStandardItem(getInternalIcon(":icons/icon-action-repo-open"), it.key());
		stash->setData(WorkspaceItem(WorkspaceItem::TYPE_STASH, it.value()), ROLE_WORKSPACE_ITEM);
		stashes->appendRow(stash);
	}

#if 0
	// Remotes
	QStandardItem *remotes = new QStandardItem(getInternalIcon(":icons/icon-item-remote"), tr("Remotes"));
	remotes->setData(WorkspaceItem(WorkspaceItem::TYPE_REMOTES, ""), ROLE_WORKSPACE_ITEM);
	remotes->setEditable(false);
	getWorkspace().getTreeModel().appendRow(remotes);
#endif

#if 0 // Unimplemented for now
	// Settings
	QStandardItem *settings = new QStandardItem(getInternalIcon(":icons/icon-action-settings"), tr("Settings"));
	settings->setData(WorkspaceItem(WorkspaceItem::TYPE_SETTINGS, ""), ROLE_WORKSPACE_ITEM);
	settings->setEditable(false);
	getWorkspace().getTreeModel().appendRow(settings);
#endif

	// Expand previously selected nodes
	name_map.clear();
	BuildNameToModelIndex(name_map, getWorkspace().getTreeModel());

	for(stringset_t::const_iterator it=expanded_items.begin(); it!=expanded_items.end(); ++it)
	{
		name_modelindex_map_t::const_iterator mi_it = name_map.find(*it);
		if(mi_it!=name_map.end())
			ui->workspaceTreeView->setExpanded(mi_it.value(), true);
	}

	// Select previous selected item
	for(stringset_t::const_iterator it=selected_items.begin(); it!=selected_items.end(); ++it)
	{
		name_modelindex_map_t::const_iterator mi_it = name_map.find(*it);
		if(mi_it!=name_map.end())
		{
			const QModelIndex &mi = mi_it.value();
			ui->workspaceTreeView->selectionModel()->select(mi, QItemSelectionModel::Select);
		}
	}
}

//------------------------------------------------------------------------------
void MainWindow::updateFileView()
{
	// Clear content except headers
	getWorkspace().getFileModel().removeRows(0, getWorkspace().getFileModel().rowCount());

	struct { WorkspaceFile::Type type; QString text; const char *icon; }
	stats[] =
	{
		{   WorkspaceFile::TYPE_EDITTED, tr("Edited"), ":icons/icons/Button Blank Yellow-01.png" },
		{   WorkspaceFile::TYPE_UNCHANGED, tr("Unchanged"), ":icons/icons/Button Blank Green-01.png" },
		{   WorkspaceFile::TYPE_ADDED, tr("Added"), ":icons/icons/Button Add-01.png" },
		{   WorkspaceFile::TYPE_DELETED, tr("Deleted"), ":icons/icons/Button Close-01.png" },
		{   WorkspaceFile::TYPE_RENAMED, tr("Renamed"), ":icons/icons/Button Reload-01.png" },
		{   WorkspaceFile::TYPE_MISSING, tr("Missing"), ":icons/icons/Button Help-01.png" },
		{   WorkspaceFile::TYPE_CONFLICTED, tr("Conflicted"), ":icons/icons/Button Blank Red-01.png" },
		{   WorkspaceFile::TYPE_EDITTED, tr("Edited"), ":icons/icon-item-edited" },
		{   WorkspaceFile::TYPE_UNCHANGED, tr("Unchanged"), ":icons/icon-item-unchanged" },
		{   WorkspaceFile::TYPE_ADDED, tr("Added"), ":icons/icon-item-added" },
		{   WorkspaceFile::TYPE_DELETED, tr("Deleted"), ":icons/icon-item-deleted" },
		{   WorkspaceFile::TYPE_RENAMED, tr("Renamed"), ":icons/icon-item-renamed" },
		{   WorkspaceFile::TYPE_MISSING, tr("Missing"), ":icons/icon-item-missing" },
		{   WorkspaceFile::TYPE_CONFLICTED, tr("Conflicted"), ":icons/icon-item-conflicted" },
		{   WorkspaceFile::TYPE_MERGED, tr("Merged"), ":icons/icon-item-edited" },
	};

	QFileIconProvider icon_provider;

	bool display_path = viewMode==VIEWMODE_LIST || selectedDirs.count() > 1;

	const QString &status_unknown = QString(tr("Unknown"));
	const QString &search_text = searchBox->text();

	size_t item_id=0;
	for(Workspace::filemap_t::iterator it = getWorkspace().getFiles().begin(); it!=getWorkspace().getFiles().end(); ++it)
	{
		const WorkspaceFile &e = *it.value();
		QString path = e.getPath();
		const QString &path = e.getPath();
		const QString &file_path = e.getFilePath();
		QString native_file_path = QDir::toNativeSeparators(file_path);

		// Apply filter if available
		if(!search_text.isEmpty() && !native_file_path.contains(search_text, Qt::CaseInsensitive))
			continue;

		// In Tree mode, filter all items not included in the current dir
		if(viewMode==VIEWMODE_TREE && !selectedDirs.contains(path))
			continue;

		// Status Column
		QString status_text = QString(tr("Unknown"));
		const char *status_icon_path= ":icons/icons/Button Blank Gray-01.png"; // Default icon
		const QString *status_text = &status_unknown;
		const char *status_icon_path= ":icons/icon-item-unknown"; // Default icon

		for(size_t t=0; t<COUNTOF(stats); ++t)
		{
			if(e.getType() == stats[t].type)
			{
				status_text = stats[t].text;
				status_text = &stats[t].text;
				status_icon_path = stats[t].icon;
				break;
			}
		}

		QStandardItem *status = new QStandardItem(QIcon(status_icon_path), status_text);
		status->setToolTip(status_text);
		QStandardItem *status = new QStandardItem(getInternalIcon(status_icon_path), *status_text);
		status->setToolTip(*status_text);
		getWorkspace().getFileModel().setItem(item_id, COLUMN_STATUS, status);

		QFileInfo finfo = e.getFileInfo();
		QString icon_type = iconProvider.type(finfo);

		if(!iconCache.contains(icon_type))
		QIcon icon = icon_provider.icon(finfo);
			iconCache.insert(icon_type, iconProvider.icon(finfo));

		const QIcon *icon = &iconCache[icon_type];

		QStandardItem *filename_item = 0;
		getWorkspace().getFileModel().setItem(item_id, COLUMN_PATH, new QStandardItem(path));

		if(display_path)
			filename_item = new QStandardItem(icon, QDir::toNativeSeparators(e.getFilePath()));
			filename_item = new QStandardItem(*icon, native_file_path);
		else
			filename_item = new QStandardItem(icon, e.getFilename());
			filename_item = new QStandardItem(*icon, e.getFilename());

		Q_ASSERT(filename_item);
		// Keep the path in the user data
		filename_item->setData(e.getFilePath());
		filename_item->setData(file_path);
		getWorkspace().getFileModel().setItem(item_id, COLUMN_FILENAME, filename_item);

		getWorkspace().getFileModel().setItem(item_id, COLUMN_EXTENSION, new QStandardItem(finfo.suffix()));
		getWorkspace().getFileModel().setItem(item_id, COLUMN_MODIFIED, new QStandardItem(finfo.lastModified().toString(Qt::SystemLocaleShortDate)));

		++item_id;
	}

	ui->fileTableView->resizeRowsToContents();
}

//------------------------------------------------------------------------------
void MainWindow::updateStashView()
{
	getWorkspace().getStashModel().clear();

	QStringList header;
	header << tr("Stashes");
	getWorkspace().getStashModel().setHorizontalHeaderLabels(header);

	for(stashmap_t::iterator it=getWorkspace().getStashes().begin(); it!=getWorkspace().getStashes().end(); ++it)
	{
		QStandardItem *item = new QStandardItem(it.key());
		item->setToolTip(it.key());
		getWorkspace().getStashModel().appendRow(item);
	}
	ui->stashTableView->resizeColumnsToContents();
	ui->stashTableView->resizeRowsToContents();
}

//------------------------------------------------------------------------------
void MainWindow::log(const QString &text, bool isHTML)
{
	QTextCursor c = ui->textBrowser->textCursor();
	c.movePosition(QTextCursor::End);
	ui->textBrowser->setTextCursor(c);

810
811
812
813
814
815
816

817
818
819

820
821
822
823
824
825
826
827
828
829
830
831
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027

1028





1029
1030
1031
1032
1033
1034
1035







+


-
+
-
-
-
-
-







	if(store->contains("ViewUnchanged"))
		ui->actionViewUnchanged->setChecked(store->value("ViewUnchanged").toBool());
	if(store->contains("ViewIgnored"))
		ui->actionViewIgnored->setChecked(store->value("ViewIgnored").toBool());
	if(store->contains("ViewAsList"))
	{
		ui->actionViewAsList->setChecked(store->value("ViewAsList").toBool());
		ui->actionViewAsFolders->setChecked(!store->value("ViewAsList").toBool());
		viewMode = store->value("ViewAsList").toBool()? VIEWMODE_LIST : VIEWMODE_TREE;
	}
	ui->workspaceTreeView->setVisible(viewMode == VIEWMODE_TREE);
	//ui->workspaceTreeView->setVisible(viewMode == VIEWMODE_TREE);

	if(store->contains("ViewStash"))
		ui->actionViewStash->setChecked(store->value("ViewStash").toBool());
	ui->stashTableView->setVisible(ui->actionViewStash->isChecked());

}

//------------------------------------------------------------------------------
void MainWindow::updateSettings()
{
	QSettings *store = settings.GetStore();

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
1060
1061
1062
1063
1064
1065
1066

1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087

1088
1089
1090
1091
1092
1093
1094
1095







-





+















-
+







	store->setValue("WindowWidth", width());
	store->setValue("WindowHeight", height());
	store->setValue("ViewUnknown", ui->actionViewUnknown->isChecked());
	store->setValue("ViewModified", ui->actionViewModified->isChecked());
	store->setValue("ViewUnchanged", ui->actionViewUnchanged->isChecked());
	store->setValue("ViewIgnored", ui->actionViewIgnored->isChecked());
	store->setValue("ViewAsList", ui->actionViewAsList->isChecked());
	store->setValue("ViewStash", ui->actionViewStash->isChecked());
}

//------------------------------------------------------------------------------
void MainWindow::selectRootDir()
{
	// FIXME: KKK
	if(viewMode==VIEWMODE_TREE)
	{
		QModelIndex root_index = ui->workspaceTreeView->model()->index(0, 0);
		ui->workspaceTreeView->selectionModel()->select(root_index, QItemSelectionModel::Select);
	}
}

//------------------------------------------------------------------------------
void MainWindow::fossilBrowse(const QString &fossilUrl)
{
	if(!uiRunning())
		ui->actionFossilUI->activate(QAction::Trigger);

	bool use_internal = settings.GetValue(FUEL_SETTING_WEB_BROWSER).toInt() == 1;

	QUrl url = QUrl(getFossilHttpAddress()+fossilUrl);
	QUrl url = QUrl(fossil().getUIHttpAddress()+fossilUrl);

	if(use_internal)
	{
		ui->webView->load(url);
		ui->tabWidget->setCurrentIndex(TAB_BROWSER);
	}
	else
901
902
903
904
905
906
907
908

909


910
911
912






913
914
915
916
917
918
919
1105
1106
1107
1108
1109
1110
1111

1112
1113
1114
1115



1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128







-
+

+
+
-
-
-
+
+
+
+
+
+







}

//------------------------------------------------------------------------------
void MainWindow::getSelectionPaths(stringset_t &paths)
{
	// Determine the directories selected
	QModelIndexList selection = ui->workspaceTreeView->selectionModel()->selectedIndexes();
	for(QModelIndexList::iterator mi_it = selection.begin(); mi_it!=selection.end(); ++mi_it)
	foreach(const QModelIndex &mi, selection)
	{
		QVariant data = mi.model()->data(mi, ROLE_WORKSPACE_ITEM);
		Q_ASSERT(data.isValid());
		const QModelIndex &mi = *mi_it;
		QVariant data = getWorkspace().getDirModel().data(mi, REPODIRMODEL_ROLE_PATH);
		paths.insert(data.toString());

		WorkspaceItem tv = data.value<WorkspaceItem>();
		if(tv.Type != WorkspaceItem::TYPE_FOLDER)
			continue;

		paths.insert(tv.Value);
	}
}
//------------------------------------------------------------------------------
// Select all workspace files that match the includeMask
void MainWindow::getAllFilenames(QStringList &filenames, int includeMask)
{
	for(Workspace::filemap_t::iterator it=getWorkspace().getFiles().begin(); it!=getWorkspace().getFiles().end(); ++it)
1004
1005
1006
1007
1008
1009
1010
1011

1012
1013

1014
1015

1016
1017

1018
1019
1020

1021
1022




1023
1024

1025
1026
1027


1028
1029

1030
1031
1032
1033
1034
1035
1036
1213
1214
1215
1216
1217
1218
1219

1220
1221

1222


1223


1224



1225


1226
1227
1228
1229


1230

1231

1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243







-
+

-
+
-
-
+
-
-
+
-
-
-
+
-
-
+
+
+
+
-
-
+
-

-
+
+


+







		if(!(includeMask & e.getType()))
			continue;

		filenames.append(filename);
	}
}
//------------------------------------------------------------------------------
void MainWindow::getStashViewSelection(QStringList &stashNames, bool allIfEmpty)
void MainWindow::getSelectionStashes(QStringList &stashNames)
{
	QModelIndexList selection = ui->stashTableView->selectionModel()->selectedIndexes();
	QModelIndexList selection = ui->workspaceTreeView->selectionModel()->selectedIndexes();
	if(selection.empty() && allIfEmpty)
	{

		ui->stashTableView->selectAll();
		selection = ui->stashTableView->selectionModel()->selectedIndexes();
	foreach(const QModelIndex &mi, selection)
		ui->stashTableView->clearSelection();
	}

	{
	for(QModelIndexList::iterator mi_it = selection.begin(); mi_it!=selection.end(); ++mi_it)
	{
		QVariant data = mi.model()->data(mi, ROLE_WORKSPACE_ITEM);
		Q_ASSERT(data.isValid());
		WorkspaceItem tv = data.value<WorkspaceItem>();

		const QModelIndex &mi = *mi_it;

		if(tv.Type != WorkspaceItem::TYPE_STASH)
		if(mi.column()!=0)
			continue;
		QString name = getWorkspace().getStashModel().data(mi).toString();

		QString name = mi.model()->data(mi, Qt::DisplayRole).toString();
		stashNames.append(name);
	}

}

//------------------------------------------------------------------------------
bool MainWindow::diffFile(const QString &repoFile)
{
	return fossil().diffFile(repoFile);
}
1045
1046
1047
1048
1049
1050
1051
1052
1053

1054
1055
1056
1057
1058
1059
1060
1252
1253
1254
1255
1256
1257
1258


1259
1260
1261
1262
1263
1264
1265
1266







-
-
+







		if(!diffFile(*it))
			return;
}

//------------------------------------------------------------------------------
bool MainWindow::startUI()
{
	QString port = settings.GetValue(FUEL_SETTING_HTTP_PORT).toString();
	bool started = fossil().startUI(port);
	bool started = fossil().startUI("");
	ui->actionFossilUI->setChecked(started);
	return started;
}
//------------------------------------------------------------------------------
void MainWindow::stopUI()
{
	fossil().stopUI();
1156
1157
1158
1159
1160
1161
1162
1163

1164
1165
1166
1167
1168


1169

1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183

1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199

1200
1201
1202
1203
1204
1205
1206
1362
1363
1364
1365
1366
1367
1368

1369
1370
1371
1372
1373
1374
1375
1376

1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390

1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406

1407
1408
1409
1410
1411
1412
1413
1414







-
+





+
+
-
+













-
+















-
+








//------------------------------------------------------------------------------
void MainWindow::on_actionCommit_triggered()
{
	QStringList commit_files;
	getSelectionFilenames(commit_files, WorkspaceFile::TYPE_MODIFIED, true);

	if(commit_files.empty())
	if(commit_files.empty() && !getWorkspace().otherChanges())
		return;

	QStringList commit_msgs = settings.GetValue(FUEL_SETTING_COMMIT_MSG).toStringList();

	QString msg;
	QString branch_name="";
	bool private_branch = false;
	bool aborted = !CommitDialog::run(this, tr("Commit Changes"), commit_files, msg, &commit_msgs);
	bool aborted = !CommitDialog::runCommit(this, commit_files, msg, commit_msgs, branch_name, private_branch);

	// Aborted or not we always keep the commit messages.
	// (This has saved me way too many times on TortoiseSVN)
	if(commit_msgs.indexOf(msg)==-1)
	{
		commit_msgs.push_front(msg);
		settings.SetValue(FUEL_SETTING_COMMIT_MSG, commit_msgs);
	}

	if(aborted)
		return;

	// Since via the commit dialog the user can deselect all files
	if(commit_files.empty())
	if(commit_files.empty() && !getWorkspace().otherChanges())
		return;

	// Do commit
	QStringList files;

	// When a subset of files has been selected, explicitely specify each file.
	// Otherwise all files will be implicitly committed by fossil. This is necessary
	// when committing after a merge where fossil thinks that we are trying to do
	// a partial commit which is not permitted.
	QStringList all_modified_files;
	getAllFilenames(all_modified_files, WorkspaceFile::TYPE_MODIFIED);

	if(commit_files.size() != all_modified_files.size())
		files = commit_files;

	fossil().commitFiles(files, msg);
	fossil().commitFiles(files, msg, branch_name, private_branch);
	refresh();
}

//------------------------------------------------------------------------------
void MainWindow::on_actionAdd_triggered()
{
	// Get unknown files only
1255
1256
1257
1258
1259
1260
1261
1262

1263
1264
1265
1266
1267
1268
1269
1463
1464
1465
1466
1467
1468
1469

1470
1471
1472
1473
1474
1475
1476
1477







-
+







	refresh();
}

//------------------------------------------------------------------------------
void MainWindow::on_actionRevert_triggered()
{
	QStringList modified_files;
	getSelectionFilenames(modified_files, WorkspaceFile::TYPE_EDITTED|WorkspaceFile::TYPE_ADDED|WorkspaceFile::TYPE_DELETED|WorkspaceFile::TYPE_MISSING|WorkspaceFile::TYPE_CONFLICTED);
	getSelectionFilenames(modified_files, WorkspaceFile::TYPE_MODIFIED);

	if(modified_files.empty())
		return;

	if(!FileActionDialog::run(this, tr("Revert files"), tr("The following files will be reverted.")+"\n"+tr("Are you sure?"), modified_files))
		return;

1370
1371
1372
1373
1374
1375
1376
1377

1378
1379
1380
1381
1382

1383
1384

1385
1386
1387

1388
1389
1390
1391

1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406


1407
1408
1409
1410
1411
1412
1413
1578
1579
1580
1581
1582
1583
1584

1585
1586




1587


1588



1589


1590

1591



1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602

1603
1604
1605
1606
1607
1608
1609
1610
1611







-
+

-
-
-
-
+
-
-
+
-
-
-
+
-
-

-
+
-
-
-











-
+
+







							"emansije: pt_PT\n"
					   );
}

//------------------------------------------------------------------------------
void MainWindow::on_actionUpdate_triggered()
{
	QStringList res;
	QStringList selected = selectedBranches + selectedTags;

	// Do test update
	if(!fossil().updateRepository(res, true))
		return;

	QString revision;
	// Fixme: parse "changes:      None. Already up-to-date" and avoid dialog

	if(!selected.isEmpty())
	if(res.length()==0)
		return;

		revision = selected.first();
	if(!FileActionDialog::run(this, tr("Update"), tr("The following files will be updated.")+"\n"+tr("Are you sure?"), res))
		return;

	// Do update
	updateRevision(revision);
	fossil().updateRepository(res, false);

	refresh();
}

//------------------------------------------------------------------------------
void MainWindow::loadFossilSettings()
{
	// Also retrieve the fossil global settings
	QStringList out;

	if(!fossil().getFossilSettings(out))
		return;

	QStringMap kv = MakeKeyValues(out);
	QStringMap kv;
	ParseProperties(kv, out);

	for(Settings::mappings_t::iterator it=settings.GetMappings().begin(); it!=settings.GetMappings().end(); ++it)
	{
		const QString &name = it.key();
		Settings::Setting::SettingType type = it->Type;

		// Command types we issue directly on fossil
1442
1443
1444
1445
1446
1447
1448








1449
1450
1451
1452

1453
1454
1455
1456
1457
1458
1459
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657

1658
1659
1660
1661
1662
1663
1664
1665







+
+
+
+
+
+
+
+



-
+







		}
	}
}

//------------------------------------------------------------------------------
void MainWindow::on_actionSettings_triggered()
{
	// Run the dialog
	if(!SettingsDialog::run(this, settings))
		return;
}

//------------------------------------------------------------------------------
void MainWindow::on_actionFossilSettings_triggered()
{
	loadFossilSettings();

	// Run the dialog
	if(!SettingsDialog::run(this, settings))
	if(!FslSettingsDialog::run(this, settings))
		return;

	// Apply settings
	for(Settings::mappings_t::iterator it=settings.GetMappings().begin(); it!=settings.GetMappings().end(); ++it)
	{
		const QString &name = it.key();
		Settings::Setting::SettingType type = it.value().Type;
1468
1469
1470
1471
1472
1473
1474

1475
1476
1477
1478
1479
1480
1481
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688







+







		}

		Q_ASSERT(type == Settings::Setting::TYPE_FOSSIL_GLOBAL || type == Settings::Setting::TYPE_FOSSIL_LOCAL);

		QString value = it.value().Value.toString();
		fossil().setFossilSetting(name, value, type == Settings::Setting::TYPE_FOSSIL_GLOBAL);
	}

}

//------------------------------------------------------------------------------
void MainWindow::on_actionViewModified_triggered()
{
	refresh();
}
1493
1494
1495
1496
1497
1498
1499










1500
1501
1502
1503

1504
1505



1506
1507
1508
1509
1510

1511
1512
1513




1514
1515
1516
1517
1518
1519

1520
1521
1522
1523

1524
1525

1526


1527
1528

1529



1530
1531
1532







1533
1534




1535


1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552



1553
1554





1555
1556
1557
1558
1559
1560
1561
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721


1722
1723
1724
1725
1726
1727
1728

1729
1730


1731
1732
1733
1734
1735
1736
1737
1738
1739

1740

1741
1742

1743
1744
1745
1746

1747
1748
1749

1750
1751
1752
1753
1754



1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767

1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789


1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801







+
+
+
+
+
+
+
+
+
+




+
-
-
+
+
+




-
+

-
-
+
+
+
+





-
+
-


-
+


+
-
+
+

-
+

+
+
+
-
-
-
+
+
+
+
+
+
+


+
+
+
+
-
+
+

















+
+
+
-
-
+
+
+
+
+







}

//------------------------------------------------------------------------------
void MainWindow::on_actionViewIgnored_triggered()
{
	refresh();
}

//------------------------------------------------------------------------------
void MainWindow::on_actionViewAll_triggered()
{
	ui->actionViewModified->setChecked(true);
	ui->actionViewUnchanged->setChecked(true);
	ui->actionViewUnknown->setChecked(true);
	ui->actionViewIgnored->setChecked(true);
	refresh();
}

//------------------------------------------------------------------------------
void MainWindow::on_actionViewAsList_triggered()
{
	ui->actionViewAsFolders->setChecked(!ui->actionViewAsList->isChecked());
	viewMode =  ui->actionViewAsList->isChecked() ? VIEWMODE_LIST : VIEWMODE_TREE;
	ui->workspaceTreeView->setVisible(viewMode == VIEWMODE_TREE);
	viewMode = ui->actionViewAsList->isChecked() ? VIEWMODE_LIST : VIEWMODE_TREE;

	updateWorkspaceView();
	updateFileView();
}

//------------------------------------------------------------------------------
QString MainWindow::getFossilHttpAddress()
void MainWindow::on_actionViewAsFolders_triggered()
{
	QString port = settings.GetValue(FUEL_SETTING_HTTP_PORT).toString();
	return "http://127.0.0.1:"+port;
	ui->actionViewAsList->setChecked(!ui->actionViewAsFolders->isChecked());
	viewMode = ui->actionViewAsList->isChecked() ? VIEWMODE_LIST : VIEWMODE_TREE;
	updateWorkspaceView();
	updateFileView();
}

//------------------------------------------------------------------------------
void MainWindow::onWorkspaceTreeViewSelectionChanged(const QItemSelection &/*selected*/, const QItemSelection &/*deselected*/)
{
	QModelIndexList selection = ui->workspaceTreeView->selectionModel()->selectedIndexes();
	QModelIndexList indices = ui->workspaceTreeView->selectionModel()->selectedIndexes();
	int num_selected = selection.count();

	// Do not modify the selection if nothing is selected
	if(num_selected==0)
	if(indices.empty())
		return;

	stringset_t new_dirs;
	selectedDirs.clear();
	selectedTags.clear();
	selectedBranches.clear();

	for(int i=0; i<num_selected; ++i)
	foreach(const QModelIndex &id, indices)
	{
		QVariant data = id.model()->data(id, ROLE_WORKSPACE_ITEM);
		Q_ASSERT(data.isValid());
		WorkspaceItem tv = data.value<WorkspaceItem>();
		QModelIndex index = selection.at(i);
		QString dir = getWorkspace().getDirModel().data(index, REPODIRMODEL_ROLE_PATH).toString();
		selectedDirs.insert(dir);

		if(tv.Type == WorkspaceItem::TYPE_FOLDER || tv.Type == WorkspaceItem::TYPE_WORKSPACE)
			new_dirs.insert(tv.Value);
		else if(tv.Type == WorkspaceItem::TYPE_TAG)
			selectedTags.append(tv.Value);
		else if(tv.Type == WorkspaceItem::TYPE_BRANCH)
			selectedBranches.append(tv.Value);
	}

	// Update the selection if we have any new folders
	if(!new_dirs.empty() && viewMode == VIEWMODE_TREE)
	{
		selectedDirs = new_dirs;
	updateFileView();
		updateFileView();
	}
}

//------------------------------------------------------------------------------
void MainWindow::on_actionOpenFolder_triggered()
{
	const QItemSelection &selection =  ui->workspaceTreeView->selectionModel()->selection();

	if(selection.indexes().count()!=1)
		return;

	QModelIndex index = selection.indexes().at(0);
	on_workspaceTreeView_doubleClicked(index);
}

//------------------------------------------------------------------------------
void MainWindow::on_workspaceTreeView_doubleClicked(const QModelIndex &index)
{
	QVariant data = index.model()->data(index, ROLE_WORKSPACE_ITEM);
	Q_ASSERT(data.isValid());
	WorkspaceItem tv = data.value<WorkspaceItem>();
	QString target = getWorkspace().getDirModel().data(index, REPODIRMODEL_ROLE_PATH).toString();
	target = getCurrentWorkspace() + PATH_SEPARATOR + target;

	if(tv.Type!=WorkspaceItem::TYPE_FOLDER && tv.Type!=WorkspaceItem::TYPE_WORKSPACE)
		return;

	QString target = getCurrentWorkspace() + PATH_SEPARATOR + tv.Value;

	QUrl url = QUrl::fromLocalFile(target);
	QDesktopServices::openUrl(url);
}

//------------------------------------------------------------------------------
void MainWindow::on_actionRenameFolder_triggered()
1724
1725
1726
1727
1728
1729
1730
1731

1732


1733



1734
1735
1736
1737

1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748


1749
1750
1751
1752
1753
1754
1755
1964
1965
1966
1967
1968
1969
1970

1971
1972
1973
1974

1975
1976
1977
1978
1979
1980

1981
1982
1983
1984
1985
1986
1987
1988
1989
1990


1991
1992
1993
1994
1995
1996
1997
1998
1999







-
+

+
+
-
+
+
+



-
+









-
-
+
+







//------------------------------------------------------------------------------
QMenu * MainWindow::createPopupMenu()
{
	return NULL;
}

//------------------------------------------------------------------------------
void MainWindow::on_actionViewStash_triggered()
const QIcon &MainWindow::getInternalIcon(const char* name)
{
	if(iconCache.contains(name))
		return iconCache[name];
	ui->stashTableView->setVisible(ui->actionViewStash->isChecked());

	iconCache.insert(name, QIcon(name));
	return iconCache[name];
}

//------------------------------------------------------------------------------
void MainWindow::on_actionNewStash_triggered()
void MainWindow::on_actionCreateStash_triggered()
{
	QStringList stashed_files;
	getSelectionFilenames(stashed_files, WorkspaceFile::TYPE_MODIFIED, true);

	if(stashed_files.empty())
		return;

	QString stash_name;
	bool revert = false;
	QString checkbox_text = tr("Revert stashed files");
	if(!CommitDialog::run(this, tr("Stash Changes"), stashed_files, stash_name, 0, true, &checkbox_text, &revert) || stashed_files.empty())

	if(!CommitDialog::runStashNew(this, stashed_files, stash_name, revert) || stashed_files.empty())
		return;

	stash_name = stash_name.trimmed();

	if(stash_name.indexOf("\"")!=-1 || stash_name.isEmpty())
	{
		QMessageBox::critical(this, tr("Error"), tr("Invalid stash name"));
1772
1773
1774
1775
1776
1777
1778

1779



1780
1781
1782
1783
1784
1785
1786
2016
2017
2018
2019
2020
2021
2022
2023

2024
2025
2026
2027
2028
2029
2030
2031
2032
2033







+
-
+
+
+







	refresh();
}

//------------------------------------------------------------------------------
void MainWindow::on_actionApplyStash_triggered()
{
	QStringList stashes;
	getSelectionStashes(stashes);
	getStashViewSelection(stashes);

	if(stashes.empty())
		return;

	bool delete_stashes = false;
	if(!FileActionDialog::run(this, tr("Apply Stash"), tr("The following stashes will be applied.")+"\n"+tr("Are you sure?"), stashes, tr("Delete after applying"), &delete_stashes))
		return;

	// Apply stashes
	for(QStringList::iterator it=stashes.begin(); it!=stashes.end(); ++it)
1811
1812
1813
1814
1815
1816
1817
1818

1819
1820
1821
1822
1823
1824
1825
2058
2059
2060
2061
2062
2063
2064

2065
2066
2067
2068
2069
2070
2071
2072







-
+







	refresh();
}

//------------------------------------------------------------------------------
void MainWindow::on_actionDeleteStash_triggered()
{
	QStringList stashes;
	getStashViewSelection(stashes);
	getSelectionStashes(stashes);

	if(stashes.empty())
		return;

	if(!FileActionDialog::run(this, tr("Delete Stashes"), tr("The following stashes will be deleted.")+"\n"+tr("Are you sure?"), stashes))
		return;

1839
1840
1841
1842
1843
1844
1845
1846

1847
1848
1849
1850
1851
1852
1853
2086
2087
2088
2089
2090
2091
2092

2093
2094
2095
2096
2097
2098
2099
2100







-
+







	refresh();
}

//------------------------------------------------------------------------------
void MainWindow::on_actionDiffStash_triggered()
{
	QStringList stashes;
	getStashViewSelection(stashes);
	getSelectionStashes(stashes);

	if(stashes.length() != 1)
		return;

	stashmap_t::iterator id_it = getWorkspace().getStashes().find(*stashes.begin());
	Q_ASSERT(id_it!=getWorkspace().getStashes().end());

1884
1885
1886
1887
1888
1889
1890
1891

1892
1893
1894
1895
1896
1897
1898
1899
1900
1901

1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
































1918
1919
1920
1921
1922
1923
1924
2131
2132
2133
2134
2135
2136
2137

2138
2139
2140
2141
2142
2143
2144
2145
2146
2147

2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203







-
+









-
+
















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







	menu->addAction(ui->actionClearLog);
	menu->popup(ui->textBrowser->mapToGlobal(pos));
}

//------------------------------------------------------------------------------
void MainWindow::on_fileTableView_customContextMenuRequested(const QPoint &pos)
{
	QPoint gpos = QCursor::pos();
	QPoint gpos = QCursor::pos() + QPoint(1, 1);
#ifdef Q_OS_WIN
	if(qApp->keyboardModifiers() & Qt::SHIFT)
	{
		ui->fileTableView->selectionModel()->select(ui->fileTableView->indexAt(pos), QItemSelectionModel::ClearAndSelect|QItemSelectionModel::Rows);
		QStringList fnames;
		getSelectionFilenames(fnames);

		if(fnames.size()==1)
		{
			QString fname = getCurrentWorkspace() + PATH_SEP + fnames[0];
			QString fname = getCurrentWorkspace() + PATH_SEPARATOR + fnames[0];
			fname = QDir::toNativeSeparators(fname);
			if(ShowExplorerMenu((HWND)winId(), fname, gpos))
				refresh();
		}
	}
	else
#else
	Q_UNUSED(pos);
#endif
	{
		QMenu *menu = new QMenu(this);
		menu->addActions(ui->fileTableView->actions());
		menu->popup(gpos);
	}

}

//------------------------------------------------------------------------------
void MainWindow::on_workspaceTreeView_customContextMenuRequested(const QPoint &)
{
	QModelIndexList indices = ui->workspaceTreeView->selectionModel()->selectedIndexes();

	if(indices.empty())
		return;

	QMenu *menu = 0;

	// Get first selected item
	const QModelIndex &mi = indices.first();
	QVariant data = getWorkspace().getTreeModel().data(mi, ROLE_WORKSPACE_ITEM);
	Q_ASSERT(data.isValid());
	WorkspaceItem tv = data.value<WorkspaceItem>();

	if(tv.Type == WorkspaceItem::TYPE_FOLDER ||  tv.Type == WorkspaceItem::TYPE_WORKSPACE)
		menu = menuWorkspace;
	else if (tv.Type == WorkspaceItem::TYPE_STASH || tv.Type == WorkspaceItem::TYPE_STASHES)
		menu = menuStashes;
	else if (tv.Type == WorkspaceItem::TYPE_TAG || tv.Type == WorkspaceItem::TYPE_TAGS)
		menu = menuTags;
	else if (tv.Type == WorkspaceItem::TYPE_BRANCH || tv.Type == WorkspaceItem::TYPE_BRANCHES)
		menu = menuBranches;

	if(menu)
	{
		QPoint pos = QCursor::pos() + QPoint(1, 1);
		menu->popup(pos);
	}
}

//------------------------------------------------------------------------------
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
	// Ignore drops from the same window
	if(event->source() != this)
		event->acceptProposedAction();
2012
2013
2014
2015
2016
2017
2018


2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035


2036
2037
2038
2039
2040
2041
2042
2043
2044
























































































































































2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479







+
+

















+
+









+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}

//------------------------------------------------------------------------------
void MainWindow::MainWinUICallback::beginProcess(const QString& text)
{
	Q_ASSERT(mainWindow);
	mainWindow->ui->statusBar->showMessage(text);
	mainWindow->lblTags->setHidden(true);
	mainWindow->lblRevision->setHidden(true);
	mainWindow->progressBar->setHidden(false);
	QCoreApplication::processEvents();
}

//------------------------------------------------------------------------------
void MainWindow::MainWinUICallback::updateProcess(const QString& text)
{
	Q_ASSERT(mainWindow);
	mainWindow->ui->statusBar->showMessage(text);
	QCoreApplication::processEvents();
}

//------------------------------------------------------------------------------
void MainWindow::MainWinUICallback::endProcess()
{
	Q_ASSERT(mainWindow);
	mainWindow->ui->statusBar->clearMessage();
	mainWindow->lblTags->setHidden(false);
	mainWindow->lblRevision->setHidden(false);
	mainWindow->progressBar->setHidden(true);
	QCoreApplication::processEvents();
}

//------------------------------------------------------------------------------
QMessageBox::StandardButton MainWindow::MainWinUICallback::Query(const QString &title, const QString &query, QMessageBox::StandardButtons buttons)
{
	return DialogQuery(mainWindow, title, query, buttons);
}

//------------------------------------------------------------------------------
void MainWindow::updateRevision(const QString &revision)
{
	const QString latest = tr(REVISION_LATEST);
	QString defaultval = latest;

	if(!revision.isEmpty())
		defaultval = revision;

	QString selected_revision = RevisionDialog::runUpdate(this, tr("Update workspace"), versionList, defaultval).trimmed();

	if(selected_revision.isEmpty())
		return;
	else if(selected_revision == latest)
		selected_revision = ""; // Empty revision is "latest"

	QStringList res;

	// Do test update
	if(!fossil().updateRepository(res, selected_revision, true))
		return;

	if(res.length()==0)
		return;

	QStringMap kv;
	ParseProperties(kv, res, ':');
	// If no changes exit
	if(kv.contains("changes") && kv["changes"].indexOf("None.")!=-1)
		return;

	if(!FileActionDialog::run(this, tr("Update"), tr("The following files will be updated.")+"\n"+tr("Are you sure?"), res))
		return;

	// Do update
	fossil().updateRepository(res, selected_revision, false);
	refresh();
}

//------------------------------------------------------------------------------
void MainWindow::on_actionCreateTag_triggered()
{
	// Default to current revision
	QString revision = fossil().getCurrentRevision();

	QString name;
	if(!RevisionDialog::runNewTag(this, tr("Create Tag"), versionList, revision, revision, name))
		return;

	if(name.isEmpty() || getWorkspace().getTags().contains(name) || getWorkspace().getBranches().contains(name))
	{
		QMessageBox::critical(this, tr("Error"), tr("Invalid name."), QMessageBox::Ok );
		return;
	}

	fossil().tagNew(name, revision);
	refresh();
}

//------------------------------------------------------------------------------
void MainWindow::on_actionDeleteTag_triggered()
{
	if(selectedTags.size()!=1)
		return;

	const QString &tagname = selectedTags.first();

	if(QMessageBox::Yes != DialogQuery(this, tr("Delete Tag"), tr("Are you sure want to delete the tag '%0' ?").arg(tagname)))
		return;

	Q_ASSERT(getWorkspace().getTags().contains(tagname));

	const QString &revision = getWorkspace().getTags()[tagname];

	fossil().tagDelete(tagname, revision);
	refresh();
}

//------------------------------------------------------------------------------
void MainWindow::on_actionCreateBranch_triggered()
{
	// Default to current revision
	QString revision = fossil().getCurrentRevision();

	QString branch_name;
	if(!RevisionDialog::runNewTag(this, tr("Create Branch"), versionList, revision, revision, branch_name))
		return;

	if(branch_name.isEmpty() || getWorkspace().getTags().contains(branch_name) || getWorkspace().getBranches().contains(branch_name))
	{
		QMessageBox::critical(this, tr("Error"), tr("Invalid name."), QMessageBox::Ok );
		return;
	}

	if(!fossil().branchNew(branch_name, revision, false))
		return;

	// Update to this branch.
	updateRevision(branch_name);
}
//------------------------------------------------------------------------------
void MainWindow::MergeRevision(const QString &defaultRevision)
{
	QStringList res;
	QString revision = defaultRevision;

	bool integrate = false;
	bool force = false;
	revision = RevisionDialog::runMerge(this, tr("Merge Branch"), versionList, revision, integrate, force);

	if(revision.isEmpty())
		return;

	// Do test merge
	if(!fossil().branchMerge(res, revision, integrate, force, true))
		return;

	if(!FileActionDialog::run(this, tr("Merge"), tr("The following changes will be applied.")+"\n"+tr("Are you sure?"), res))
		return;

	// Do update
	fossil().branchMerge(res, revision, integrate, force, false);

	log(tr("Merge completed. Don't forget to commit!")+"\n");

	refresh();
}

//------------------------------------------------------------------------------
void MainWindow::on_actionMergeBranch_triggered()
{
	QString revision;

	if(!selectedBranches.isEmpty())
		revision = selectedBranches.first();
	MergeRevision(revision);
}

//------------------------------------------------------------------------------
void MainWindow::onSearchBoxTextChanged(const QString &)
{
	updateFileView();
}

//------------------------------------------------------------------------------
void MainWindow::onSearch()
{
	searchBox->selectAll();
	searchBox->setFocus();
}

Changes to src/MainWindow.h.
1
2
3
4
5

6

7
8
9
10
11
12
13
1
2
3
4
5
6

7
8
9
10
11
12
13
14





+
-
+







#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QStringList>
#include <QFileIconProvider>
#include "SettingsDialog.h"
#include "Settings.h"
#include "Workspace.h"

namespace Ui {
	class MainWindow;
}

//////////////////////////////////////////////////////////////////////////
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
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







+








-
+









-
-
+

-

+
+





+














+
+







	void fullRefresh();

private:
	bool refresh();
	void scanWorkspace();
	void applySettings();
	void updateSettings();
	void updateRevision(const QString& revision);
	const QString &getCurrentWorkspace();
	void setCurrentWorkspace(const QString &workspace);
	void log(const QString &text, bool isHTML=false);
	void setStatus(const QString &text);
	bool uiRunning() const;
	void getSelectionFilenames(QStringList &filenames, int includeMask=WorkspaceFile::TYPE_ALL, bool allIfEmpty=false);
	void getFileViewSelection(QStringList &filenames, int includeMask=WorkspaceFile::TYPE_ALL, bool allIfEmpty=false);
	void getDirViewSelection(QStringList &filenames, int includeMask=WorkspaceFile::TYPE_ALL, bool allIfEmpty=false);
	void getStashViewSelection(QStringList &stashNames, bool allIfEmpty=false);
	void getSelectionStashes(QStringList &stashNames);
	void getSelectionPaths(stringset_t &paths);
	void getAllFilenames(QStringList &filenames, int includeMask=WorkspaceFile::TYPE_ALL);
	bool startUI();
	void stopUI();
	void enableActions(bool on);
	void addWorkspace(const QString &dir);
	void rebuildRecent();
	bool openWorkspace(const QString &path);
	void loadFossilSettings();
	QString getFossilHttpAddress();
	void updateDirView();
	void updateWorkspaceView();
	void updateFileView();
	void updateStashView();
	void selectRootDir();
	void MergeRevision(const QString& defaultRevision);

	void fossilBrowse(const QString &fossilUrl);
	void dragEnterEvent(class QDragEnterEvent *event);
	void dropEvent(class QDropEvent *event);
	void setBusy(bool busy);
	virtual QMenu *createPopupMenu();
	const QIcon& getInternalIcon(const char *name);

	enum ViewMode
	{
		VIEWMODE_LIST,
		VIEWMODE_TREE
	};

private slots:
	// Manual slots.
	// Use a different naming scheme to prevent warnings from Qt's automatic signaling
	void onOpenRecent();
	void onWorkspaceTreeViewSelectionChanged(const class QItemSelection &selected, const class QItemSelection &deselected);
	void onFileViewDragOut();
	void onAbort();
	void onSearchBoxTextChanged(const QString &text);
	void onSearch();

	// Designer slots
	void on_actionRefresh_triggered();
	void on_actionDiff_triggered();
	void on_actionFossilUI_triggered();
	void on_actionQuit_triggered();
	void on_actionTimeline_triggered();
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
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







+




+

+






-
-
+





+
+
+
+
+







	void on_actionRevert_triggered();
	void on_actionOpenContaining_triggered();
	void on_actionRename_triggered();
	void on_actionUndo_triggered();
	void on_actionAbout_triggered();
	void on_actionUpdate_triggered();
	void on_actionSettings_triggered();
	void on_actionFossilSettings_triggered();
	void on_actionViewUnchanged_triggered();
	void on_actionViewModified_triggered();
	void on_actionViewUnknown_triggered();
	void on_actionViewIgnored_triggered();
	void on_actionViewAll_triggered();
	void on_actionViewAsList_triggered();
	void on_actionViewAsFolders_triggered();
	void on_actionOpenFolder_triggered();
	void on_actionRenameFolder_triggered();
	void on_actionNewRepository_triggered();
	void on_actionOpenRepository_triggered();
	void on_actionCloseRepository_triggered();
	void on_actionCloneRepository_triggered();
	void on_actionViewStash_triggered();
	void on_actionNewStash_triggered();
	void on_actionCreateStash_triggered();
	void on_actionApplyStash_triggered();
	void on_actionDeleteStash_triggered();
	void on_actionDiffStash_triggered();
	void on_textBrowser_customContextMenuRequested(const QPoint &pos);
	void on_fileTableView_customContextMenuRequested(const QPoint &pos);
	void on_workspaceTreeView_customContextMenuRequested(const QPoint &pos);
	void on_actionCreateTag_triggered();
	void on_actionDeleteTag_triggered();
	void on_actionCreateBranch_triggered();
	void on_actionMergeBranch_triggered();

private:
	class MainWinUICallback : public UICallback
	{
	public:
		MainWinUICallback() : mainWindow(0)
		{}
139
140
141
142
143
144
145


146


147
148


149







150
151



152
153
154
155
156
157
158
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







+
+

+
+


+
+

+
+
+
+
+
+
+


+
+
+







	friend class MainWinUICallback;

	enum
	{
		MAX_RECENT=5
	};

	typedef QMap<QString, QIcon> icon_map_t;

	Ui::MainWindow		*ui;
	QFileIconProvider	iconProvider;
	icon_map_t			iconCache;
	class QAction		*recentWorkspaceActs[MAX_RECENT];
	class QProgressBar	*progressBar;
	class QLabel		*lblRevision;
	class QLabel		*lblTags;
	class QShortcut		*abortShortcut;
	class SearchBox		*searchBox;
	class QShortcut		*searchShortcut;
	QMenu				*menuWorkspace;
	QMenu				*menuStashes;
	QMenu				*menuTags;
	QMenu				*menuBranches;

	bool				operationAborted;
	stringset_t			selectedDirs;	// The directory selected in the tree
	QStringList			selectedTags;
	QStringList			selectedBranches;
	QStringList			versionList;

	Workspace			workspace;
	Workspace &			getWorkspace() { return workspace; }

	Fossil &			fossil() { return workspace.fossil(); }
	const Fossil &		fossil() const { return workspace.fossil(); }

Added src/RevisionDialog.cpp.




























































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#include "RevisionDialog.h"
#include "ui_RevisionDialog.h"
#include "Utils.h"

//-----------------------------------------------------------------------------
RevisionDialog::RevisionDialog(QWidget *parent, const QStringList &completions, const QString &defaultValue) :
	QDialog(parent),
	ui(new Ui::RevisionDialog),
	completer(completions, parent)
{
	ui->setupUi(this);
	ui->cmbRevision->setCompleter(&completer);

	ui->cmbRevision->addItems(completions);

	if(!defaultValue.isEmpty())
		ui->cmbRevision->setCurrentText(defaultValue);
}

//-----------------------------------------------------------------------------
RevisionDialog::~RevisionDialog()
{
	delete ui;
}

//-----------------------------------------------------------------------------
QString RevisionDialog::runUpdate(QWidget *parent, const QString &title, const QStringList &completions, const QString &defaultValue)
{
	RevisionDialog dlg(parent, completions, defaultValue);
	dlg.setWindowTitle(title);
	dlg.ui->lblName->setVisible(false);
	dlg.ui->lineName->setVisible(false);
	dlg.ui->lblIntegrate->setVisible(false);
	dlg.ui->chkIntegrate->setVisible(false);
	dlg.ui->lblForce->setVisible(false);
	dlg.ui->chkForce->setVisible(false);

	dlg.adjustSize();

	if(dlg.exec() != QDialog::Accepted)
		return QString("");
	return dlg.ui->cmbRevision->currentText().trimmed();
}

//-----------------------------------------------------------------------------
QString RevisionDialog::runMerge(QWidget *parent, const QString &title, const QStringList &completions, const QString &defaultValue, bool &integrate, bool &force)
{
	RevisionDialog dlg(parent, completions, defaultValue);
	dlg.setWindowTitle(title);
	dlg.ui->lblName->setVisible(false);
	dlg.ui->lineName->setVisible(false);
	dlg.ui->lblIntegrate->setVisible(true);
	dlg.ui->chkIntegrate->setVisible(true);
	dlg.ui->chkIntegrate->setChecked(integrate);
	dlg.ui->lblForce->setVisible(true);
	dlg.ui->chkForce->setVisible(true);
	dlg.ui->chkForce->setChecked(force);

	dlg.adjustSize();

	if(dlg.exec() != QDialog::Accepted)
		return QString("");

	integrate = dlg.ui->chkIntegrate->checkState() == Qt::Checked;
	force = dlg.ui->chkForce->checkState() == Qt::Checked;

	return dlg.ui->cmbRevision->currentText().trimmed();
}


//-----------------------------------------------------------------------------
bool RevisionDialog::runNewTag(QWidget *parent, const QString &title, const QStringList &completions, const QString &defaultValue, QString &revision, QString &name)
{
	RevisionDialog dlg(parent, completions, defaultValue);
	dlg.setWindowTitle(title);

	dlg.ui->lblName->setVisible(true);
	dlg.ui->lineName->setVisible(true);
	dlg.ui->lblIntegrate->setVisible(false);
	dlg.ui->chkIntegrate->setVisible(false);
	dlg.ui->lblForce->setVisible(false);
	dlg.ui->chkForce->setVisible(false);

	dlg.adjustSize();

	if(dlg.exec() != QDialog::Accepted)
		return false;

	revision = dlg.ui->cmbRevision->currentText().trimmed();
	name = dlg.ui->lineName->text().trimmed();
	return true;
}
Added src/RevisionDialog.h.




























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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#ifndef REVISIONDIALOG_H
#define REVISIONDIALOG_H

#include <QDialog>
#include <QCompleter>

namespace Ui {
	class RevisionDialog;
}

class RevisionDialog : public QDialog
{
	Q_OBJECT

public:
	explicit RevisionDialog(QWidget *parent, const QStringList &completions, const QString &defaultValue);
	~RevisionDialog();

	static QString runUpdate(QWidget *parent, const QString &title, const QStringList &completions, const QString &defaultValue);
	static QString runMerge(QWidget* parent, const QString& title, const QStringList& completions, const QString& defaultValue, bool& integrate, bool& force);
	static bool runNewTag(QWidget *parent, const QString &title, const QStringList &completions, const QString &defaultValue, QString &revision, QString &name);

private:
	Ui::RevisionDialog *ui;
	QCompleter	completer;
};

#endif // REVISIONDIALOG_H
Added src/SearchBox.cpp.
























1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#include "SearchBox.h"
#include <QKeyEvent>

SearchBox::SearchBox(QWidget *parent) : QLineEdit(parent)
{
}

SearchBox::~SearchBox()
{

}

void SearchBox::keyPressEvent(QKeyEvent *event)
{
	// Clear text on escape
	if(event->key() == Qt::Key_Escape)
	{
		setText("");
		clearFocus();
	}
	else
		QLineEdit::keyPressEvent(event);
}

Added src/SearchBox.h.























1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#ifndef SEARCHBOX_H
#define SEARCHBOX_H

#include <QLineEdit>

class SearchBox : public QLineEdit
{
	Q_OBJECT
public:
	explicit SearchBox(QWidget* parent=0);
	~SearchBox();

signals:

public slots:

protected:
	void keyPressEvent(QKeyEvent *event);

};


#endif // SEARCHBOX_H
Added src/Settings.cpp.




























































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#include "Settings.h"

#include <QSettings>
#include <QCoreApplication>
#include <QDir>
#include <QTranslator>
#include <QResource>
#include <QTextCodec>

///////////////////////////////////////////////////////////////////////////////
Settings::Settings(bool portableMode) : store(0)
{
	Mappings.insert(FOSSIL_SETTING_GDIFF_CMD, Setting("", Setting::TYPE_FOSSIL_GLOBAL));
	Mappings.insert(FOSSIL_SETTING_GMERGE_CMD, Setting("", Setting::TYPE_FOSSIL_GLOBAL));
	Mappings.insert(FOSSIL_SETTING_PROXY_URL, Setting("", Setting::TYPE_FOSSIL_GLOBAL));
	Mappings.insert(FOSSIL_SETTING_HTTP_PORT, Setting("", Setting::TYPE_FOSSIL_GLOBAL));

	Mappings.insert(FOSSIL_SETTING_IGNORE_GLOB, Setting("", Setting::TYPE_FOSSIL_LOCAL));
	Mappings.insert(FOSSIL_SETTING_CRNL_GLOB, Setting("", Setting::TYPE_FOSSIL_LOCAL));
	Mappings.insert(FOSSIL_SETTING_REMOTE_URL, Setting("off", Setting::TYPE_FOSSIL_COMMAND));

	// Go into portable mode when explicitly requested or if a config file exists next to the executable
	QString ini_path = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + QDir::separator() + QCoreApplication::applicationName() + ".ini");
	if( portableMode || QFile::exists(ini_path))
		store = new QSettings(ini_path, QSettings::IniFormat);
	else
	{
		// Linux: ~/.config/organizationName/applicationName.conf
		// Windows: HKEY_CURRENT_USER\Software\organizationName\Fuel
		store = new QSettings(QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
	}
	Q_ASSERT(store);

	if(!HasValue(FUEL_SETTING_FILE_DBLCLICK))
		SetValue(FUEL_SETTING_FILE_DBLCLICK, 0);
	if(!HasValue(FUEL_SETTING_LANGUAGE) && SupportsLang(QLocale::system().name()))
		SetValue(FUEL_SETTING_LANGUAGE, QLocale::system().name());
	if(!HasValue(FUEL_SETTING_WEB_BROWSER))
		SetValue(FUEL_SETTING_WEB_BROWSER, 0);

	ApplyEnvironment();
}

//-----------------------------------------------------------------------------
Settings::~Settings()
{
	Q_ASSERT(store);
	delete store;
}

//-----------------------------------------------------------------------------
void Settings::ApplyEnvironment()
{
	QString lang_id = GetValue(FUEL_SETTING_LANGUAGE).toString();
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
	QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8"));
#endif
	if(!InstallLang(lang_id))
		SetValue(FUEL_SETTING_LANGUAGE, "en_US");
}

//-----------------------------------------------------------------------------
bool Settings::InstallLang(const QString &langId)
{
	if(langId == "en_US")
	{
		QCoreApplication::instance()->removeTranslator(&translator);
		return true;
	}

	QString locale_path = QString(":intl/intl/%0.qm").arg(langId);
	if(!translator.load(locale_path))
		return false;

	Q_ASSERT(!translator.isEmpty());
	QCoreApplication::instance()->installTranslator(&translator);


	return true;
}

//-----------------------------------------------------------------------------
bool Settings::HasValue(const QString &name) const
{
	return store->contains(name);
}

//-----------------------------------------------------------------------------
const QVariant Settings::GetValue(const QString &name)
{
	if(!HasValue(name))
		return QVariant();
	return store->value(name);
}

//-----------------------------------------------------------------------------
void Settings::SetValue(const QString &name, const QVariant &value)
{
	store->setValue(name, value);
}

//-----------------------------------------------------------------------------
QVariant &Settings::GetFossilValue(const QString &name)
{
	mappings_t::iterator it=Mappings.find(name);
	Q_ASSERT(it!=Mappings.end());
	return it.value().Value;
}

//-----------------------------------------------------------------------------
void Settings::SetFossilValue(const QString &name, const QVariant &value)
{
	mappings_t::iterator it=Mappings.find(name);
	Q_ASSERT(it!=Mappings.end());
	it->Value = value;
}

//-----------------------------------------------------------------------------
bool Settings::SupportsLang(const QString &langId) const
{
	QString locale_path = QString(":intl/intl/%0.qm").arg(langId);
	QResource res(locale_path);
	return res.isValid();
}
Added src/Settings.h.











































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#ifndef SETTINGS_H
#define SETTINGS_H

#include <QMap>
#include <QVariant>
#include <QTranslator>

#define FUEL_SETTING_FOSSIL_PATH			"FossilPath"
#define FUEL_SETTING_COMMIT_MSG				"CommitMsgHistory"
#define FUEL_SETTING_FILE_DBLCLICK			"FileDblClickAction"
#define FUEL_SETTING_LANGUAGE				"Language"
#define FUEL_SETTING_WEB_BROWSER			"WebBrowser"

#define FOSSIL_SETTING_GDIFF_CMD			"gdiff-command"
#define FOSSIL_SETTING_GMERGE_CMD			"gmerge-command"
#define FOSSIL_SETTING_PROXY_URL			"proxy"
#define FOSSIL_SETTING_IGNORE_GLOB			"ignore-glob"
#define FOSSIL_SETTING_CRNL_GLOB			"crnl-glob"
#define FOSSIL_SETTING_REMOTE_URL			"remote-url"
#define FOSSIL_SETTING_HTTP_PORT			"http-port"


enum FileDblClickAction
{
	FILE_DLBCLICK_ACTION_DIFF,
	FILE_DLBCLICK_ACTION_OPEN,
	FILE_DLBCLICK_ACTION_OPENCONTAINING,
	FILE_DLBCLICK_ACTION_MAX
};

struct Settings
{
	struct Setting
	{
		enum SettingType
		{
			TYPE_FOSSIL_GLOBAL,
			TYPE_FOSSIL_LOCAL,
			TYPE_FOSSIL_COMMAND
		};

		Setting(QVariant value, SettingType type) : Value(value), Type(type)
		{}
		QVariant Value;
		SettingType Type;
	};
	typedef QMap<QString, Setting> mappings_t;


	Settings(bool portableMode = false);
	~Settings();

	void				ApplyEnvironment();

	// App configuration access
	class QSettings *	GetStore() { return store; }
	bool				HasValue(const QString &name) const; // store->contains(FUEL_SETTING_FOSSIL_PATH)
	const QVariant		GetValue(const QString &name); // settings.store->value
	void				SetValue(const QString &name, const QVariant &value); // settings.store->value

	// Fossil configuration access
	QVariant &		GetFossilValue(const QString &name);
	void			SetFossilValue(const QString &name, const QVariant &value);
	mappings_t &	GetMappings() { return Mappings; }

	bool			SupportsLang(const QString &langId) const;
	bool			InstallLang(const QString &langId);
private:
	mappings_t		Mappings;
	class QSettings	*store;
	QTranslator		translator;
};


#endif // SETTINGS_H
Changes to src/SettingsDialog.cpp.
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
1
2

3
4


5


























6
7
8
9
10
11
12


-


-
-

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







#include "SettingsDialog.h"
#include "ui_SettingsDialog.h"
#include <QFileDialog>
#include "Utils.h"

#include <QSettings>
#include <QCoreApplication>
#include <QDir>
#include <QTranslator>
#include <QResource>
#include <QTextCodec>


///////////////////////////////////////////////////////////////////////////////
QString SettingsDialog::SelectExe(QWidget *parent, const QString &description)
{
	QString filter(tr("Applications"));
#ifdef Q_OS_WIN
	filter += " (*.exe)";
#else
	filter += " (*)";
#endif
	QString path = QFileDialog::getOpenFileName(
				parent,
				description,
				QString(),
				filter,
				&filter);

	if(!QFile::exists(path))
		return QString();

	return path;
}

///////////////////////////////////////////////////////////////////////////////
SettingsDialog::SettingsDialog(QWidget *parent, Settings &_settings) :
	QDialog(parent, Qt::Sheet),
	ui(new Ui::SettingsDialog),
	settings(&_settings)
{
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
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







-











-
-
-
-
-
-
-
-
-







	ui->cmbFossilBrowser->addItem(tr("System"));
	ui->cmbFossilBrowser->addItem(tr("Internal"));

	// App Settings
	ui->lineFossilPath->setText(QDir::toNativeSeparators(settings->GetValue(FUEL_SETTING_FOSSIL_PATH).toString()));
	ui->cmbDoubleClickAction->setCurrentIndex(settings->GetValue(FUEL_SETTING_FILE_DBLCLICK).toInt());
	ui->cmbFossilBrowser->setCurrentIndex(settings->GetValue(FUEL_SETTING_WEB_BROWSER).toInt());
	ui->lineUIPort->setText(settings->GetValue(FUEL_SETTING_HTTP_PORT).toString());

	// Initialize language combo
	foreach(const LangMap &m, langMap)
		ui->cmbActiveLanguage->addItem(m.name);

	QString lang = settings->GetValue(FUEL_SETTING_LANGUAGE).toString();
	// Select current language
	ui->cmbActiveLanguage->setCurrentIndex(
				ui->cmbActiveLanguage->findText(
					LangIdToName(lang)));

	// Global Settings
	ui->lineGDiffCommand->setText(settings->GetFossilValue(FOSSIL_SETTING_GDIFF_CMD).toString());
	ui->lineGMergeCommand->setText(settings->GetFossilValue(FOSSIL_SETTING_GMERGE_CMD).toString());
	ui->lineProxy->setText(settings->GetFossilValue(FOSSIL_SETTING_PROXY_URL).toString());

	// Repository Settings
	ui->lineRemoteURL->setText(settings->GetFossilValue(FOSSIL_SETTING_REMOTE_URL).toString());
	ui->lineIgnore->setText(settings->GetFossilValue(FOSSIL_SETTING_IGNORE_GLOB).toString());
	ui->lineIgnoreCRNL->setText(settings->GetFossilValue(FOSSIL_SETTING_CRNL_GLOB).toString());
}

//-----------------------------------------------------------------------------
SettingsDialog::~SettingsDialog()
{
	delete ui;
}
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
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







-









-
-
-
-
-
-
-
-
-












-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







//-----------------------------------------------------------------------------
void SettingsDialog::on_buttonBox_accepted()
{
	settings->SetValue(FUEL_SETTING_FOSSIL_PATH, QDir::fromNativeSeparators(ui->lineFossilPath->text()));
	Q_ASSERT(ui->cmbDoubleClickAction->currentIndex()>=FILE_DLBCLICK_ACTION_DIFF && ui->cmbDoubleClickAction->currentIndex()<FILE_DLBCLICK_ACTION_MAX);
	settings->SetValue(FUEL_SETTING_FILE_DBLCLICK, ui->cmbDoubleClickAction->currentIndex());
	settings->SetValue(FUEL_SETTING_WEB_BROWSER, ui->cmbFossilBrowser->currentIndex());
	settings->SetValue(FUEL_SETTING_HTTP_PORT, ui->lineUIPort->text());

	Q_ASSERT(settings->HasValue(FUEL_SETTING_LANGUAGE));
	QString curr_langid = settings->GetValue(FUEL_SETTING_LANGUAGE).toString();
	QString new_langid = LangNameToId(ui->cmbActiveLanguage->currentText());
	Q_ASSERT(!new_langid.isEmpty());
	settings->SetValue(FUEL_SETTING_LANGUAGE, new_langid);

	if(curr_langid != new_langid)
		QMessageBox::information(this, tr("Restart required"), tr("The language change will take effect after restarting the application"), QMessageBox::Ok);

	settings->SetFossilValue(FOSSIL_SETTING_GDIFF_CMD, ui->lineGDiffCommand->text());
	settings->SetFossilValue(FOSSIL_SETTING_GMERGE_CMD, ui->lineGMergeCommand->text());
	settings->SetFossilValue(FOSSIL_SETTING_PROXY_URL, ui->lineProxy->text());

	settings->SetFossilValue(FOSSIL_SETTING_REMOTE_URL, ui->lineRemoteURL->text());
	settings->SetFossilValue(FOSSIL_SETTING_IGNORE_GLOB, ui->lineIgnore->text());
	settings->SetFossilValue(FOSSIL_SETTING_CRNL_GLOB, ui->lineIgnoreCRNL->text());


	settings->ApplyEnvironment();
}

//-----------------------------------------------------------------------------
void SettingsDialog::on_btnSelectFossil_clicked()
{
	QString path = SelectExe(this, tr("Select Fossil executable"));
	if(!path.isEmpty())
		ui->lineFossilPath->setText(QDir::toNativeSeparators(path));
}

//-----------------------------------------------------------------------------
void SettingsDialog::on_btnSelectFossilGDiff_clicked()
{
	QString path = SelectExe(this, tr("Select Graphical Diff application"));
	if(!path.isEmpty())
		ui->lineGDiffCommand->setText(QDir::toNativeSeparators(path));
}

//-----------------------------------------------------------------------------
void SettingsDialog::on_btnSelectGMerge_clicked()
{
	QString path = SelectExe(this, tr("Select Graphical Merge application"));
	if(!path.isEmpty())
		ui->lineGMergeCommand->setText(path);
}

//-----------------------------------------------------------------------------
void SettingsDialog::on_btnClearMessageHistory_clicked()
{
	if(DialogQuery(this, tr("Clear Commit Message History"), tr("Are you sure you want to clear the commit message history?"))==QMessageBox::Yes)
		settings->SetValue(FUEL_SETTING_COMMIT_MSG, QStringList());
}

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
117
118
119
120
121
122
123




























































































































-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
	{
		if(m.name == name)
			return m.id;
	}

	return "";
}

///////////////////////////////////////////////////////////////////////////////
Settings::Settings(bool portableMode) : store(0)
{
	Mappings.insert(FOSSIL_SETTING_GDIFF_CMD, Setting("", Setting::TYPE_FOSSIL_GLOBAL));
	Mappings.insert(FOSSIL_SETTING_GMERGE_CMD, Setting("", Setting::TYPE_FOSSIL_GLOBAL));
	Mappings.insert(FOSSIL_SETTING_PROXY_URL, Setting("", Setting::TYPE_FOSSIL_GLOBAL));

	Mappings.insert(FOSSIL_SETTING_IGNORE_GLOB, Setting("", Setting::TYPE_FOSSIL_LOCAL));
	Mappings.insert(FOSSIL_SETTING_CRNL_GLOB, Setting("", Setting::TYPE_FOSSIL_LOCAL));
	Mappings.insert(FOSSIL_SETTING_REMOTE_URL, Setting("off", Setting::TYPE_FOSSIL_COMMAND));

	// Go into portable mode when explicitly requested or if a config file exists next to the executable
	QString ini_path = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + QDir::separator() + QCoreApplication::applicationName() + ".ini");
	if( portableMode || QFile::exists(ini_path))
		store = new QSettings(ini_path, QSettings::IniFormat);
	else
	{
		// Linux: ~/.config/organizationName/applicationName.conf
		// Windows: HKEY_CURRENT_USER\Software\organizationName\Fuel
		store = new QSettings(QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
	}
	Q_ASSERT(store);

	if(!HasValue(FUEL_SETTING_FILE_DBLCLICK))
		SetValue(FUEL_SETTING_FILE_DBLCLICK, 0);
	if(!HasValue(FUEL_SETTING_LANGUAGE) && SupportsLang(QLocale::system().name()))
		SetValue(FUEL_SETTING_LANGUAGE, QLocale::system().name());
	if(!HasValue(FUEL_SETTING_WEB_BROWSER))
		SetValue(FUEL_SETTING_WEB_BROWSER, 0);
	if(!HasValue(FUEL_SETTING_HTTP_PORT))
		SetValue(FUEL_SETTING_HTTP_PORT, "8090");

	ApplyEnvironment();
}

//-----------------------------------------------------------------------------
Settings::~Settings()
{
	Q_ASSERT(store);
	delete store;
}

//-----------------------------------------------------------------------------
void Settings::ApplyEnvironment()
{
	QString lang_id = GetValue(FUEL_SETTING_LANGUAGE).toString();
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
	QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8"));
#endif
	if(!InstallLang(lang_id))
		SetValue(FUEL_SETTING_LANGUAGE, "en_US");
}

//-----------------------------------------------------------------------------
bool Settings::InstallLang(const QString &langId)
{
	if(langId == "en_US")
	{
		QCoreApplication::instance()->removeTranslator(&translator);
		return true;
	}

	QString locale_path = QString(":intl/intl/%0.qm").arg(langId);
	if(!translator.load(locale_path))
		return false;

	Q_ASSERT(!translator.isEmpty());
	QCoreApplication::instance()->installTranslator(&translator);


	return true;
}

//-----------------------------------------------------------------------------
bool Settings::HasValue(const QString &name) const
{
	return store->contains(name);
}

//-----------------------------------------------------------------------------
const QVariant Settings::GetValue(const QString &name)
{
	if(!HasValue(name))
		return QVariant();
	return store->value(name);
}

//-----------------------------------------------------------------------------
void Settings::SetValue(const QString &name, const QVariant &value)
{
	store->setValue(name, value);
}

//-----------------------------------------------------------------------------
QVariant &Settings::GetFossilValue(const QString &name)
{
	mappings_t::iterator it=Mappings.find(name);
	Q_ASSERT(it!=Mappings.end());
	return it.value().Value;
}

//-----------------------------------------------------------------------------
void Settings::SetFossilValue(const QString &name, const QVariant &value)
{
	mappings_t::iterator it=Mappings.find(name);
	Q_ASSERT(it!=Mappings.end());
	it->Value = value;
}

//-----------------------------------------------------------------------------
bool Settings::SupportsLang(const QString &langId) const
{
	QString locale_path = QString(":intl/intl/%0.qm").arg(langId);
	QResource res(locale_path);
	return res.isValid();
}
Changes to src/SettingsDialog.h.
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
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




-
+
-
-

-



-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-















-
-



-







#ifndef SETTINGSDIALOG_H
#define SETTINGSDIALOG_H

#include <QDialog>
#include <QMap>
#include "Settings.h"
#include <QVariant>
#include <QTranslator>


namespace Ui {
	class SettingsDialog;
}

#define FUEL_SETTING_FOSSIL_PATH			"FossilPath"
#define FUEL_SETTING_COMMIT_MSG				"CommitMsgHistory"
#define FUEL_SETTING_FILE_DBLCLICK			"FileDblClickAction"
#define FUEL_SETTING_LANGUAGE				"Language"
#define FUEL_SETTING_WEB_BROWSER			"WebBrowser"
#define FUEL_SETTING_HTTP_PORT				"HTTPPort"

#define FOSSIL_SETTING_GDIFF_CMD			"gdiff-command"
#define FOSSIL_SETTING_GMERGE_CMD			"gmerge-command"
#define FOSSIL_SETTING_PROXY_URL			"proxy"
#define FOSSIL_SETTING_IGNORE_GLOB			"ignore-glob"
#define FOSSIL_SETTING_CRNL_GLOB			"crnl-glob"
#define FOSSIL_SETTING_REMOTE_URL			"remote-url"


enum FileDblClickAction
{
	FILE_DLBCLICK_ACTION_DIFF,
	FILE_DLBCLICK_ACTION_OPEN,
	FILE_DLBCLICK_ACTION_OPENCONTAINING,
	FILE_DLBCLICK_ACTION_MAX
};

struct Settings
{
	struct Setting
	{
		enum SettingType
		{
			TYPE_FOSSIL_GLOBAL,
			TYPE_FOSSIL_LOCAL,
			TYPE_FOSSIL_COMMAND
		};

		Setting(QVariant value, SettingType type) : Value(value), Type(type)
		{}
		QVariant Value;
		SettingType Type;
	};
	typedef QMap<QString, Setting> mappings_t;


	Settings(bool portableMode = false);
	~Settings();

	void				ApplyEnvironment();

	// App configuration access
	class QSettings *	GetStore() { return store; }
	bool				HasValue(const QString &name) const; // store->contains(FUEL_SETTING_FOSSIL_PATH)
	const QVariant		GetValue(const QString &name); // settings.store->value
	void				SetValue(const QString &name, const QVariant &value); // settings.store->value

	// Fossil configuration access
	QVariant &		GetFossilValue(const QString &name);
	void			SetFossilValue(const QString &name, const QVariant &value);
	mappings_t &	GetMappings() { return Mappings; }

	bool			SupportsLang(const QString &langId) const;
	bool			InstallLang(const QString &langId);
private:
	mappings_t		Mappings;
	class QSettings	*store;
	QTranslator		translator;
};


class SettingsDialog : public QDialog
{
	Q_OBJECT

public:
	explicit SettingsDialog(QWidget *parent, Settings &_settings);
	~SettingsDialog();

	static bool run(QWidget *parent, Settings &_settings);


private slots:
	void on_btnSelectFossil_clicked();
	void on_buttonBox_accepted();
	void on_btnSelectFossilGDiff_clicked();
	void on_btnSelectGMerge_clicked();
	void on_btnClearMessageHistory_clicked();

private:
	static QString SelectExe(QWidget *parent, const QString &description);
	QString LangIdToName(const QString &id);
	QString LangNameToId(const QString &name);
	void CreateLangMap();

	struct LangMap
	{
		LangMap(const QString &_id, const QString &_name)
Changes to src/Utils.cpp.
1
2
3

4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
11



+







#include "Utils.h"
#include <QMessageBox>
#include <QDialogButtonBox>
#include <QFileDialog>

///////////////////////////////////////////////////////////////////////////////
QMessageBox::StandardButton DialogQuery(QWidget *parent, const QString &title, const QString &query, QMessageBox::StandardButtons buttons)
{
	QMessageBox mb(QMessageBox::Question, title, query, buttons, parent, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::Sheet );
	mb.setDefaultButton(QMessageBox::No);
	mb.setWindowModality(Qt::WindowModal);
25
26
27
28
29
30
31





















32
33
34
35
36
37
38
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







{
	QStringList res;
	for(int i=0; i<paths.size(); ++i)
		res.append(QuotePath(paths[i]));
	return res;
}

//-----------------------------------------------------------------------------
QString SelectExe(QWidget *parent, const QString &description)
{
	QString filter(QObject::tr("Applications"));
#ifdef Q_OS_WIN
	filter += " (*.exe)";
#else
	filter += " (*)";
#endif
	QString path = QFileDialog::getOpenFileName(
				parent,
				description,
				QString(),
				filter,
				&filter);

	if(!QFile::exists(path))
		return QString();

	return path;
}
//-----------------------------------------------------------------------------
#if 0 // Unused
#include <QInputDialog>

static bool DialogQueryText(QWidget *parent, const QString &title, const QString &query, QString &text, bool isPassword=false)
{
	QInputDialog dlg(parent, Qt::Sheet);
302
303
304
305
306
307
308





























































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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
	pMalloc->Release ();

	return bResult;
}

#endif

//-----------------------------------------------------------------------------
void ParseProperties(QStringMap &properties, const QStringList &lines, QChar separator)
{
	properties.clear();
	foreach(QString l, lines)
	{
		l = l.trimmed();
		int index = l.indexOf(separator);

		QString key;
		QString value;
		if(index!=-1)
		{
			key = l.left(index).trimmed();
			value = l.mid(index+1).trimmed();
		}
		else
			key = l;

		properties.insert(key, value);
	}
}


//------------------------------------------------------------------------------
void GetStandardItemTextRecursive(QString &name, const QStandardItem &item, const QChar &separator)
{
	if(item.parent())
	{
		GetStandardItemTextRecursive(name, *item.parent());
		name.append(separator);
	}

	name.append(item.data(Qt::DisplayRole).toString());
}

//------------------------------------------------------------------------------
void BuildNameToModelIndex(name_modelindex_map_t &map, const QStandardItem &item)
{
	QString name;
	GetStandardItemTextRecursive(name, item);
	map.insert(name, item.index());

	for(int i=0; i<item.rowCount(); ++i)
	{
		const QStandardItem *child = item.child(i);
		Q_ASSERT(child);
		BuildNameToModelIndex(map, *child);
	}
}

//------------------------------------------------------------------------------
void BuildNameToModelIndex(name_modelindex_map_t &map, const QStandardItemModel &model)
{
	for(int i=0; i<model.rowCount(); ++i)
	{
		const QStandardItem *item = model.item(i);
		Q_ASSERT(item);
		BuildNameToModelIndex(map, *item);
	}
}
Changes to src/Utils.h.
1
2
3
4
5


6
7
8
9
10
11
12
13
14
15











16
17
18
19
20
21
22
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





+
+










+
+
+
+
+
+
+
+
+
+
+







#ifndef UTILS_H
#define UTILS_H

#include <QString>
#include <QMessageBox>
#include <QMap>
#include <QStandardItem>

#define COUNTOF(array)			(sizeof(array)/sizeof(array[0]))
#define FOSSIL_CHECKOUT1	"_FOSSIL_"
#define FOSSIL_CHECKOUT2	".fslckout"
#define FOSSIL_EXT			"fossil"


QMessageBox::StandardButton DialogQuery(QWidget *parent, const QString &title, const QString &query, QMessageBox::StandardButtons buttons = QMessageBox::Yes|QMessageBox::No);
QString						QuotePath(const QString &path);
QStringList					QuotePaths(const QStringList &paths);
QString						SelectExe(QWidget *parent, const QString &description);


typedef QMap<QString, QModelIndex> name_modelindex_map_t;
void						GetStandardItemTextRecursive(QString &name, const QStandardItem &item, const QChar &separator='/');
void						BuildNameToModelIndex(name_modelindex_map_t &map, const QStandardItem &item);
void						BuildNameToModelIndex(name_modelindex_map_t &map, const QStandardItemModel &model);


typedef QMap<QString, QString> QStringMap;
void						ParseProperties(QStringMap &properties, const QStringList &lines, QChar separator=' ');

#ifdef Q_OS_WIN
	bool ShowExplorerMenu(HWND hwnd, const QString &path, const QPoint &qpoint);
#endif

class UICallback
{
Changes to src/Workspace.cpp.
13
14
15
16
17
18
19




20
21
22
23
24
25
26
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30







+
+
+
+







{
	// Dispose RepoFiles
	foreach(WorkspaceFile *r, getFiles())
		delete r;

	getFiles().clear();
	getPaths().clear();
	stashMap.clear();
	branchList.clear();
	tags.clear();
	isIntegrated = false;
}

//------------------------------------------------------------------------------
bool Workspace::scanDirectory(QFileInfoList &entries, const QString& dirPath, const QString &baseDir, const QString ignoreSpec, const bool &abort, UICallback &uiCallback)
{
	QDir dir(dirPath);

112
113
114
115
116
117
118




119
120


121
122
123
124
125
126
127
116
117
118
119
120
121
122
123
124
125
126


127
128
129
130
131
132
133
134
135







+
+
+
+
-
-
+
+








	for(QStringList::iterator line_it=res.begin(); line_it!=res.end(); ++line_it)
	{
		QString line = (*line_it).trimmed();
		if(line.length()==0)
			continue;

		int space_index = line.indexOf(' ');
		if(space_index==-1)
			continue;

		QString status_text = line.left(10).trimmed();
		QString fname = line.right(line.length() - 10).trimmed();
		QString status_text = line.left(space_index);
		QString fname = line.right(line.length() - space_index).trimmed();
		WorkspaceFile::Type type = WorkspaceFile::TYPE_UNKNOWN;

		// Generate a RepoFile for all non-existant fossil files
		// or for all files if we skipped scanning the workspace
		bool add_missing = !scan_files;

		if(status_text=="EDITED")
140
141
142
143
144
145
146


147
148
149
150
151
152
153
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163







+
+







		}
		else if(status_text=="RENAMED")
			type = WorkspaceFile::TYPE_RENAMED;
		else if(status_text=="UNCHANGED")
			type = WorkspaceFile::TYPE_UNCHANGED;
		else if(status_text=="CONFLICT")
			type = WorkspaceFile::TYPE_CONFLICTED;
		else if(status_text=="UPDATED_BY_MERGE" || status_text=="ADDED_BY_MERGE" || status_text=="ADDED_BY_INTEGRATE" || status_text=="UPDATED_BY_INTEGRATE")
			type = WorkspaceFile::TYPE_MERGED;

		// Filter unwanted file types
		if( ((type & WorkspaceFile::TYPE_MODIFIED) && !scanModified) ||
			((type & WorkspaceFile::TYPE_UNCHANGED) && !scanUnchanged))
		{
			getFiles().remove(fname);
			continue;
174
175
176
177
178
179
180













181

182









183
184
185
186
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







+
+
+
+
+
+
+
+
+
+
+
+
+
-
+

+
+
+
+
+
+
+
+
+





		rf->setType(type);

		QString path = rf->getPath();
		getPaths().insert(path);
	}

	// Check if the repository needs integration
	res.clear();
	fossil().status(res);
	isIntegrated = false;
	foreach(const QString &l, res)
	{
		if(l.trimmed().indexOf("INTEGRATE")==0)
		{
			isIntegrated = true;
			break;
		}
	}

	// Load the stash
	// Load the stashes, branches and tags
	fossil().stashList(getStashes());

	fossil().branchList(branchList, branchList);

	fossil().tagList(tags);
	// Fossil includes the branches in the tag list
	// So remove them
	foreach(const QString &name, branchList)
		tags.remove(name);

_done:
	uiCallback.endProcess();
}

Changes to src/Workspace.h.
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
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








+

















+
-
+







#ifndef WORKSPACE_H
#define WORKSPACE_H

#include <QStandardItemModel>
#include <QFileInfo>
#include <QDir>
#include <QSet>
#include <QMap>
#include "Utils.h"
#include "Fossil.h"

//////////////////////////////////////////////////////////////////////////
// WorkspaceFile
//////////////////////////////////////////////////////////////////////////
struct WorkspaceFile
{
	enum Type
	{
		TYPE_UNKNOWN		= 1<<0,
		TYPE_UNCHANGED		= 1<<1,
		TYPE_EDITTED		= 1<<2,
		TYPE_ADDED			= 1<<3,
		TYPE_DELETED		= 1<<4,
		TYPE_MISSING		= 1<<5,
		TYPE_RENAMED		= 1<<6,
		TYPE_CONFLICTED		= 1<<7,
		TYPE_MERGED			= 1<<8,
		TYPE_MODIFIED		= TYPE_EDITTED|TYPE_ADDED|TYPE_DELETED|TYPE_MISSING|TYPE_RENAMED|TYPE_CONFLICTED,
		TYPE_MODIFIED		= TYPE_EDITTED|TYPE_ADDED|TYPE_DELETED|TYPE_MISSING|TYPE_RENAMED|TYPE_CONFLICTED|TYPE_MERGED,
		TYPE_REPO			= TYPE_UNCHANGED|TYPE_MODIFIED,
		TYPE_ALL			= TYPE_UNKNOWN|TYPE_REPO
	};

	WorkspaceFile(const QFileInfo &info, Type type, const QString &repoPath)
	{
		FileInfo = info;
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
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







+
+
+
+

















-
-
+
+



+
+
+






+
+
+


-
+
-



	QString		FilePath;
	QString		Path;
};


typedef QSet<QString> stringset_t;

//////////////////////////////////////////////////////////////////////////
// Workspace
//////////////////////////////////////////////////////////////////////////

class Workspace
{
public:
	~Workspace();

	typedef QList<WorkspaceFile*> filelist_t;
	typedef QMap<QString, WorkspaceFile*> filemap_t;

	void				clearState();

	Fossil &			fossil() { return bridge; }
	const Fossil &		fossil() const { return bridge; }

	static bool			scanDirectory(QFileInfoList &entries, const QString& dirPath, const QString &baseDir, const QString ignoreSpec, const bool& abort, UICallback &uiCallback);
	void				scanWorkspace(bool scanLocal, bool scanIgnored, bool scanModified, bool scanUnchanged, const QString &ignoreGlob, UICallback &uiCallback, bool &operationAborted);

	QStandardItemModel	&getFileModel() { return repoFileModel; }
	QStandardItemModel	&getDirModel() { return repoDirModel; }
	QStandardItemModel	&getStashModel() { return repoStashModel; }
	QStandardItemModel	&getTreeModel() { return repoTreeModel; }

	filemap_t			&getFiles() { return workspaceFiles; }
	stringset_t			&getPaths() { return pathSet; }
	stashmap_t			&getStashes() { return stashMap; }
	QStringMap			&getTags() { return tags; }
	QStringList			&getBranches() { return branchList; }
	bool				otherChanges() const { return isIntegrated; }

private:
	Fossil				bridge;
	filemap_t			workspaceFiles;
	stringset_t			pathSet;
	stashmap_t			stashMap;
	QStringList			branchList;
	QStringMap			tags;
	bool				isIntegrated;

	QStandardItemModel	repoFileModel;
	QStandardItemModel	repoDirModel;
	QStandardItemModel	repoTreeModel;
	QStandardItemModel	repoStashModel;
};

#endif // WORKSPACE_H
Changes to src/main.cpp.
1
2
3
4
5
6
7
8
9

10
11
12
13
14
15
16
1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
16








-
+







#include <QApplication>
#include "MainWindow.h"

int main(int argc, char *argv[])
{
	QApplication app(argc, argv);
	app.setApplicationName("Fuel");
	app.setApplicationVersion("2.0.0");
	app.setOrganizationDomain("fuelscm.org");
	app.setOrganizationDomain("fuel-scm.org");
	app.setOrganizationName("Fuel-SCM");


	#ifdef Q_OS_MACX
		// Native OSX applications don't have menu icons
		app.setAttribute(Qt::AA_DontShowIconsInMenus);
	#endif
Changes to ui/BrowserWidget.ui.
10
11
12
13
14
15
16
17










18
19
20
21
22
23
24
10
11
12
13
14
15
16

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33







-
+
+
+
+
+
+
+
+
+
+







    <height>300</height>
   </rect>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <property name="spacing">
    <number>0</number>
   </property>
   <property name="margin">
   <property name="leftMargin">
    <number>0</number>
   </property>
   <property name="topMargin">
    <number>0</number>
   </property>
   <property name="rightMargin">
    <number>0</number>
   </property>
   <property name="bottomMargin">
    <number>0</number>
   </property>
   <item>
    <widget class="QToolBar" name="toolBar">
     <property name="windowTitle">
      <string/>
     </property>
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
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







-
+











-
+











-
+











-
+







   <item>
    <widget class="CustomWebView" name="webView" native="true"/>
   </item>
  </layout>
  <action name="actionBrowserBack">
   <property name="icon">
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icons/Button Previous-01.png</normaloff>:/icons/icons/Button Previous-01.png</iconset>
     <normaloff>:/icons/icon-action-previous</normaloff>:/icons/icon-action-previous</iconset>
   </property>
   <property name="text">
    <string>Back</string>
   </property>
   <property name="toolTip">
    <string>Back</string>
   </property>
  </action>
  <action name="actionBrowserForward">
   <property name="icon">
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icons/Button Next-01.png</normaloff>:/icons/icons/Button Next-01.png</iconset>
     <normaloff>:/icons/icon-action-next</normaloff>:/icons/icon-action-next</iconset>
   </property>
   <property name="text">
    <string>Forward</string>
   </property>
   <property name="toolTip">
    <string>Forward</string>
   </property>
  </action>
  <action name="actionBrowserRefresh">
   <property name="icon">
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icons/Button Refresh-01.png</normaloff>:/icons/icons/Button Refresh-01.png</iconset>
     <normaloff>:/icons/icon-action-refresh</normaloff>:/icons/icon-action-refresh</iconset>
   </property>
   <property name="text">
    <string>Refresh</string>
   </property>
   <property name="toolTip">
    <string>Refresh</string>
   </property>
  </action>
  <action name="actionBrowserStop">
   <property name="icon">
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icons/Button Close-01.png</normaloff>:/icons/icons/Button Close-01.png</iconset>
     <normaloff>:/icons/icon-action-stop</normaloff>:/icons/icon-action-stop</iconset>
   </property>
   <property name="text">
    <string>Stop</string>
   </property>
  </action>
 </widget>
 <customwidgets>
Changes to ui/CommitDialog.ui.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
20












-
+







<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>CommitDialog</class>
 <widget class="QDialog" name="CommitDialog">
  <property name="windowModality">
   <enum>Qt::WindowModal</enum>
  </property>
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
    <height>394</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Commit</string>
  </property>
  <property name="modal">
   <bool>true</bool>
58
59
60
61
62
63
64






















65
66
67












































68
69
70
71
72
73
74
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







      <property name="selectionBehavior">
       <enum>QAbstractItemView::SelectRows</enum>
      </property>
     </widget>
    </widget>
   </item>
   <item>
    <widget class="QWidget" name="widgetBranchOptions" native="true">
     <layout class="QFormLayout" name="formLayout">
      <property name="leftMargin">
       <number>0</number>
      </property>
      <property name="topMargin">
       <number>0</number>
      </property>
      <property name="rightMargin">
       <number>0</number>
      </property>
      <property name="bottomMargin">
       <number>0</number>
      </property>
      <item row="0" column="0">
       <widget class="QLabel" name="label_2">
        <property name="text">
         <string>New branch</string>
        </property>
       </widget>
      </item>
      <item row="0" column="1">
    <widget class="QCheckBox" name="checkBox">
     <property name="text">
      <string/>
       <widget class="QCheckBox" name="chkNewBranch">
        <property name="text">
         <string/>
        </property>
       </widget>
      </item>
      <item row="1" column="1">
       <widget class="QCheckBox" name="chkPrivateBranch">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string/>
        </property>
       </widget>
      </item>
      <item row="2" column="1">
       <widget class="QLineEdit" name="lineBranchName">
        <property name="enabled">
         <bool>false</bool>
        </property>
       </widget>
      </item>
      <item row="2" column="0">
       <widget class="QLabel" name="label">
        <property name="text">
         <string>Branch name</string>
        </property>
       </widget>
      </item>
      <item row="1" column="0">
       <widget class="QLabel" name="label_3">
        <property name="text">
         <string>Private branch</string>
        </property>
       </widget>
      </item>
     </layout>
    </widget>
   </item>
   <item>
    <widget class="QCheckBox" name="chkRevertFiles">
     <property name="text">
      <string>Revert stashed files</string>
     </property>
    </widget>
   </item>
   <item>
    <widget class="QDialogButtonBox" name="buttonBox">
     <property name="orientation">
      <enum>Qt::Horizontal</enum>
Added ui/FslSettingsDialog.ui.












































































































































































































































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>FslSettingsDialog</class>
 <widget class="QDialog" name="FslSettingsDialog">
  <property name="windowModality">
   <enum>Qt::WindowModal</enum>
  </property>
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>457</width>
    <height>266</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Fossil Settings</string>
  </property>
  <property name="windowIcon">
   <iconset resource="../rsrc/resources.qrc">
    <normaloff>:/icons/icon-application</normaloff>:/icons/icon-application</iconset>
  </property>
  <property name="modal">
   <bool>true</bool>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <item>
    <widget class="QWidget" name="widget" native="true">
     <layout class="QFormLayout" name="formLayout">
      <property name="leftMargin">
       <number>0</number>
      </property>
      <property name="topMargin">
       <number>0</number>
      </property>
      <property name="rightMargin">
       <number>0</number>
      </property>
      <property name="bottomMargin">
       <number>0</number>
      </property>
      <item row="0" column="0">
       <widget class="QLabel" name="label_2">
        <property name="minimumSize">
         <size>
          <width>100</width>
          <height>0</height>
         </size>
        </property>
        <property name="text">
         <string>Graphical Diff </string>
        </property>
       </widget>
      </item>
      <item row="0" column="1">
       <layout class="QHBoxLayout" name="horizontalLayout_9">
        <item>
         <widget class="QLineEdit" name="lineGDiffCommand">
          <property name="toolTip">
           <string>Path to graphical diff tool</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QPushButton" name="btnSelectFossilGDiff">
          <property name="sizePolicy">
           <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <property name="maximumSize">
           <size>
            <width>24</width>
            <height>24</height>
           </size>
          </property>
          <property name="text">
           <string>...</string>
          </property>
         </widget>
        </item>
       </layout>
      </item>
      <item row="1" column="0">
       <widget class="QLabel" name="label_3">
        <property name="minimumSize">
         <size>
          <width>100</width>
          <height>0</height>
         </size>
        </property>
        <property name="text">
         <string>Graphical Merge</string>
        </property>
       </widget>
      </item>
      <item row="1" column="1">
       <layout class="QHBoxLayout" name="horizontalLayout_10">
        <item>
         <widget class="QLineEdit" name="lineGMergeCommand">
          <property name="toolTip">
           <string>Path to the graphical merge tool</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QPushButton" name="btnSelectGMerge">
          <property name="sizePolicy">
           <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <property name="maximumSize">
           <size>
            <width>24</width>
            <height>24</height>
           </size>
          </property>
          <property name="text">
           <string>...</string>
          </property>
         </widget>
        </item>
       </layout>
      </item>
      <item row="2" column="0">
       <widget class="QLabel" name="label_44">
        <property name="minimumSize">
         <size>
          <width>100</width>
          <height>0</height>
         </size>
        </property>
        <property name="text">
         <string>HTTP Proxy</string>
        </property>
       </widget>
      </item>
      <item row="2" column="1">
       <widget class="QLineEdit" name="lineProxy">
        <property name="minimumSize">
         <size>
          <width>0</width>
          <height>0</height>
         </size>
        </property>
        <property name="toolTip">
         <string>The URL of the HTTP proxy</string>
        </property>
       </widget>
      </item>
      <item row="3" column="0">
       <widget class="QLabel" name="uILanguageLabel_3">
        <property name="text">
         <string>HTTP Port</string>
        </property>
       </widget>
      </item>
      <item row="3" column="1">
       <widget class="QLineEdit" name="lineUIPort">
        <property name="toolTip">
         <string>HTTP port to use for the Fossil web interface</string>
        </property>
       </widget>
      </item>
      <item row="4" column="1">
       <widget class="QLineEdit" name="lineIgnoreCRNL">
        <property name="minimumSize">
         <size>
          <width>0</width>
          <height>0</height>
         </size>
        </property>
        <property name="toolTip">
         <string>A comma separated list of glob-style file patterns to exclude from Fossil's CR/NL consistency checking</string>
        </property>
       </widget>
      </item>
      <item row="4" column="0">
       <widget class="QLabel" name="label_7">
        <property name="minimumSize">
         <size>
          <width>100</width>
          <height>0</height>
         </size>
        </property>
        <property name="text">
         <string>Ignore CR/NL</string>
        </property>
       </widget>
      </item>
      <item row="5" column="1">
       <widget class="QLineEdit" name="lineIgnore">
        <property name="minimumSize">
         <size>
          <width>0</width>
          <height>0</height>
         </size>
        </property>
        <property name="toolTip">
         <string>A comma separated list of glob-style file/path patterns ignored in Fossil file operations</string>
        </property>
       </widget>
      </item>
      <item row="5" column="0">
       <widget class="QLabel" name="label_4">
        <property name="minimumSize">
         <size>
          <width>100</width>
          <height>0</height>
         </size>
        </property>
        <property name="text">
         <string>Ignore List</string>
        </property>
       </widget>
      </item>
      <item row="6" column="1">
       <widget class="QLineEdit" name="lineRemoteURL">
        <property name="minimumSize">
         <size>
          <width>0</width>
          <height>0</height>
         </size>
        </property>
        <property name="toolTip">
         <string>The remote url used to push/pull changes.
URL style user names and passwords are also supported.
For example http://username:password@server.com/fossil</string>
        </property>
       </widget>
      </item>
      <item row="6" column="0">
       <widget class="QLabel" name="label_5">
        <property name="minimumSize">
         <size>
          <width>100</width>
          <height>0</height>
         </size>
        </property>
        <property name="text">
         <string>Remote Url</string>
        </property>
       </widget>
      </item>
     </layout>
    </widget>
   </item>
   <item>
    <widget class="QDialogButtonBox" name="buttonBox">
     <property name="orientation">
      <enum>Qt::Horizontal</enum>
     </property>
     <property name="standardButtons">
      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <resources>
  <include location="../rsrc/resources.qrc"/>
 </resources>
 <connections>
  <connection>
   <sender>buttonBox</sender>
   <signal>accepted()</signal>
   <receiver>FslSettingsDialog</receiver>
   <slot>accept()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>248</x>
     <y>254</y>
    </hint>
    <hint type="destinationlabel">
     <x>157</x>
     <y>274</y>
    </hint>
   </hints>
  </connection>
  <connection>
   <sender>buttonBox</sender>
   <signal>rejected()</signal>
   <receiver>FslSettingsDialog</receiver>
   <slot>reject()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>316</x>
     <y>260</y>
    </hint>
    <hint type="destinationlabel">
     <x>286</x>
     <y>274</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>
Changes to ui/MainWindow.ui.
13
14
15
16
17
18
19
20
21


22
23
24
25
26
27
28
13
14
15
16
17
18
19


20
21
22
23
24
25
26
27
28







-
-
+
+







  <property name="acceptDrops">
   <bool>true</bool>
  </property>
  <property name="windowTitle">
   <string>Fuel</string>
  </property>
  <property name="windowIcon">
   <iconset>
    <normaloff>:/icons/icons/Battery-01.png</normaloff>:/icons/icons/Battery-01.png</iconset>
   <iconset resource="../rsrc/resources.qrc">
    <normaloff>:/icons/icon-application</normaloff>:/icons/icon-application</iconset>
  </property>
  <property name="unifiedTitleAndToolBarOnMac">
   <bool>true</bool>
  </property>
  <widget class="QWidget" name="centralWidget">
   <layout class="QVBoxLayout" name="verticalLayout">
    <property name="leftMargin">
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
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







-
+











-
+

-
-
-







        <property name="sizePolicy">
         <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
          <horstretch>20</horstretch>
          <verstretch>0</verstretch>
         </sizepolicy>
        </property>
        <property name="contextMenuPolicy">
         <enum>Qt::ActionsContextMenu</enum>
         <enum>Qt::CustomContextMenu</enum>
        </property>
        <property name="editTriggers">
         <set>QAbstractItemView::NoEditTriggers</set>
        </property>
        <property name="selectionMode">
         <enum>QAbstractItemView::ExtendedSelection</enum>
        </property>
        <property name="selectionBehavior">
         <enum>QAbstractItemView::SelectItems</enum>
        </property>
        <property name="sortingEnabled">
         <bool>true</bool>
         <bool>false</bool>
        </property>
        <attribute name="headerVisible">
         <bool>true</bool>
        </attribute>
        <attribute name="headerShowSortIndicator" stdset="0">
         <bool>false</bool>
        </attribute>
       </widget>
       <widget class="FileTableView" name="fileTableView">
        <property name="sizePolicy">
         <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
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
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







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-












-
+







        <attribute name="verticalHeaderVisible">
         <bool>false</bool>
        </attribute>
        <attribute name="verticalHeaderDefaultSectionSize">
         <number>30</number>
        </attribute>
       </widget>
       <widget class="QTableView" name="stashTableView">
        <property name="sizePolicy">
         <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
          <horstretch>20</horstretch>
          <verstretch>0</verstretch>
         </sizepolicy>
        </property>
        <property name="contextMenuPolicy">
         <enum>Qt::ActionsContextMenu</enum>
        </property>
        <property name="editTriggers">
         <set>QAbstractItemView::NoEditTriggers</set>
        </property>
        <property name="alternatingRowColors">
         <bool>true</bool>
        </property>
        <property name="selectionBehavior">
         <enum>QAbstractItemView::SelectRows</enum>
        </property>
        <property name="showGrid">
         <bool>false</bool>
        </property>
        <property name="sortingEnabled">
         <bool>true</bool>
        </property>
        <property name="wordWrap">
         <bool>false</bool>
        </property>
        <attribute name="horizontalHeaderHighlightSections">
         <bool>false</bool>
        </attribute>
        <attribute name="horizontalHeaderStretchLastSection">
         <bool>true</bool>
        </attribute>
        <attribute name="verticalHeaderVisible">
         <bool>false</bool>
        </attribute>
       </widget>
      </widget>
      <widget class="QTabWidget" name="tabWidget">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
         <horstretch>0</horstretch>
         <verstretch>8</verstretch>
        </sizepolicy>
       </property>
       <property name="tabPosition">
        <enum>QTabWidget::South</enum>
       </property>
       <property name="currentIndex">
        <number>1</number>
        <number>0</number>
       </property>
       <widget class="QWidget" name="tabLog">
        <attribute name="title">
         <string>Log</string>
        </attribute>
        <layout class="QVBoxLayout" name="verticalLayout_2">
         <property name="leftMargin">
259
260
261
262
263
264
265
266

267
268
269
270
271
272
273
218
219
220
221
222
223
224

225
226
227
228
229
230
231
232







-
+







  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>865</width>
     <height>22</height>
     <height>23</height>
    </rect>
   </property>
   <widget class="QMenu" name="menuFile">
    <property name="title">
     <string>&amp;File</string>
    </property>
    <addaction name="actionNewRepository"/>
291
292
293
294
295
296
297

298
299








300
301













302
303
304

305
306
307
308
309
310
311
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







+

-
+
+
+
+
+
+
+
+

-
+
+
+
+
+
+
+
+
+
+
+
+
+



+







    <property name="title">
     <string>&amp;View</string>
    </property>
    <addaction name="actionViewModified"/>
    <addaction name="actionViewUnchanged"/>
    <addaction name="actionViewUnknown"/>
    <addaction name="actionViewIgnored"/>
    <addaction name="actionViewAll"/>
    <addaction name="separator"/>
    <addaction name="actionViewStash"/>
    <addaction name="actionViewAsList"/>
    <addaction name="actionViewAsFolders"/>
   </widget>
   <widget class="QMenu" name="menuWorkspace">
    <property name="title">
     <string>&amp;Workspace</string>
    </property>
    <addaction name="actionRefresh"/>
    <addaction name="separator"/>
    <addaction name="actionViewAsList"/>
    <addaction name="actionCommit"/>
    <addaction name="actionUpdate"/>
    <addaction name="separator"/>
    <addaction name="actionPush"/>
    <addaction name="actionPull"/>
    <addaction name="separator"/>
    <addaction name="actionUndo"/>
    <addaction name="separator"/>
    <addaction name="actionCreateBranch"/>
    <addaction name="actionCreateTag"/>
    <addaction name="actionCreateStash"/>
    <addaction name="separator"/>
    <addaction name="actionFossilSettings"/>
   </widget>
   <addaction name="menuFile"/>
   <addaction name="menuView"/>
   <addaction name="menuWorkspace"/>
   <addaction name="menuHelp"/>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <property name="windowTitle">
    <string>Main Toolbar</string>
   </property>
   <property name="movable">
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
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







-
-











-
-
+
+


-
+













-
-
+
+


-
+













-
-
+
+
















-
-
+
+
















-
-
+
+
















-
-
+
+
















-
-
+
+







   <addaction name="separator"/>
   <addaction name="actionUndo"/>
   <addaction name="separator"/>
   <addaction name="actionAdd"/>
   <addaction name="actionRevert"/>
   <addaction name="actionDelete"/>
   <addaction name="separator"/>
   <addaction name="actionNewStash"/>
   <addaction name="separator"/>
   <addaction name="actionDiff"/>
   <addaction name="actionHistory"/>
   <addaction name="separator"/>
   <addaction name="actionFossilUI"/>
   <addaction name="actionTimeline"/>
   <addaction name="separator"/>
   <addaction name="actionOpenContaining"/>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
  <action name="actionRefresh">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Button Refresh-01.png</normaloff>:/icons/icons/Button Refresh-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-refresh</normaloff>:/icons/icon-action-refresh</iconset>
   </property>
   <property name="text">
    <string>Refresh</string>
    <string>&amp;Refresh</string>
   </property>
   <property name="toolTip">
    <string>Refresh the views</string>
   </property>
   <property name="statusTip">
    <string>Refresh the views</string>
   </property>
   <property name="shortcut">
    <string>F5</string>
   </property>
  </action>
  <action name="actionCommit">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Save-01.png</normaloff>:/icons/icons/Save-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-commit</normaloff>:/icons/icon-action-commit</iconset>
   </property>
   <property name="text">
    <string>Commit</string>
    <string>&amp;Commit</string>
   </property>
   <property name="toolTip">
    <string>Commit modifications</string>
   </property>
   <property name="statusTip">
    <string>Commit modifications</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+M</string>
   </property>
  </action>
  <action name="actionDiff">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Document Copy-01.png</normaloff>:/icons/icons/Document Copy-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-item-diff</normaloff>:/icons/icon-item-diff</iconset>
   </property>
   <property name="text">
    <string>Diff</string>
   </property>
   <property name="toolTip">
    <string>Display the differences between the current and last committed version</string>
   </property>
   <property name="statusTip">
    <string>Display the differences between the current and last committed version</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+D</string>
   </property>
  </action>
  <action name="actionAdd">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/File New-01.png</normaloff>:/icons/icons/File New-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-item-add</normaloff>:/icons/icon-item-add</iconset>
   </property>
   <property name="text">
    <string>Add</string>
   </property>
   <property name="toolTip">
    <string>Add files to the repository</string>
   </property>
   <property name="statusTip">
    <string>Add files to the repository</string>
   </property>
   <property name="shortcut">
    <string>Ctrl++</string>
   </property>
  </action>
  <action name="actionDelete">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/File Delete-01.png</normaloff>:/icons/icons/File Delete-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-item-delete</normaloff>:/icons/icon-item-delete</iconset>
   </property>
   <property name="text">
    <string>Delete</string>
   </property>
   <property name="toolTip">
    <string>Delete files from the repository</string>
   </property>
   <property name="statusTip">
    <string>Delete files from the repository</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+-</string>
   </property>
  </action>
  <action name="actionNewRepository">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Document Blank-01.png</normaloff>:/icons/icons/Document Blank-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-repo-new</normaloff>:/icons/icon-action-repo-new</iconset>
   </property>
   <property name="text">
    <string>&amp;New...</string>
   </property>
   <property name="toolTip">
    <string>Make a new Fossil repository</string>
   </property>
   <property name="statusTip">
    <string>Make a new Fossil repository</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+N</string>
   </property>
  </action>
  <action name="actionOpenRepository">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/My Documents-01.png</normaloff>:/icons/icons/My Documents-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-repo-open</normaloff>:/icons/icon-action-repo-open</iconset>
   </property>
   <property name="text">
    <string>&amp;Open...</string>
   </property>
   <property name="toolTip">
    <string>Open a Fossil repository or workspace folder</string>
   </property>
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
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







-
-
+
+


-
+







-
-
+
+


-
+













-
-
+
+


-
+













-
-
+
+
















-
-
+
+



















-
-
+
+



















-
-
+
+













-
-
+
+













-
-
+
+













-
-
+
+













-
-
+
+
















-
-
+
+
















-
-
+
+


-
+













-
-
+
+













-
-
+
+


-
+


-
+










-
-
+
+







   </property>
   <property name="statusTip">
    <string>Close the current workspace</string>
   </property>
  </action>
  <action name="actionCloneRepository">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/My Websites-01.png</normaloff>:/icons/icons/My Websites-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-repo-clone</normaloff>:/icons/icon-action-repo-clone</iconset>
   </property>
   <property name="text">
    <string>Clone...</string>
    <string>C&amp;lone...</string>
   </property>
   <property name="statusTip">
    <string>Clone a remote repository</string>
   </property>
  </action>
  <action name="actionPush">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Button Upload-01.png</normaloff>:/icons/icons/Button Upload-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-push</normaloff>:/icons/icon-action-push</iconset>
   </property>
   <property name="text">
    <string>Push</string>
    <string>&amp;Push</string>
   </property>
   <property name="toolTip">
    <string>Push changes to the remote repository</string>
   </property>
   <property name="statusTip">
    <string>Push changes to the remote repository</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+P</string>
   </property>
  </action>
  <action name="actionPull">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Button Download-01.png</normaloff>:/icons/icons/Button Download-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-pull</normaloff>:/icons/icon-action-pull</iconset>
   </property>
   <property name="text">
    <string>Pull</string>
    <string>Pu&amp;ll</string>
   </property>
   <property name="toolTip">
    <string>Pull changes from the remote repository</string>
   </property>
   <property name="statusTip">
    <string>Pull changes from the remote repository</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+L</string>
   </property>
  </action>
  <action name="actionRename">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/File Open-01.png</normaloff>:/icons/icons/File Open-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-item-rename</normaloff>:/icons/icon-item-rename</iconset>
   </property>
   <property name="text">
    <string>Rename</string>
   </property>
   <property name="toolTip">
    <string>Rename the selected file</string>
   </property>
   <property name="statusTip">
    <string>Rename the selected file</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+R</string>
   </property>
  </action>
  <action name="actionQuit">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Button Turn Off-01.png</normaloff>:/icons/icons/Button Turn Off-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-quit</normaloff>:/icons/icon-action-quit</iconset>
   </property>
   <property name="text">
    <string>&amp;Quit</string>
   </property>
   <property name="statusTip">
    <string>Quit</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+Q</string>
   </property>
   <property name="menuRole">
    <enum>QAction::QuitRole</enum>
   </property>
   <property name="iconVisibleInMenu">
    <bool>true</bool>
   </property>
  </action>
  <action name="actionHistory">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/File History-01.png</normaloff>:/icons/icons/File History-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-item-history</normaloff>:/icons/icon-item-history</iconset>
   </property>
   <property name="text">
    <string>History</string>
   </property>
   <property name="toolTip">
    <string>Display the version history of a file via the Fossil UI</string>
   </property>
   <property name="statusTip">
    <string>Display the version history of a file via the Fossil UI</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+H</string>
   </property>
  </action>
  <action name="actionFossilUI">
   <property name="checkable">
    <bool>true</bool>
   </property>
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Network MAC-01.png</normaloff>:/icons/icons/Network MAC-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-webview</normaloff>:/icons/icon-webview</iconset>
   </property>
   <property name="text">
    <string>Fossil UI</string>
   </property>
   <property name="toolTip">
    <string>Starts the Fossil UI in the Web Browser</string>
   </property>
   <property name="statusTip">
    <string>Starts the Fossil UI in the Web Browser</string>
   </property>
  </action>
  <action name="actionRevert">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Document-Revert-icon.png</normaloff>:/icons/icons/Document-Revert-icon.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-item-revert</normaloff>:/icons/icon-item-revert</iconset>
   </property>
   <property name="text">
    <string>Revert</string>
   </property>
   <property name="toolTip">
    <string>Revert files to the last commited version</string>
   </property>
   <property name="statusTip">
    <string>Revert files to the last commited version</string>
   </property>
  </action>
  <action name="actionClearLog">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Text Edit.png</normaloff>:/icons/icons/Text Edit.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-clear-log</normaloff>:/icons/icon-clear-log</iconset>
   </property>
   <property name="text">
    <string>Clear Log</string>
   </property>
   <property name="toolTip">
    <string>Clears the log</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+K</string>
   </property>
  </action>
  <action name="actionTimeline">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Clock-01.png</normaloff>:/icons/icons/Clock-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-timeline</normaloff>:/icons/icon-action-timeline</iconset>
   </property>
   <property name="text">
    <string>Timeline</string>
   </property>
   <property name="toolTip">
    <string>Display the change history of the Fossil repository</string>
   </property>
   <property name="statusTip">
    <string>Display the change history of the Fossil repository</string>
   </property>
  </action>
  <action name="actionOpenFile">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Document-01.png</normaloff>:/icons/icons/Document-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-item-file</normaloff>:/icons/icon-item-file</iconset>
   </property>
   <property name="text">
    <string>Open File</string>
   </property>
   <property name="toolTip">
    <string>Open the selected file</string>
   </property>
   <property name="statusTip">
    <string>Open the selected file</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+Return</string>
   </property>
  </action>
  <action name="actionOpenContaining">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Folder-01.png</normaloff>:/icons/icons/Folder-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-folder-explore</normaloff>:/icons/icon-action-folder-explore</iconset>
   </property>
   <property name="text">
    <string>Open Containing</string>
   </property>
   <property name="toolTip">
    <string>Open the folder containing the selected file</string>
   </property>
   <property name="statusTip">
    <string>Open the folder containing the selected file</string>
   </property>
   <property name="shortcut">
    <string>Alt+Return</string>
   </property>
  </action>
  <action name="actionUndo">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Button Reload-01.png</normaloff>:/icons/icons/Button Reload-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-undo</normaloff>:/icons/icon-action-undo</iconset>
   </property>
   <property name="text">
    <string>Undo</string>
    <string>U&amp;ndo</string>
   </property>
   <property name="toolTip">
    <string>Undo the last Fossil action</string>
   </property>
   <property name="statusTip">
    <string>Undo the last Fossil action</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+Z</string>
   </property>
  </action>
  <action name="actionAbout">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Battery-01.png</normaloff>:/icons/icons/Battery-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-application</normaloff>:/icons/icon-application</iconset>
   </property>
   <property name="text">
    <string>&amp;About...</string>
   </property>
   <property name="statusTip">
    <string>About Fuel</string>
   </property>
   <property name="menuRole">
    <enum>QAction::AboutRole</enum>
   </property>
  </action>
  <action name="actionUpdate">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Button Play-01.png</normaloff>:/icons/icons/Button Play-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-update</normaloff>:/icons/icon-action-update</iconset>
   </property>
   <property name="text">
    <string>Update</string>
    <string>&amp;Update</string>
   </property>
   <property name="toolTip">
    <string>Update the workspace to the latest version</string>
    <string>Update the workspace to a revision</string>
   </property>
   <property name="statusTip">
    <string>Update the workspace to the latest version</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+U</string>
   </property>
  </action>
  <action name="actionSettings">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Gear-01.png</normaloff>:/icons/icons/Gear-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-settings</normaloff>:/icons/icon-action-settings</iconset>
   </property>
   <property name="text">
    <string>&amp;Preferences...</string>
   </property>
   <property name="toolTip">
    <string>Fuel Preferences</string>
   </property>
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
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







-
-
+
+













-
-
+
+











-
+

-
-
+
+


-
+







-
-
+
+











-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-


-
-
+
+







-
-
+
+




+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
















-
+
+
+


   </property>
   <property name="statusTip">
    <string>View the workspace as a list of files</string>
   </property>
  </action>
  <action name="actionOpenFolder">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Folder-01.png</normaloff>:/icons/icons/Folder-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-item-folder</normaloff>:/icons/icon-item-folder</iconset>
   </property>
   <property name="text">
    <string>Open Folder</string>
   </property>
   <property name="toolTip">
    <string>Open the selected folder</string>
   </property>
   <property name="statusTip">
    <string>Open the selected folder</string>
   </property>
  </action>
  <action name="actionRenameFolder">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Folder Open-01.png</normaloff>:/icons/icons/Folder Open-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-folder-rename</normaloff>:/icons/icon-action-folder-rename</iconset>
   </property>
   <property name="text">
    <string>Rename Folder</string>
   </property>
   <property name="toolTip">
    <string>Rename the selected folder</string>
   </property>
   <property name="statusTip">
    <string>Rename the selected folder</string>
   </property>
  </action>
  <action name="actionNewStash">
  <action name="actionCreateStash">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Folder Add-01.png</normaloff>:/icons/icons/Folder Add-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-stash-new</normaloff>:/icons/icon-action-stash-new</iconset>
   </property>
   <property name="text">
    <string>Stash changes</string>
    <string>&amp;Stash Changes</string>
   </property>
   <property name="statusTip">
    <string>Stash changes</string>
   </property>
  </action>
  <action name="actionApplyStash">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Folder Open-01.png</normaloff>:/icons/icons/Folder Open-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-stash-apply</normaloff>:/icons/icon-action-stash-apply</iconset>
   </property>
   <property name="text">
    <string>Apply Stash</string>
   </property>
   <property name="iconText">
    <string>Apply stashed changes</string>
   </property>
   <property name="toolTip">
    <string>Apply stashed changes</string>
   </property>
  </action>
  <action name="actionViewStash">
   <property name="checkable">
    <bool>true</bool>
   </property>
   <property name="text">
    <string>&amp;Stashed Changes</string>
   </property>
   <property name="iconText">
    <string>View Stashed Changes</string>
   </property>
   <property name="toolTip">
    <string>View Stashed Changes</string>
   </property>
   <property name="statusTip">
    <string>Show the list of stashed changes</string>
   </property>
  </action>
  <action name="actionDeleteStash">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Folder Delete-01.png</normaloff>:/icons/icons/Folder Delete-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-stash-delete</normaloff>:/icons/icon-action-stash-delete</iconset>
   </property>
   <property name="text">
    <string>Delete Stash</string>
   </property>
  </action>
  <action name="actionDiffStash">
   <property name="icon">
    <iconset>
     <normaloff>:/icons/icons/Folder Explorer-01.png</normaloff>:/icons/icons/Folder Explorer-01.png</iconset>
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-stash-diff</normaloff>:/icons/icon-action-stash-diff</iconset>
   </property>
   <property name="text">
    <string>Diff Stash</string>
   </property>
  </action>
  <action name="actionCreateTag">
   <property name="icon">
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-tag-new</normaloff>:/icons/icon-action-tag-new</iconset>
   </property>
   <property name="text">
    <string>Create &amp;Tag</string>
   </property>
   <property name="toolTip">
    <string>Create a tag for a revision</string>
   </property>
   <property name="statusTip">
    <string>Create a tag for a revision</string>
   </property>
  </action>
  <action name="actionDeleteTag">
   <property name="icon">
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-tag-delete</normaloff>:/icons/icon-action-tag-delete</iconset>
   </property>
   <property name="text">
    <string>Delete Tag</string>
   </property>
   <property name="toolTip">
    <string>Delete Tag</string>
   </property>
  </action>
  <action name="actionCreateBranch">
   <property name="icon">
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-item-branch</normaloff>:/icons/icon-item-branch</iconset>
   </property>
   <property name="text">
    <string>Create &amp;Branch</string>
   </property>
   <property name="toolTip">
    <string>Create a branch from a revision</string>
   </property>
   <property name="statusTip">
    <string>Create a branch from a revision</string>
   </property>
  </action>
  <action name="actionMergeBranch">
   <property name="icon">
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-merge</normaloff>:/icons/icon-action-merge</iconset>
   </property>
   <property name="text">
    <string>Merge Branch</string>
   </property>
   <property name="toolTip">
    <string>Merge with a branch</string>
   </property>
   <property name="statusTip">
    <string>Merge with a branch</string>
   </property>
  </action>
  <action name="actionViewAsFolders">
   <property name="checkable">
    <bool>true</bool>
   </property>
   <property name="text">
    <string>Files and F&amp;olders</string>
   </property>
   <property name="toolTip">
    <string>View files and folders</string>
   </property>
   <property name="statusTip">
    <string>View the workspace as files and folders</string>
   </property>
  </action>
  <action name="actionViewAll">
   <property name="text">
    <string>&amp;All</string>
   </property>
   <property name="statusTip">
    <string>Show all files</string>
   </property>
  </action>
  <action name="actionFossilSettings">
   <property name="icon">
    <iconset resource="../rsrc/resources.qrc">
     <normaloff>:/icons/icon-action-settings</normaloff>:/icons/icon-action-settings</iconset>
   </property>
   <property name="text">
    <string>F&amp;ossil Settings</string>
   </property>
  </action>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <customwidgets>
  <customwidget>
   <class>FileTableView</class>
   <extends>QTableView</extends>
   <header>FileTableView.h</header>
  </customwidget>
  <customwidget>
   <class>BrowserWidget</class>
   <extends>QWidget</extends>
   <header>BrowserWidget.h</header>
   <container>1</container>
  </customwidget>
 </customwidgets>
 <resources/>
 <resources>
  <include location="../rsrc/resources.qrc"/>
 </resources>
 <connections/>
</ui>
Added ui/RevisionDialog.ui.

































































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>RevisionDialog</class>
 <widget class="QDialog" name="RevisionDialog">
  <property name="windowModality">
   <enum>Qt::WindowModal</enum>
  </property>
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>478</width>
    <height>177</height>
   </rect>
  </property>
  <property name="minimumSize">
   <size>
    <width>400</width>
    <height>0</height>
   </size>
  </property>
  <property name="modal">
   <bool>true</bool>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <item>
    <layout class="QFormLayout" name="formLayout">
     <item row="0" column="0">
      <widget class="QLabel" name="lblRevision">
       <property name="text">
        <string>Revision</string>
       </property>
      </widget>
     </item>
     <item row="0" column="1">
      <widget class="QComboBox" name="cmbRevision">
       <property name="editable">
        <bool>true</bool>
       </property>
      </widget>
     </item>
     <item row="1" column="0">
      <widget class="QLabel" name="lblName">
       <property name="text">
        <string>Name</string>
       </property>
      </widget>
     </item>
     <item row="1" column="1">
      <widget class="QLineEdit" name="lineName"/>
     </item>
     <item row="2" column="0">
      <widget class="QLabel" name="lblIntegrate">
       <property name="text">
        <string>Integrate</string>
       </property>
      </widget>
     </item>
     <item row="3" column="0">
      <widget class="QLabel" name="lblForce">
       <property name="text">
        <string>Force</string>
       </property>
      </widget>
     </item>
     <item row="2" column="1">
      <widget class="QCheckBox" name="chkIntegrate">
       <property name="text">
        <string/>
       </property>
      </widget>
     </item>
     <item row="3" column="1">
      <widget class="QCheckBox" name="chkForce">
       <property name="text">
        <string/>
       </property>
      </widget>
     </item>
    </layout>
   </item>
   <item>
    <widget class="QDialogButtonBox" name="buttonBox">
     <property name="orientation">
      <enum>Qt::Horizontal</enum>
     </property>
     <property name="standardButtons">
      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections>
  <connection>
   <sender>buttonBox</sender>
   <signal>accepted()</signal>
   <receiver>RevisionDialog</receiver>
   <slot>accept()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>248</x>
     <y>254</y>
    </hint>
    <hint type="destinationlabel">
     <x>157</x>
     <y>274</y>
    </hint>
   </hints>
  </connection>
  <connection>
   <sender>buttonBox</sender>
   <signal>rejected()</signal>
   <receiver>RevisionDialog</receiver>
   <slot>reject()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>316</x>
     <y>260</y>
    </hint>
    <hint type="destinationlabel">
     <x>286</x>
     <y>274</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>
Changes to ui/SettingsDialog.ui.
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
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












-
+





+
+
+
+





-
-
-
-
+
+
+
+
+
-
-
-
+
+
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>SettingsDialog</class>
 <widget class="QDialog" name="SettingsDialog">
  <property name="windowModality">
   <enum>Qt::WindowModal</enum>
  </property>
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>457</width>
    <height>352</height>
    <height>204</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Settings</string>
  </property>
  <property name="windowIcon">
   <iconset resource="../rsrc/resources.qrc">
    <normaloff>:/icons/icon-application</normaloff>:/icons/icon-application</iconset>
  </property>
  <property name="modal">
   <bool>true</bool>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <item>
    <widget class="QTabWidget" name="tabWidget">
     <property name="currentIndex">
      <number>0</number>
     </property>
    <widget class="QWidget" name="widget" native="true">
     <layout class="QFormLayout" name="formLayout">
      <property name="leftMargin">
       <number>0</number>
      </property>
     <widget class="QWidget" name="tabApp">
      <attribute name="icon">
       <iconset resource="../rsrc/resources.qrc">
      <property name="topMargin">
       <number>0</number>
        <normaloff>:/icons/icons/Battery-01.png</normaloff>:/icons/icons/Battery-01.png</iconset>
      </attribute>
      <attribute name="title">
      </property>
      <property name="rightMargin">
       <string>Application</string>
      </attribute>
      <layout class="QFormLayout" name="formLayout">
       <item row="0" column="0">
        <widget class="QLabel" name="label">
         <property name="minimumSize">
          <size>
           <width>100</width>
           <height>0</height>
          </size>
         </property>
         <property name="text">
          <string>Fossil Path</string>
         </property>
        </widget>
       </item>
       <item row="0" column="1">
        <layout class="QHBoxLayout" name="horizontalLayout_8">
         <item>
          <widget class="QLineEdit" name="lineFossilPath">
           <property name="toolTip">
            <string>Path to the Fossil executable. Leave blank to use the default Fossil</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="btnSelectFossil">
           <property name="sizePolicy">
            <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
             <horstretch>0</horstretch>
             <verstretch>0</verstretch>
            </sizepolicy>
           </property>
           <property name="maximumSize">
            <size>
             <width>24</width>
             <height>24</height>
            </size>
           </property>
           <property name="text">
            <string>...</string>
           </property>
          </widget>
         </item>
        </layout>
       </item>
       <item row="1" column="0">
       <number>0</number>
      </property>
      <property name="bottomMargin">
       <number>0</number>
      </property>
      <item row="0" column="0">
       <widget class="QLabel" name="label">
        <property name="minimumSize">
         <size>
          <width>100</width>
          <height>0</height>
         </size>
        </property>
        <property name="text">
         <string>Fossil Path</string>
        </property>
       </widget>
      </item>
      <item row="0" column="1">
       <layout class="QHBoxLayout" name="horizontalLayout_8">
        <item>
         <widget class="QLineEdit" name="lineFossilPath">
          <property name="toolTip">
           <string>Path to the Fossil executable. Leave blank to use the default Fossil</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QPushButton" name="btnSelectFossil">
          <property name="sizePolicy">
           <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <property name="maximumSize">
           <size>
            <width>24</width>
            <height>24</height>
           </size>
          </property>
          <property name="text">
           <string>...</string>
          </property>
         </widget>
        </item>
       </layout>
      </item>
      <item row="1" column="0">
        <widget class="QLabel" name="label_2">
         <property name="minimumSize">
          <size>
           <width>100</width>
           <height>0</height>
          </size>
         </property>
         <property name="text">
          <string>Graphical Diff </string>
         </property>
        </widget>
       </item>
       <item row="1" column="1">
        <layout class="QHBoxLayout" name="horizontalLayout_9">
         <item>
          <widget class="QLineEdit" name="lineGDiffCommand">
           <property name="toolTip">
            <string>Path to graphical diff tool</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="btnSelectFossilGDiff">
           <property name="sizePolicy">
            <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
             <horstretch>0</horstretch>
             <verstretch>0</verstretch>
            </sizepolicy>
           </property>
           <property name="maximumSize">
            <size>
             <width>24</width>
             <height>24</height>
            </size>
           </property>
           <property name="text">
            <string>...</string>
           </property>
          </widget>
         </item>
        </layout>
       </item>
       <item row="2" column="0">
        <widget class="QLabel" name="label_3">
         <property name="minimumSize">
          <size>
           <width>100</width>
           <height>0</height>
          </size>
         </property>
         <property name="text">
          <string>Graphical Merge</string>
         </property>
        </widget>
       </item>
       <item row="2" column="1">
        <layout class="QHBoxLayout" name="horizontalLayout_10">
         <item>
          <widget class="QLineEdit" name="lineGMergeCommand">
           <property name="toolTip">
            <string>Path to the graphical merge tool</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="btnSelectGMerge">
           <property name="sizePolicy">
            <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
             <horstretch>0</horstretch>
             <verstretch>0</verstretch>
            </sizepolicy>
           </property>
           <property name="maximumSize">
            <size>
             <width>24</width>
             <height>24</height>
            </size>
           </property>
           <property name="text">
            <string>...</string>
           </property>
          </widget>
         </item>
        </layout>
       </item>
       <item row="3" column="0">
        <widget class="QLabel" name="label_44">
         <property name="minimumSize">
          <size>
           <width>100</width>
           <height>0</height>
          </size>
         </property>
         <property name="text">
          <string>HTTP Proxy</string>
         </property>
        </widget>
       </item>
       <item row="3" column="1">
        <widget class="QLineEdit" name="lineProxy">
         <property name="minimumSize">
          <size>
           <width>0</width>
           <height>0</height>
          </size>
         </property>
         <property name="toolTip">
          <string>The URL of the HTTP proxy</string>
         </property>
        </widget>
       </item>
       <item row="4" column="0">
        <widget class="QLabel" name="uILanguageLabel_3">
         <property name="text">
          <string>HTTP Port</string>
         </property>
        </widget>
       </item>
       <item row="4" column="1">
        <widget class="QLineEdit" name="lineUIPort">
         <property name="toolTip">
          <string>HTTP port to use for the Fossil web interface</string>
         </property>
        </widget>
       </item>
       <item row="5" column="0">
        <widget class="QLabel" name="label_6">
         <property name="minimumSize">
          <size>
           <width>100</width>
           <height>0</height>
          </size>
         </property>
         <property name="text">
          <string>Commit Messages</string>
         </property>
        </widget>
       </item>
       <item row="5" column="1">
        <widget class="QPushButton" name="btnClearMessageHistory">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="toolTip">
          <string>Clear the commit message history</string>
         </property>
         <property name="text">
          <string>Clear</string>
         </property>
        </widget>
       </item>
       <item row="6" column="0">
        <widget class="QLabel" name="uILanguageLabel_2">
         <property name="text">
          <string>Web Browser</string>
         </property>
        </widget>
       </item>
       <item row="6" column="1">
        <widget class="QComboBox" name="cmbFossilBrowser">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="toolTip">
          <string>Web browser to use for the Fossil web interface</string>
         </property>
        </widget>
       </item>
       <item row="7" column="0">
        <widget class="QLabel" name="label_8">
         <property name="minimumSize">
          <size>
           <width>100</width>
           <height>0</height>
          </size>
         </property>
         <property name="text">
          <string>Double-click Action</string>
         </property>
        </widget>
       </item>
       <item row="7" column="1">
        <widget class="QComboBox" name="cmbDoubleClickAction">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="toolTip">
          <string>Action to perfom when double-clicking a file</string>
         </property>
         <property name="currentIndex">
          <number>-1</number>
         </property>
        </widget>
       </item>
       <item row="8" column="0">
        <widget class="QLabel" name="uILanguageLabel">
         <property name="text">
          <string>Language</string>
         </property>
        </widget>
       </item>
       <item row="8" column="1">
        <widget class="QComboBox" name="cmbActiveLanguage">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="toolTip">
          <string>Language for the user interface</string>
         </property>
        </widget>
       </item>
      </layout>
       <widget class="QLabel" name="label_6">
        <property name="minimumSize">
         <size>
          <width>100</width>
          <height>0</height>
         </size>
        </property>
        <property name="text">
         <string>Commit Messages</string>
        </property>
       </widget>
      </item>
      <item row="1" column="1">
       <widget class="QPushButton" name="btnClearMessageHistory">
        <property name="sizePolicy">
         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
          <horstretch>0</horstretch>
          <verstretch>0</verstretch>
         </sizepolicy>
        </property>
        <property name="toolTip">
         <string>Clear the commit message history</string>
        </property>
        <property name="text">
         <string>Clear</string>
        </property>
       </widget>
      </item>
      <item row="2" column="0">
       <widget class="QLabel" name="uILanguageLabel_2">
        <property name="text">
         <string>Web Browser</string>
        </property>
       </widget>
      </item>
      <item row="2" column="1">
       <widget class="QComboBox" name="cmbFossilBrowser">
        <property name="sizePolicy">
         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
          <horstretch>0</horstretch>
          <verstretch>0</verstretch>
         </sizepolicy>
        </property>
        <property name="toolTip">
         <string>Web browser to use for the Fossil web interface</string>
        </property>
       </widget>
      </item>
      <item row="3" column="0">
       <widget class="QLabel" name="label_8">
        <property name="minimumSize">
         <size>
          <width>100</width>
          <height>0</height>
         </size>
        </property>
        <property name="text">
         <string>Double-click Action</string>
        </property>
       </widget>
      </item>
      <item row="3" column="1">
       <widget class="QComboBox" name="cmbDoubleClickAction">
        <property name="sizePolicy">
         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
          <horstretch>0</horstretch>
          <verstretch>0</verstretch>
         </sizepolicy>
        </property>
        <property name="toolTip">
         <string>Action to perfom when double-clicking a file</string>
        </property>
        <property name="currentIndex">
         <number>-1</number>
        </property>
       </widget>
      </item>
      <item row="4" column="0">
       <widget class="QLabel" name="uILanguageLabel">
        <property name="text">
         <string>Language</string>
        </property>
       </widget>
      </item>
      <item row="4" column="1">
       <widget class="QComboBox" name="cmbActiveLanguage">
        <property name="sizePolicy">
         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
          <horstretch>0</horstretch>
          <verstretch>0</verstretch>
         </sizepolicy>
        </property>
        <property name="toolTip">
         <string>Language for the user interface</string>
        </property>
       </widget>
      </item>
     </layout>
     </widget>
     <widget class="QWidget" name="tabRepo">
      <attribute name="icon">
       <iconset resource="../rsrc/resources.qrc">
        <normaloff>:/icons/icons/Book-01.png</normaloff>:/icons/icons/Book-01.png</iconset>
      </attribute>
      <attribute name="title">
       <string>Repository</string>
      </attribute>
      <layout class="QFormLayout" name="formLayout_2">
       <property name="fieldGrowthPolicy">
        <enum>QFormLayout::ExpandingFieldsGrow</enum>
       </property>
       <property name="labelAlignment">
        <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
       </property>
       <item row="0" column="0">
        <widget class="QLabel" name="label_5">
         <property name="minimumSize">
          <size>
           <width>100</width>
           <height>0</height>
          </size>
         </property>
         <property name="text">
          <string>Remote Url</string>
         </property>
        </widget>
       </item>
       <item row="0" column="1">
        <widget class="QLineEdit" name="lineRemoteURL">
         <property name="minimumSize">
          <size>
           <width>0</width>
           <height>0</height>
          </size>
         </property>
         <property name="toolTip">
          <string>The remote url used to push/pull changes.
URL style user names and passwords are also supported.
For example http://username:password@server.com/fossil</string>
         </property>
        </widget>
       </item>
       <item row="1" column="0">
        <widget class="QLabel" name="label_4">
         <property name="minimumSize">
          <size>
           <width>100</width>
           <height>0</height>
          </size>
         </property>
         <property name="text">
          <string>Ignore List</string>
         </property>
        </widget>
       </item>
       <item row="1" column="1">
        <widget class="QLineEdit" name="lineIgnore">
         <property name="minimumSize">
          <size>
           <width>0</width>
           <height>0</height>
          </size>
         </property>
         <property name="toolTip">
          <string>A comma separated list of glob-style file/path patterns ignored in Fossil file operations</string>
         </property>
        </widget>
       </item>
       <item row="2" column="0">
        <widget class="QLabel" name="label_7">
         <property name="minimumSize">
          <size>
           <width>100</width>
           <height>0</height>
          </size>
         </property>
         <property name="text">
          <string>Ignore CR/NL</string>
         </property>
        </widget>
       </item>
       <item row="2" column="1">
        <widget class="QLineEdit" name="lineIgnoreCRNL">
         <property name="minimumSize">
          <size>
           <width>0</width>
           <height>0</height>
          </size>
         </property>
         <property name="toolTip">
          <string>A comma separated list of glob-style file patterns to exclude from Fossil's CR/NL consistency checking</string>
         </property>
        </widget>
       </item>
      </layout>
     </widget>
    </widget>
   </item>
   <item>
    <widget class="QDialogButtonBox" name="buttonBox">
     <property name="orientation">
      <enum>Qt::Horizontal</enum>
     </property>