2 * This file is part of the vng project
3 * Copyright (C) 2008 Thomas Zander <tzander@trolltech.com>
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.
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.
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/>.
19 #include "HunksCursor.h"
20 #include "ChangeSet.h"
24 HunksCursor::HunksCursor(ChangeSet
&changeSet
)
25 : m_changeSet(changeSet
),
31 if (changeSet
.count()) {
32 File file
= changeSet
.files()[0];
33 foreach (File file
, changeSet
.files()) {
34 if (file
.fileName().isEmpty() || file
.oldFileName().isEmpty())
35 file
.setProtectionAcceptance(Vng::Accepted
);
37 // make sure the first hunk is an actual change
38 if (file
.fileName() == file
.oldFileName())
39 forward(ItemScope
, true);
43 HunksCursor::~HunksCursor()
47 int HunksCursor::forward(Scope scope
, bool skipAnswered
)
49 if (m_changeSet
.count() == 0 || m_fileIndex
>= m_changeSet
.count())
50 return currentIndex();
53 Last(const ChangeSet
&changeSet
)
56 file
= changeSet
.count() - 1;
57 File f
= changeSet
.files().at(file
);
60 Hunk h
= f
.hunks()[hunk
];
62 subHunk
= h
.subHunkCount() - 1;
65 int file
, hunk
, subHunk
;
67 Last
last(m_changeSet
);
68 if (m_fileIndex
> last
.file
) {
69 m_fileIndex
= last
.file
+1;
72 return currentIndex(); // already at end.
77 if (++m_subHunkIndex
< currentSubHunkCount())
81 File file
= m_changeSet
.files().at(m_fileIndex
);
82 if (m_hunkIndex
+ 1 - 2 >= file
.count())
83 return forward(BlockScope
, skipAnswered
);
94 if (m_fileIndex
> last
.file
)
95 skipAnswered
= false; // there is nothing left;
98 m_fileIndex
= last
.file
+ 1;
105 return currentIndex();
107 File file
= m_changeSet
.files()[m_fileIndex
];
108 const bool renamed
= file
.fileName() != file
.oldFileName();
109 const bool protectionChanged
= !renamed
&& file
.protection() != file
.oldProtection();
110 if (m_hunkIndex
== 0 && !renamed
)
112 if (m_hunkIndex
== 1 && !protectionChanged
)
113 return forward(ItemScope
, skipAnswered
);
116 if (m_hunkIndex
== 0 && file
.renameAcceptance() != Vng::Undecided
117 || m_hunkIndex
== 1 && file
.protectionAcceptance() != Vng::Undecided
)
118 return forward(ItemScope
, skipAnswered
);
120 if (m_hunkIndex
>= 2) { // a hunk;
121 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
122 Vng::Acceptance a
= hunk
.acceptance();
123 if (a
== Vng::Accepted
|| a
== Vng::Rejected
|| hunk
.acceptance(m_subHunkIndex
) != Vng::Undecided
) {
124 if (hunk
.subHunkCount() == m_subHunkIndex
+ 1)
125 return forward(BlockScope
, skipAnswered
);
126 return forward(ItemScope
, skipAnswered
);
130 return currentIndex();
133 int HunksCursor::back(Scope scope
)
135 if (m_changeSet
.count() == 0
136 || m_fileIndex
== 0 && m_hunkIndex
== 0 && m_subHunkIndex
== 0)
137 return currentIndex();
140 if (--m_subHunkIndex
>= 0)
143 if (--m_hunkIndex
< 1) {
145 return back(BlockScope
);
147 m_subHunkIndex
= currentSubHunkCount() - 1;
150 if (--m_fileIndex
< 0)
152 m_hunkIndex
= m_changeSet
.files().at(m_fileIndex
).count() -1+2;
153 Q_ASSERT(m_hunkIndex
>= 0);
154 m_subHunkIndex
= currentSubHunkCount() - 1;
163 File file
= m_changeSet
.files()[m_fileIndex
];
164 const bool renamed
= file
.fileName() != file
.oldFileName();
165 const bool protectionChanged
= !renamed
&& file
.protection() != file
.oldProtection();
166 if (m_hunkIndex
== 1 && !protectionChanged
)
168 if (m_hunkIndex
== 0 && !renamed
)
169 return back(BlockScope
);
171 return currentIndex();
174 void HunksCursor::setResponse(bool response
, Scope scope
)
176 if (m_changeSet
.count() == 0)
178 const Vng::Acceptance accept
= response
? Vng::Accepted
: Vng::Rejected
;
180 if (scope
== ItemScope
) {
181 File file
= m_changeSet
.files()[m_fileIndex
];
182 if (m_hunkIndex
== 0) {
183 if (!response
&& file
.oldFileName().isEmpty()
184 || response
&& file
.fileName().isEmpty()) { // new file that is not added, removed file that we want added.
185 setResponse(response
, BlockScope
);
188 file
.setRenameAcceptance(accept
);
190 else if (m_hunkIndex
== 1)
191 file
.setProtectionAcceptance(accept
);
193 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
194 hunk
.setAcceptance(m_subHunkIndex
, accept
);
199 int fileIndex
= m_fileIndex
;
200 int hunkIndex
= m_hunkIndex
;
203 File file
= m_changeSet
.files()[fileIndex
];
204 QList
<Hunk
> hunks
= file
.hunks();
207 file
.setRenameAcceptance(accept
);
208 else if (hunkIndex
== 1)
209 file
.setProtectionAcceptance(accept
);
211 hunks
[hunkIndex
- 2].setAcceptance(accept
);
213 } while(scope
>= BlockScope
&& hunkIndex
-2 < hunks
.count());
216 } while(scope
== FullRange
&& fileIndex
< m_changeSet
.count());
219 int HunksCursor::count()
224 void HunksCursor::forceCount()
226 if (m_totalHunks
< 0) {
228 foreach(File file
, m_changeSet
.files()) {
229 if (file
.fileName() != file
.oldFileName())
231 else if (file
.protection() != file
.oldProtection())
233 foreach(Hunk hunk
, file
.hunks())
234 total
+= hunk
.subHunkCount();
236 m_totalHunks
= total
;
240 int HunksCursor::currentIndex() const
243 QList
<File
> files
= m_changeSet
.files().mid(0, m_fileIndex
+ 1);
244 QList
<File
>::Iterator iter
= files
.begin();
245 while(iter
!= files
.end()) {
247 const bool renamed
= file
.fileName() != file
.oldFileName();
248 const bool protectionChanged
= !renamed
&& file
.protection() != file
.oldProtection();
249 QList
<Hunk
> hunks
= file
.hunks();
251 if (iter
== files
.end() && m_fileIndex
< m_changeSet
.count()) {
252 if (m_hunkIndex
> 0 && renamed
)
254 if (m_hunkIndex
> 1 && protectionChanged
)
256 hunks
= hunks
.mid(0, m_hunkIndex
- 2);
261 if (protectionChanged
)
264 QList
<Hunk
>::Iterator iter2
= hunks
.begin();
266 while(iter2
!= hunks
.end()) {
267 if (isValid() && iter
== files
.end() && m_hunkIndex
< index
++)
269 answer
+= (*iter2
).subHunkCount();
273 return answer
+ m_subHunkIndex
;
276 QString
HunksCursor::currentText() const
279 if (m_changeSet
.count() <= m_fileIndex
)
281 File file
= m_changeSet
.files()[m_fileIndex
];
284 QTextStream
ts(&output
);
286 m_config
->colorize(ts
);
287 if (m_hunkIndex
== 0) { // file rename
288 if (file
.fileName().isEmpty())
290 else if (file
.oldFileName().isEmpty())
295 else if (m_hunkIndex
== 1) // protections change
296 ts
<< "mode change ";
300 m_config
->normalColor(ts
);
301 if (m_hunkIndex
== 0) {
302 if (!file
.oldFileName().isEmpty())
303 ts
<< "`" << file
.oldFileName() << "' ";
304 if (! file
.fileName().isEmpty())
305 ts
<< "`" << file
.fileName() << "'";
307 else if (m_hunkIndex
== 1)
308 ts
<< file
.fileName() << " " << file
.oldProtection() << " => " << file
.protection() << endl
;
310 if (m_hunkIndex
< 2) {
316 if (file
.count() <= m_hunkIndex
- 2)
317 return "no change\n";
318 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
319 bytes
.append(file
.fileName());
321 bytes
.append(QString::number(hunk
.lineNumber(m_subHunkIndex
)));
322 //bytes.append("[subhunk "+ QString::number(m_subHunkIndex + 1) +"/"+ QString::number(hunk.subHunkCount()) +"]");
325 QByteArray patch
= hunk
.subHunk(m_subHunkIndex
);
326 //m_config.normalColor(out);
327 if (patch
.contains((char) 0)) { // binary
328 //m_config.colorize(out);
329 bytes
.append(QString("binary data\n"));
330 //m_config.normalColor(out);
336 return output
+ QString(bytes
);
339 QString
HunksCursor::helpMessage() const
342 "How to use revert...\n"
343 "y: revert this patch\n"
344 "n: don't revert it\n\n"
346 "s: don't revert the rest of the changes to this file\n"
347 "f: revert the rest of the changes to this file\n\n"
349 "d: revert selected patches, skipping all the remaining patches\n"
350 "a: revert all the remaining patches\n"
351 "q: cancel revert\n\n"
353 "j: skip to next patch\n"
354 "k: back up to previous patch\n"
355 "c: calculate number of patches\n"
356 "h or ?: show this help\n");
359 int HunksCursor::currentSubHunkCount()
361 File file
= m_changeSet
.files()[m_fileIndex
];
364 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
365 return hunk
.subHunkCount();
368 bool HunksCursor::isValid() const
370 return m_changeSet
.count() > 0 && m_changeSet
.count() > m_fileIndex
;
373 QString
HunksCursor::allowedOptions() const
375 QString allowed
= "ynsfqadjk";
376 if (m_totalHunks
== -1)