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 // make sure the first hunk is an actual change
33 File file
= changeSet
.file(0);
34 if (file
.fileName() == file
.oldFileName())
35 forward(ItemScope
, true);
39 HunksCursor::~HunksCursor()
43 int HunksCursor::forward(Scope scope
, bool skipAnswered
)
45 if (m_changeSet
.count() == 0 || m_fileIndex
>= m_changeSet
.count())
46 return currentIndex();
49 Last(const ChangeSet
&changeSet
)
52 file
= changeSet
.count() - 1;
53 if (! changeSet
.hasAllHunks())
55 File f
= changeSet
.file(file
);
58 Hunk h
= f
.hunks()[hunk
];
60 subHunk
= h
.subHunkCount() - 1;
63 int file
, hunk
, subHunk
;
65 Last
last(m_changeSet
);
66 if (m_fileIndex
> last
.file
) {
67 m_fileIndex
= last
.file
+1;
70 return currentIndex(); // already at end.
75 if (++m_subHunkIndex
< currentSubHunkCount())
79 File file
= m_changeSet
.file(m_fileIndex
);
80 if (m_hunkIndex
+ 1 - 2 >= file
.count())
81 return forward(BlockScope
, skipAnswered
);
92 if (m_fileIndex
> last
.file
)
93 skipAnswered
= false; // there is nothing left;
96 m_fileIndex
= last
.file
+ 1;
103 return currentIndex();
105 File file
= m_changeSet
.file(m_fileIndex
);
106 const bool renamed
= file
.fileName() != file
.oldFileName();
107 const bool protectionChanged
= !renamed
&& file
.protection() != file
.oldProtection();
108 if (m_hunkIndex
== 0 && !renamed
)
110 if (m_hunkIndex
== 1 && !protectionChanged
)
111 return forward(ItemScope
, skipAnswered
);
114 if (m_hunkIndex
== 0 && file
.renameAcceptance() != Vng::Undecided
115 || m_hunkIndex
== 1 && file
.protectionAcceptance() != Vng::Undecided
)
116 return forward(ItemScope
, skipAnswered
);
118 if (m_hunkIndex
>= 2) { // a hunk;
119 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
120 Vng::Acceptance a
= hunk
.acceptance();
121 if (a
== Vng::Accepted
|| a
== Vng::Rejected
|| hunk
.acceptance(m_subHunkIndex
) != Vng::Undecided
) {
122 if (hunk
.subHunkCount() == m_subHunkIndex
+ 1)
123 return forward(BlockScope
, skipAnswered
);
124 return forward(ItemScope
, skipAnswered
);
128 return currentIndex();
131 int HunksCursor::back(Scope scope
)
133 if (m_changeSet
.count() == 0
134 || m_fileIndex
== 0 && m_hunkIndex
== 0 && m_subHunkIndex
== 0)
135 return currentIndex();
138 if (--m_subHunkIndex
>= 0)
141 if (--m_hunkIndex
< 1) {
143 return back(BlockScope
);
145 m_subHunkIndex
= currentSubHunkCount() - 1;
148 if (--m_fileIndex
< 0)
150 m_hunkIndex
= m_changeSet
.file(m_fileIndex
).count() -1+2;
151 Q_ASSERT(m_hunkIndex
>= 0);
152 m_subHunkIndex
= currentSubHunkCount() - 1;
161 File file
= m_changeSet
.file(m_fileIndex
);
162 const bool renamed
= file
.fileName() != file
.oldFileName();
163 const bool protectionChanged
= !renamed
&& file
.protection() != file
.oldProtection();
164 if (m_hunkIndex
== 1 && !protectionChanged
)
166 if (m_hunkIndex
== 0 && !renamed
)
167 return back(BlockScope
);
169 return currentIndex();
172 void HunksCursor::setResponse(bool response
, Scope scope
)
174 if (m_changeSet
.count() == 0)
176 const Vng::Acceptance accept
= response
? Vng::Accepted
: Vng::Rejected
;
178 if (scope
== ItemScope
) {
179 File file
= m_changeSet
.file(m_fileIndex
);
180 if (m_hunkIndex
== 0) {
181 if (!response
&& file
.oldFileName().isEmpty()
182 || response
&& file
.fileName().isEmpty()) { // new file that is not added, removed file that we want added.
183 setResponse(response
, BlockScope
);
186 file
.setRenameAcceptance(accept
);
188 else if (m_hunkIndex
== 1)
189 file
.setProtectionAcceptance(accept
);
191 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
192 hunk
.setAcceptance(m_subHunkIndex
, accept
);
197 int fileIndex
= m_fileIndex
;
198 int hunkIndex
= m_hunkIndex
;
201 File file
= m_changeSet
.file(fileIndex
);
202 QList
<Hunk
> hunks
= file
.hunks();
205 file
.setRenameAcceptance(accept
);
206 else if (hunkIndex
== 1)
207 file
.setProtectionAcceptance(accept
);
209 hunks
[hunkIndex
- 2].setAcceptance(accept
);
211 } while(scope
>= BlockScope
&& hunkIndex
-2 < hunks
.count());
214 } while(scope
== FullRange
&& fileIndex
< m_changeSet
.count());
217 int HunksCursor::count()
219 if (m_totalHunks
== -1 && m_changeSet
.hasAllHunks())
224 void HunksCursor::forceCount()
226 if (m_totalHunks
< 0) {
228 for (int i
=0; i
< m_changeSet
.count(); ++i
) {
229 File file
= m_changeSet
.file(i
);
230 if (file
.fileName() != file
.oldFileName())
232 else if (file
.protection() != file
.oldProtection())
234 foreach(Hunk hunk
, file
.hunks())
235 total
+= hunk
.subHunkCount();
237 m_totalHunks
= total
;
241 int HunksCursor::currentIndex() const
244 const int end
= qMin(m_changeSet
.count(), m_fileIndex
+1);
247 File file
= m_changeSet
.file(i
);
248 const bool renamed
= file
.fileName() != file
.oldFileName();
249 const bool protectionChanged
= !renamed
&& file
.protection() != file
.oldProtection();
250 QList
<Hunk
> hunks
= file
.hunks();
252 if (i
== end
&& m_fileIndex
< m_changeSet
.count()) {
253 if (m_hunkIndex
> 0 && renamed
)
255 if (m_hunkIndex
> 1 && protectionChanged
)
257 hunks
= hunks
.mid(0, m_hunkIndex
- 2);
262 if (protectionChanged
)
265 QList
<Hunk
>::Iterator iter2
= hunks
.begin();
267 while(iter2
!= hunks
.end()) {
268 if (isValid() && i
== end
&& m_hunkIndex
< index
++)
270 answer
+= (*iter2
).subHunkCount();
274 return answer
+ m_subHunkIndex
;
277 QString
HunksCursor::currentText() const
280 if (m_changeSet
.count() <= m_fileIndex
)
282 File file
= m_changeSet
.file(m_fileIndex
);
285 QTextStream
ts(&output
);
287 m_config
->colorize(ts
);
288 if (m_hunkIndex
== 0) { // file rename
289 if (file
.fileName().isEmpty())
291 else if (file
.oldFileName().isEmpty())
296 else if (m_hunkIndex
== 1) // protections change
297 ts
<< "mode change ";
301 m_config
->normalColor(ts
);
302 if (m_hunkIndex
== 0) {
303 if (!file
.oldFileName().isEmpty())
304 ts
<< "`" << file
.oldFileName() << "' ";
305 if (! file
.fileName().isEmpty())
306 ts
<< "`" << file
.fileName() << "'";
308 else if (m_hunkIndex
== 1)
309 ts
<< file
.fileName() << " " << file
.oldProtection() << " => " << file
.protection() << endl
;
311 if (m_hunkIndex
< 2) {
317 if (file
.count() <= m_hunkIndex
- 2)
318 return "no change\n";
319 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
320 bytes
.append(file
.fileName());
322 bytes
.append(QString::number(hunk
.lineNumber(m_subHunkIndex
)));
323 //bytes.append("[subhunk "+ QString::number(m_subHunkIndex + 1) +"/"+ QString::number(hunk.subHunkCount()) +"]");
326 QByteArray patch
= hunk
.subHunk(m_subHunkIndex
);
327 //m_config.normalColor(out);
328 if (patch
.contains((char) 0)) { // binary
329 //m_config.colorize(out);
330 bytes
.append(QString("binary data\n"));
331 //m_config.normalColor(out);
337 return output
+ QString(bytes
);
340 QString
HunksCursor::helpMessage() const
343 "How to use revert...\n"
344 "y: revert this patch\n"
345 "n: don't revert it\n\n"
347 "s: don't revert the rest of the changes to this file\n"
348 "f: revert the rest of the changes to this file\n\n"
350 "d: revert selected patches, skipping all the remaining patches\n"
351 "a: revert all the remaining patches\n"
352 "q: cancel revert\n\n"
354 "j: skip to next patch\n"
355 "k: back up to previous patch\n"
356 "c: calculate number of patches\n"
357 "h or ?: show this help\n");
360 int HunksCursor::currentSubHunkCount()
362 File file
= m_changeSet
.file(m_fileIndex
);
365 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
366 return hunk
.subHunkCount();
369 bool HunksCursor::isValid() const
371 return m_changeSet
.count() > 0 && m_changeSet
.count() > m_fileIndex
;
374 QString
HunksCursor::allowedOptions() const
376 QString allowed
= "ynsfqadjk";
377 if (m_totalHunks
== -1)