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
.file(0);
33 for (int i
=0; i
< changeSet
.count(); ++i
) {
34 File file
= changeSet
.file(i
);
35 if (file
.fileName().isEmpty() || file
.oldFileName().isEmpty())
36 file
.setProtectionAcceptance(Vng::Accepted
);
38 // make sure the first hunk is an actual change
39 if (file
.fileName() == file
.oldFileName())
40 forward(ItemScope
, true);
44 HunksCursor::~HunksCursor()
48 int HunksCursor::forward(Scope scope
, bool skipAnswered
)
50 if (m_changeSet
.count() == 0 || m_fileIndex
>= m_changeSet
.count())
51 return currentIndex();
54 Last(const ChangeSet
&changeSet
)
57 file
= changeSet
.count() - 1;
58 if (! changeSet
.hasAllHunks())
60 File f
= changeSet
.file(file
);
63 Hunk h
= f
.hunks()[hunk
];
65 subHunk
= h
.subHunkCount() - 1;
68 int file
, hunk
, subHunk
;
70 Last
last(m_changeSet
);
71 if (m_fileIndex
> last
.file
) {
72 m_fileIndex
= last
.file
+1;
75 return currentIndex(); // already at end.
80 if (++m_subHunkIndex
< currentSubHunkCount())
84 File file
= m_changeSet
.file(m_fileIndex
);
85 if (m_hunkIndex
+ 1 - 2 >= file
.count())
86 return forward(BlockScope
, skipAnswered
);
97 if (m_fileIndex
> last
.file
)
98 skipAnswered
= false; // there is nothing left;
101 m_fileIndex
= last
.file
+ 1;
108 return currentIndex();
110 File file
= m_changeSet
.file(m_fileIndex
);
111 const bool renamed
= file
.fileName() != file
.oldFileName();
112 const bool protectionChanged
= !renamed
&& file
.protection() != file
.oldProtection();
113 if (m_hunkIndex
== 0 && !renamed
)
115 if (m_hunkIndex
== 1 && !protectionChanged
)
116 return forward(ItemScope
, skipAnswered
);
119 if (m_hunkIndex
== 0 && file
.renameAcceptance() != Vng::Undecided
120 || m_hunkIndex
== 1 && file
.protectionAcceptance() != Vng::Undecided
)
121 return forward(ItemScope
, skipAnswered
);
123 if (m_hunkIndex
>= 2) { // a hunk;
124 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
125 Vng::Acceptance a
= hunk
.acceptance();
126 if (a
== Vng::Accepted
|| a
== Vng::Rejected
|| hunk
.acceptance(m_subHunkIndex
) != Vng::Undecided
) {
127 if (hunk
.subHunkCount() == m_subHunkIndex
+ 1)
128 return forward(BlockScope
, skipAnswered
);
129 return forward(ItemScope
, skipAnswered
);
133 return currentIndex();
136 int HunksCursor::back(Scope scope
)
138 if (m_changeSet
.count() == 0
139 || m_fileIndex
== 0 && m_hunkIndex
== 0 && m_subHunkIndex
== 0)
140 return currentIndex();
143 if (--m_subHunkIndex
>= 0)
146 if (--m_hunkIndex
< 1) {
148 return back(BlockScope
);
150 m_subHunkIndex
= currentSubHunkCount() - 1;
153 if (--m_fileIndex
< 0)
155 m_hunkIndex
= m_changeSet
.file(m_fileIndex
).count() -1+2;
156 Q_ASSERT(m_hunkIndex
>= 0);
157 m_subHunkIndex
= currentSubHunkCount() - 1;
166 File file
= m_changeSet
.file(m_fileIndex
);
167 const bool renamed
= file
.fileName() != file
.oldFileName();
168 const bool protectionChanged
= !renamed
&& file
.protection() != file
.oldProtection();
169 if (m_hunkIndex
== 1 && !protectionChanged
)
171 if (m_hunkIndex
== 0 && !renamed
)
172 return back(BlockScope
);
174 return currentIndex();
177 void HunksCursor::setResponse(bool response
, Scope scope
)
179 if (m_changeSet
.count() == 0)
181 const Vng::Acceptance accept
= response
? Vng::Accepted
: Vng::Rejected
;
183 if (scope
== ItemScope
) {
184 File file
= m_changeSet
.file(m_fileIndex
);
185 if (m_hunkIndex
== 0) {
186 if (!response
&& file
.oldFileName().isEmpty()
187 || response
&& file
.fileName().isEmpty()) { // new file that is not added, removed file that we want added.
188 setResponse(response
, BlockScope
);
191 file
.setRenameAcceptance(accept
);
193 else if (m_hunkIndex
== 1)
194 file
.setProtectionAcceptance(accept
);
196 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
197 hunk
.setAcceptance(m_subHunkIndex
, accept
);
202 int fileIndex
= m_fileIndex
;
203 int hunkIndex
= m_hunkIndex
;
206 File file
= m_changeSet
.file(fileIndex
);
207 QList
<Hunk
> hunks
= file
.hunks();
210 file
.setRenameAcceptance(accept
);
211 else if (hunkIndex
== 1)
212 file
.setProtectionAcceptance(accept
);
214 hunks
[hunkIndex
- 2].setAcceptance(accept
);
216 } while(scope
>= BlockScope
&& hunkIndex
-2 < hunks
.count());
219 } while(scope
== FullRange
&& fileIndex
< m_changeSet
.count());
222 int HunksCursor::count()
224 if (m_totalHunks
== -1 && m_changeSet
.hasAllHunks())
229 void HunksCursor::forceCount()
231 if (m_totalHunks
< 0) {
233 for (int i
=0; i
< m_changeSet
.count(); ++i
) {
234 File file
= m_changeSet
.file(i
);
235 if (file
.fileName() != file
.oldFileName())
237 else if (file
.protection() != file
.oldProtection())
239 foreach(Hunk hunk
, file
.hunks())
240 total
+= hunk
.subHunkCount();
242 m_totalHunks
= total
;
246 int HunksCursor::currentIndex() const
249 const int end
= qMin(m_changeSet
.count(), m_fileIndex
+1);
252 File file
= m_changeSet
.file(i
);
253 const bool renamed
= file
.fileName() != file
.oldFileName();
254 const bool protectionChanged
= !renamed
&& file
.protection() != file
.oldProtection();
255 QList
<Hunk
> hunks
= file
.hunks();
257 if (i
== end
&& m_fileIndex
< m_changeSet
.count()) {
258 if (m_hunkIndex
> 0 && renamed
)
260 if (m_hunkIndex
> 1 && protectionChanged
)
262 hunks
= hunks
.mid(0, m_hunkIndex
- 2);
267 if (protectionChanged
)
270 QList
<Hunk
>::Iterator iter2
= hunks
.begin();
272 while(iter2
!= hunks
.end()) {
273 if (isValid() && i
== end
&& m_hunkIndex
< index
++)
275 answer
+= (*iter2
).subHunkCount();
279 return answer
+ m_subHunkIndex
;
282 QString
HunksCursor::currentText() const
285 if (m_changeSet
.count() <= m_fileIndex
)
287 File file
= m_changeSet
.file(m_fileIndex
);
290 QTextStream
ts(&output
);
292 m_config
->colorize(ts
);
293 if (m_hunkIndex
== 0) { // file rename
294 if (file
.fileName().isEmpty())
296 else if (file
.oldFileName().isEmpty())
301 else if (m_hunkIndex
== 1) // protections change
302 ts
<< "mode change ";
306 m_config
->normalColor(ts
);
307 if (m_hunkIndex
== 0) {
308 if (!file
.oldFileName().isEmpty())
309 ts
<< "`" << file
.oldFileName() << "' ";
310 if (! file
.fileName().isEmpty())
311 ts
<< "`" << file
.fileName() << "'";
313 else if (m_hunkIndex
== 1)
314 ts
<< file
.fileName() << " " << file
.oldProtection() << " => " << file
.protection() << endl
;
316 if (m_hunkIndex
< 2) {
322 if (file
.count() <= m_hunkIndex
- 2)
323 return "no change\n";
324 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
325 bytes
.append(file
.fileName());
327 bytes
.append(QString::number(hunk
.lineNumber(m_subHunkIndex
)));
328 //bytes.append("[subhunk "+ QString::number(m_subHunkIndex + 1) +"/"+ QString::number(hunk.subHunkCount()) +"]");
331 QByteArray patch
= hunk
.subHunk(m_subHunkIndex
);
332 //m_config.normalColor(out);
333 if (patch
.contains((char) 0)) { // binary
334 //m_config.colorize(out);
335 bytes
.append(QString("binary data\n"));
336 //m_config.normalColor(out);
342 return output
+ QString(bytes
);
345 QString
HunksCursor::helpMessage() const
348 "How to use revert...\n"
349 "y: revert this patch\n"
350 "n: don't revert it\n\n"
352 "s: don't revert the rest of the changes to this file\n"
353 "f: revert the rest of the changes to this file\n\n"
355 "d: revert selected patches, skipping all the remaining patches\n"
356 "a: revert all the remaining patches\n"
357 "q: cancel revert\n\n"
359 "j: skip to next patch\n"
360 "k: back up to previous patch\n"
361 "c: calculate number of patches\n"
362 "h or ?: show this help\n");
365 int HunksCursor::currentSubHunkCount()
367 File file
= m_changeSet
.file(m_fileIndex
);
370 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
371 return hunk
.subHunkCount();
374 bool HunksCursor::isValid() const
376 return m_changeSet
.count() > 0 && m_changeSet
.count() > m_fileIndex
;
379 QString
HunksCursor::allowedOptions() const
381 QString allowed
= "ynsfqadjk";
382 if (m_totalHunks
== -1)