|
1 /* |
|
2 * LDForge: LDraw parts authoring CAD |
|
3 * Copyright (C) 2013 Santeri Piippo |
|
4 * |
|
5 * This program is free software: you can redistribute it and/or modify |
|
6 * it under the terms of the GNU General Public License as published by |
|
7 * the Free Software Foundation, either version 3 of the License, or |
|
8 * (at your option) any later version. |
|
9 * |
|
10 * This program is distributed in the hope that it will be useful, |
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 * GNU General Public License for more details. |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License |
|
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
17 */ |
|
18 |
|
19 #include "historyDialog.h" |
|
20 #include "history.h" |
|
21 #include "colors.h" |
|
22 #include <qboxlayout.h> |
|
23 #include <qmessagebox.h> |
|
24 |
|
25 EXTERN_ACTION (undo); |
|
26 EXTERN_ACTION (redo); |
|
27 |
|
28 // ============================================================================= |
|
29 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
30 // ============================================================================= |
|
31 HistoryDialog::HistoryDialog (QWidget* parent, Qt::WindowFlags f) : QDialog (parent, f) { |
|
32 historyList = new QListWidget; |
|
33 undoButton = new QPushButton ("Undo"); |
|
34 redoButton = new QPushButton ("Redo"); |
|
35 clearButton = new QPushButton ("Clear"); |
|
36 buttons = new QDialogButtonBox (QDialogButtonBox::Close); |
|
37 |
|
38 historyList->setAlternatingRowColors (true); |
|
39 |
|
40 undoButton->setIcon (getIcon ("undo")); |
|
41 redoButton->setIcon (getIcon ("redo")); |
|
42 |
|
43 connect (undoButton, SIGNAL (clicked ()), this, SLOT (slot_undo ())); |
|
44 connect (redoButton, SIGNAL (clicked ()), this, SLOT (slot_redo ())); |
|
45 connect (clearButton, SIGNAL (clicked ()), this, SLOT (slot_clear ())); |
|
46 connect (buttons, SIGNAL (rejected ()), this, SLOT (reject ())); |
|
47 connect (historyList, SIGNAL (itemSelectionChanged ()), this, SLOT (slot_selChanged ())); |
|
48 |
|
49 QVBoxLayout* qButtonLayout = new QVBoxLayout; |
|
50 qButtonLayout->setDirection (QBoxLayout::TopToBottom); |
|
51 qButtonLayout->addWidget (undoButton); |
|
52 qButtonLayout->addWidget (redoButton); |
|
53 qButtonLayout->addWidget (clearButton); |
|
54 qButtonLayout->addStretch (); |
|
55 |
|
56 QGridLayout* qLayout = new QGridLayout; |
|
57 qLayout->setColumnStretch (0, 1); |
|
58 qLayout->addWidget (historyList, 0, 0, 2, 1); |
|
59 qLayout->addLayout (qButtonLayout, 0, 1); |
|
60 qLayout->addWidget (buttons, 1, 1); |
|
61 |
|
62 setLayout (qLayout); |
|
63 setWindowIcon (getIcon ("history")); |
|
64 setWindowTitle (APPNAME " - Edit history"); |
|
65 |
|
66 populateList (); |
|
67 updateButtons (); |
|
68 updateSelection (); |
|
69 } |
|
70 |
|
71 // ============================================================================= |
|
72 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
73 // ============================================================================= |
|
74 void HistoryDialog::populateList () { |
|
75 historyList->clear (); |
|
76 |
|
77 QListWidgetItem* qItem = new QListWidgetItem; |
|
78 qItem->setText ("[[ initial state ]]"); |
|
79 qItem->setIcon (getIcon ("empty")); |
|
80 historyList->addItem (qItem); |
|
81 |
|
82 for (HistoryEntry* entry : History::entries ()) { |
|
83 str text; |
|
84 QIcon entryIcon; |
|
85 |
|
86 switch (entry->type ()) { |
|
87 case HISTORY_Add: |
|
88 { |
|
89 AddHistory* subentry = static_cast<AddHistory*> (entry); |
|
90 ulong count = subentry->paObjs.size (); |
|
91 str verb = "Added"; |
|
92 |
|
93 switch (subentry->eType) { |
|
94 case AddHistory::Paste: |
|
95 verb = "Pasted"; |
|
96 entryIcon = getIcon ("paste"); |
|
97 break; |
|
98 |
|
99 default: |
|
100 { |
|
101 // Determine a common type for these objects. If all objects are of the same |
|
102 // type, we display its addition icon. Otherwise, we draw a subfile addition |
|
103 // one as a default. |
|
104 LDObject::Type eCommonType = LDObject::Unidentified; |
|
105 for (LDObject* obj : subentry->paObjs) { |
|
106 if (eCommonType == LDObject::Unidentified or obj->getType() == eCommonType) |
|
107 eCommonType = obj->getType (); |
|
108 else { |
|
109 eCommonType = LDObject::Unidentified; |
|
110 break; |
|
111 } |
|
112 } |
|
113 |
|
114 // Set the icon based on the common type decided above. |
|
115 if (eCommonType == LDObject::Unidentified) |
|
116 entryIcon = getIcon ("add-subfile"); |
|
117 else |
|
118 entryIcon = getIcon (fmt ("add-%s", g_saObjTypeIcons[eCommonType])); |
|
119 } |
|
120 break; |
|
121 } |
|
122 |
|
123 text.format ("%s %lu objects\n%s", verb.chars(), count, |
|
124 LDObject::objectListContents (subentry->paObjs).chars()); |
|
125 } |
|
126 break; |
|
127 |
|
128 case HISTORY_QuadSplit: |
|
129 { |
|
130 QuadSplitHistory* subentry = static_cast<QuadSplitHistory*> (entry); |
|
131 ulong ulCount = subentry->paQuads.size (); |
|
132 text.format ("Split %lu quad%s to triangles", ulCount, PLURAL (ulCount)); |
|
133 |
|
134 entryIcon = getIcon ("quad-split"); |
|
135 } |
|
136 break; |
|
137 |
|
138 case HISTORY_Del: |
|
139 { |
|
140 DelHistory* subentry = static_cast<DelHistory*> (entry); |
|
141 ulong count = subentry->cache.size (); |
|
142 str verb = "Deleted"; |
|
143 entryIcon = getIcon ("delete"); |
|
144 |
|
145 switch (subentry->eType) { |
|
146 case DelHistory::Cut: |
|
147 entryIcon = getIcon ("cut"); |
|
148 verb = "Cut"; |
|
149 break; |
|
150 |
|
151 default: |
|
152 break; |
|
153 } |
|
154 |
|
155 text.format ("%s %lu objects:\n%s", verb.chars(), count, |
|
156 LDObject::objectListContents (subentry->cache).chars ()); |
|
157 } |
|
158 break; |
|
159 |
|
160 case HISTORY_SetColor: |
|
161 { |
|
162 SetColorHistory* subentry = static_cast<SetColorHistory*> (entry); |
|
163 ulong count = subentry->ulaIndices.size (); |
|
164 text.format ("Set color of %lu objects to %d (%s)", count, |
|
165 subentry->dNewColor, getColor (subentry->dNewColor)->zName.chars()); |
|
166 |
|
167 entryIcon = getIcon ("palette"); |
|
168 } |
|
169 break; |
|
170 |
|
171 case HISTORY_ListMove: |
|
172 { |
|
173 ListMoveHistory* subentry = static_cast<ListMoveHistory*> (entry); |
|
174 ulong ulCount = subentry->ulaIndices.size (); |
|
175 |
|
176 text.format ("Moved %lu objects %s", ulCount, |
|
177 subentry->bUp ? "up" : "down"); |
|
178 entryIcon = getIcon (subentry->bUp ? "arrow-up" : "arrow-down"); |
|
179 } |
|
180 break; |
|
181 |
|
182 case HISTORY_Edit: |
|
183 { |
|
184 EditHistory* subentry = static_cast<EditHistory*> (entry); |
|
185 |
|
186 text.format ("Edited %u objects\n%s", |
|
187 subentry->paNewObjs.size(), |
|
188 LDObject::objectListContents (subentry->paOldObjs).chars ()); |
|
189 entryIcon = getIcon ("set-contents"); |
|
190 } |
|
191 break; |
|
192 |
|
193 case HISTORY_Inline: |
|
194 { |
|
195 InlineHistory* subentry = static_cast<InlineHistory*> (entry); |
|
196 |
|
197 text.format ("%s %lu subfiles:\n%lu resultants", |
|
198 (subentry->bDeep) ? "Deep-inlined" : "Inlined", |
|
199 (ulong) subentry->paRefs.size(), |
|
200 (ulong) subentry->ulaBitIndices.size()); |
|
201 |
|
202 entryIcon = getIcon (subentry->bDeep ? "inline-deep" : "inline"); |
|
203 } |
|
204 break; |
|
205 |
|
206 default: |
|
207 text = "???"; |
|
208 break; |
|
209 } |
|
210 |
|
211 QListWidgetItem* item = new QListWidgetItem; |
|
212 item->setText (text); |
|
213 item->setIcon (entryIcon); |
|
214 historyList->addItem (item); |
|
215 } |
|
216 } |
|
217 |
|
218 // ============================================================================= |
|
219 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
220 // ============================================================================= |
|
221 void HistoryDialog::slot_undo () { |
|
222 History::undo (); |
|
223 updateButtons (); |
|
224 updateSelection (); |
|
225 } |
|
226 |
|
227 // ============================================================================= |
|
228 void HistoryDialog::slot_redo () { |
|
229 History::redo (); |
|
230 updateButtons (); |
|
231 updateSelection (); |
|
232 } |
|
233 |
|
234 void HistoryDialog::updateSelection () { |
|
235 historyList->setCurrentItem (historyList->item (History::pos () + 1)); |
|
236 } |
|
237 |
|
238 // ============================================================================= |
|
239 void HistoryDialog::slot_clear () { |
|
240 if (!confirm ("Are you sure you want to clear the edit history?\nThis cannot be undone.")) |
|
241 return; // Canceled |
|
242 |
|
243 History::clear (); |
|
244 populateList (); |
|
245 updateButtons (); |
|
246 } |
|
247 |
|
248 // ============================================================================= |
|
249 void HistoryDialog::updateButtons () { |
|
250 undoButton->setEnabled (ACTION (undo)->isEnabled ()); |
|
251 redoButton->setEnabled (ACTION (redo)->isEnabled ()); |
|
252 } |
|
253 |
|
254 // ============================================================================= |
|
255 void HistoryDialog::slot_selChanged () { |
|
256 if (historyList->selectedItems ().size () != 1) |
|
257 return; |
|
258 |
|
259 QListWidgetItem* qItem = historyList->selectedItems ()[0]; |
|
260 |
|
261 // Find the index of the edit |
|
262 long lIdx; |
|
263 for (lIdx = 0; lIdx < historyList->count (); ++lIdx) |
|
264 if (historyList->item (lIdx) == qItem) |
|
265 break; |
|
266 |
|
267 // qHistoryList is 0-based, History is -1-based, thus decrement |
|
268 // the index now |
|
269 lIdx--; |
|
270 |
|
271 if (lIdx == History::pos ()) |
|
272 return; |
|
273 |
|
274 // Seek to the selected edit by repeadetly undoing or redoing. |
|
275 while (History::pos () != lIdx) { |
|
276 if (History::pos () > lIdx) |
|
277 History::undo (); |
|
278 else |
|
279 History::redo (); |
|
280 } |
|
281 |
|
282 updateButtons (); |
|
283 } |