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"
23 HunksCursor::HunksCursor(ChangeSet
&changeSet
)
24 : m_changeSet(changeSet
),
30 if (changeSet
.count()) {
31 File file
= changeSet
.files()[0];
32 foreach (File file
, changeSet
.files()) {
33 if (file
.fileName().isEmpty() || file
.oldFileName().isEmpty())
34 file
.setProtectionAcceptance(Vng::Accepted
);
36 // make sure the first hunk is an actual change
37 if (file
.fileName() == file
.oldFileName())
38 forward(ItemScope
, true);
42 HunksCursor::~HunksCursor()
46 int HunksCursor::forward(Scope scope
, bool skipAnswered
)
48 if (m_changeSet
.count() == 0 || m_fileIndex
>= m_changeSet
.count())
49 return currentIndex();
52 Last(const ChangeSet
&changeSet
)
55 file
= changeSet
.count() - 1;
56 File f
= changeSet
.files().at(file
);
59 Hunk h
= f
.hunks()[hunk
];
61 subHunk
= h
.subHunkCount() - 1;
64 int file
, hunk
, subHunk
;
66 Last
last(m_changeSet
);
67 if (m_fileIndex
> last
.file
) {
68 m_fileIndex
= last
.file
+1;
71 return currentIndex(); // already at end.
76 if (++m_subHunkIndex
< currentSubHunkCount())
80 File file
= m_changeSet
.files().at(m_fileIndex
);
81 if (m_hunkIndex
+ 1 - 2 >= file
.count())
82 return forward(BlockScope
, skipAnswered
);
93 if (m_fileIndex
> last
.file
)
94 skipAnswered
= false; // there is nothing left;
97 m_fileIndex
= last
.file
+ 1;
104 return currentIndex();
106 File file
= m_changeSet
.files()[m_fileIndex
];
107 const bool renamed
= file
.fileName() != file
.oldFileName();
108 const bool protectionChanged
= !renamed
&& file
.protection() != file
.oldProtection();
109 if (m_hunkIndex
== 0 && !renamed
)
111 if (m_hunkIndex
== 1 && !protectionChanged
)
112 return forward(ItemScope
, skipAnswered
);
115 if (m_hunkIndex
== 0 && file
.renameAcceptance() != Vng::Undecided
116 || m_hunkIndex
== 1 && file
.protectionAcceptance() != Vng::Undecided
)
117 return forward(ItemScope
, skipAnswered
);
119 if (m_hunkIndex
>= 2) { // a hunk;
120 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
121 Vng::Acceptance a
= hunk
.acceptance();
122 if (a
== Vng::Accepted
|| a
== Vng::Rejected
|| hunk
.acceptance(m_subHunkIndex
) != Vng::Undecided
) {
123 if (hunk
.subHunkCount() == m_subHunkIndex
+ 1)
124 return forward(BlockScope
, skipAnswered
);
125 return forward(ItemScope
, skipAnswered
);
129 return currentIndex();
132 int HunksCursor::back(Scope scope
)
134 if (m_changeSet
.count() == 0
135 || m_fileIndex
== 0 && m_hunkIndex
== 0 && m_subHunkIndex
== 0)
136 return currentIndex();
139 if (--m_subHunkIndex
>= 0)
142 if (--m_hunkIndex
< 1) {
144 return back(BlockScope
);
146 m_subHunkIndex
= currentSubHunkCount() - 1;
149 if (--m_fileIndex
< 0)
151 m_hunkIndex
= m_changeSet
.files().at(m_fileIndex
).count() -1+2;
152 Q_ASSERT(m_hunkIndex
>= 0);
153 m_subHunkIndex
= currentSubHunkCount() - 1;
162 File file
= m_changeSet
.files()[m_fileIndex
];
163 const bool renamed
= file
.fileName() != file
.oldFileName();
164 const bool protectionChanged
= !renamed
&& file
.protection() != file
.oldProtection();
165 if (m_hunkIndex
== 1 && !protectionChanged
)
167 if (m_hunkIndex
== 0 && !renamed
)
168 return back(BlockScope
);
170 return currentIndex();
173 void HunksCursor::setResponse(bool response
, Scope scope
)
175 if (m_changeSet
.count() == 0)
177 const Vng::Acceptance accept
= response
? Vng::Accepted
: Vng::Rejected
;
179 if (scope
== ItemScope
) {
180 File file
= m_changeSet
.files()[m_fileIndex
];
181 if (m_hunkIndex
== 0)
182 file
.setRenameAcceptance(accept
);
183 else if (m_hunkIndex
== 1)
184 file
.setProtectionAcceptance(accept
);
186 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
187 hunk
.setAcceptance(m_subHunkIndex
, accept
);
192 int fileIndex
= m_fileIndex
;
193 int hunkIndex
= m_hunkIndex
;
196 File file
= m_changeSet
.files()[fileIndex
];
197 QList
<Hunk
> hunks
= file
.hunks();
200 file
.setRenameAcceptance(accept
);
201 else if (hunkIndex
== 1)
202 file
.setProtectionAcceptance(accept
);
204 hunks
[hunkIndex
- 2].setAcceptance(accept
);
206 } while(scope
>= BlockScope
&& hunkIndex
-2 < hunks
.count());
209 } while(scope
== FullRange
&& fileIndex
< m_changeSet
.count());
212 int HunksCursor::count()
217 void HunksCursor::forceCount()
219 if (m_totalHunks
< 0) {
221 foreach(File file
, m_changeSet
.files()) {
222 if (file
.fileName() != file
.oldFileName())
224 else if (file
.protection() != file
.oldProtection())
226 foreach(Hunk hunk
, file
.hunks())
227 total
+= hunk
.subHunkCount();
229 m_totalHunks
= total
;
233 int HunksCursor::currentIndex() const
236 QList
<File
> files
= m_changeSet
.files().mid(0, m_fileIndex
+ 1);
237 QList
<File
>::Iterator iter
= files
.begin();
238 while(iter
!= files
.end()) {
240 const bool renamed
= file
.fileName() != file
.oldFileName();
241 const bool protectionChanged
= !renamed
&& file
.protection() != file
.oldProtection();
242 QList
<Hunk
> hunks
= file
.hunks();
244 if (iter
== files
.end() && m_fileIndex
< m_changeSet
.count()) {
245 if (m_hunkIndex
> 0 && renamed
)
247 if (m_hunkIndex
> 1 && protectionChanged
)
249 hunks
= hunks
.mid(0, m_hunkIndex
- 2);
254 if (protectionChanged
)
257 QList
<Hunk
>::Iterator iter2
= hunks
.begin();
259 while(iter2
!= hunks
.end()) {
260 if (isValid() && iter
== files
.end() && m_hunkIndex
< index
++)
262 answer
+= (*iter2
).subHunkCount();
266 return answer
+ m_subHunkIndex
;
269 QString
HunksCursor::currentText() const
272 if (m_changeSet
.count() <= m_fileIndex
)
274 File file
= m_changeSet
.files()[m_fileIndex
];
277 QTextStream
ts(&output
);
279 m_config
->colorize(ts
);
280 if (m_hunkIndex
== 0) { // file rename
281 if (file
.fileName().isEmpty())
283 else if (file
.oldFileName().isEmpty())
288 else if (m_hunkIndex
== 1) // protections change
289 ts
<< "mode change ";
293 m_config
->normalColor(ts
);
294 if (m_hunkIndex
== 0) {
295 if (!file
.oldFileName().isEmpty())
296 ts
<< "`" << file
.oldFileName() << "' ";
297 if (! file
.fileName().isEmpty())
298 ts
<< "`" << file
.fileName() << "'";
300 else if (m_hunkIndex
== 1)
301 ts
<< file
.fileName() << " " << file
.oldProtection() << " => " << file
.protection() << endl
;
303 if (m_hunkIndex
< 2) {
309 if (file
.count() <= m_hunkIndex
- 2)
310 return "no change\n";
311 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
312 bytes
.append(file
.fileName());
314 bytes
.append(QString::number(hunk
.lineNumber(m_subHunkIndex
)));
315 //bytes.append("[subhunk "+ QString::number(m_subHunkIndex + 1) +"/"+ QString::number(hunk.subHunkCount()) +"]");
318 QByteArray patch
= hunk
.subHunk(m_subHunkIndex
);
319 //m_config.normalColor(out);
320 if (patch
.contains((char) 0)) { // binary
321 //m_config.colorize(out);
322 bytes
.append(QString("binary data\n"));
323 //m_config.normalColor(out);
329 return output
+ QString(bytes
);
332 QString
HunksCursor::helpMessage() const
335 "How to use revert...\n"
336 "y: revert this patch\n"
337 "n: don't revert it\n\n"
339 "s: don't revert the rest of the changes to this file\n"
340 "f: revert the rest of the changes to this file\n\n"
342 "d: revert selected patches, skipping all the remaining patches\n"
343 "a: revert all the remaining patches\n"
344 "q: cancel revert\n\n"
346 "j: skip to next patch\n"
347 "k: back up to previous patch\n"
348 "c: calculate number of patches\n"
349 "h or ?: show this help\n");
352 int HunksCursor::currentSubHunkCount()
354 File file
= m_changeSet
.files()[m_fileIndex
];
357 Hunk hunk
= file
.hunks()[m_hunkIndex
- 2];
358 return hunk
.subHunkCount();
361 bool HunksCursor::isValid() const
363 return m_changeSet
.count() > 0 && m_changeSet
.count() > m_fileIndex
;
366 QString
HunksCursor::allowedOptions() const
368 QString allowed
= "ynsfqadjk";
369 if (m_totalHunks
== -1)