Chris@109: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@109: Chris@109: /* Chris@109: EasyMercurial Chris@109: Chris@109: Based on HgExplorer by Jari Korhonen Chris@109: Copyright (c) 2010 Jari Korhonen Chris@644: Copyright (c) 2013 Chris Cannam Chris@644: Copyright (c) 2013 Queen Mary, University of London Chris@109: Chris@109: This program is free software; you can redistribute it and/or Chris@109: modify it under the terms of the GNU General Public License as Chris@109: published by the Free Software Foundation; either version 2 of the Chris@109: License, or (at your option) any later version. See the file Chris@109: COPYING included with this distribution for more information. Chris@109: */ Chris@109: Chris@92: #include "filestates.h" Chris@74: Chris@86: #include "debug.h" Chris@86: Chris@74: #include Chris@74: Chris@94: FileStates::FileStates() Chris@94: { Chris@94: } Chris@94: Chris@94: void FileStates::clearBuckets() Chris@94: { Chris@199: m_clean.clear(); Chris@94: m_modified.clear(); Chris@94: m_added.clear(); Chris@94: m_removed.clear(); Chris@94: m_missing.clear(); Chris@159: m_inConflict.clear(); Chris@94: m_unknown.clear(); Chris@199: m_ignored.clear(); Chris@94: } Chris@94: Chris@94: FileStates::State FileStates::charToState(QChar c, bool *ok) Chris@94: { Chris@159: // Note that InConflict does not correspond to a stat char -- it's Chris@163: // reported separately, by resolve --list, which shows U for Chris@163: // Unresolved -- stat reports files in conflict as M, which means Chris@163: // they will appear in more than one bin if we handle them Chris@163: // naively. 'u' is also used by stat as the command option for Chris@163: // Unknown, but the stat output uses ? for these so there's no Chris@163: // ambiguity in parsing. Chris@159: Chris@94: if (ok) *ok = true; Chris@94: if (c == 'M') return Modified; Chris@94: if (c == 'A') return Added; Chris@94: if (c == 'R') return Removed; Chris@94: if (c == '!') return Missing; Chris@163: if (c == 'U') return InConflict; Chris@94: if (c == '?') return Unknown; Chris@94: if (c == 'C') return Clean; Chris@199: if (c == 'I') return Ignored; Chris@94: if (ok) *ok = false; Chris@94: return Unknown; Chris@94: } Chris@94: Chris@94: QStringList *FileStates::stateToBucket(State s) Chris@94: { Chris@94: switch (s) { Chris@324: case Clean: return &m_clean; Chris@94: case Modified: return &m_modified; Chris@94: case Added: return &m_added; Chris@94: case Unknown: return &m_unknown; Chris@94: case Removed: return &m_removed; Chris@94: case Missing: return &m_missing; Chris@159: case InConflict: return &m_inConflict; Chris@199: case Ignored: return &m_ignored; Chris@205: Chris@205: default: return &m_clean; Chris@94: } Chris@94: } Chris@94: Chris@94: void FileStates::parseStates(QString text) Chris@74: { Chris@74: text.replace("\r\n", "\n"); Chris@74: Chris@94: clearBuckets(); Chris@163: m_stateMap.clear(); Chris@74: Chris@74: QStringList lines = text.split("\n", QString::SkipEmptyParts); Chris@94: Chris@74: foreach (QString line, lines) { Chris@94: Chris@86: if (line.length() < 3 || line[1] != ' ') { Chris@86: continue; Chris@86: } Chris@94: Chris@94: QChar c = line[0]; Chris@94: bool ok = false; Chris@94: State s = charToState(c, &ok); Chris@94: if (!ok) continue; Chris@94: Chris@74: QString file = line.right(line.length() - 2); Chris@163: m_stateMap[file] = s; Chris@163: } Chris@163: Chris@163: foreach (QString file, m_stateMap.keys()) { Chris@163: QStringList *bucket = stateToBucket(m_stateMap[file]); Chris@199: if (bucket) bucket->push_back(file); Chris@74: } Chris@86: Chris@199: DEBUG << "FileStates: " Chris@199: << m_modified.size() << " modified, " << m_added.size() Chris@159: << " added, " << m_removed.size() << " removed, " << m_missing.size() Chris@159: << " missing, " << m_inConflict.size() << " in conflict, " Chris@159: << m_unknown.size() << " unknown" << endl; Chris@74: } Chris@92: Chris@324: QStringList FileStates::filesInState(State s) const Chris@92: { Chris@94: QStringList *sl = const_cast(this)->stateToBucket(s); Chris@94: if (sl) return *sl; Chris@94: else return QStringList(); Chris@92: } Chris@92: Chris@324: bool FileStates::isInState(QString file, State s) const Chris@324: { Chris@324: return filesInState(s).contains(file); Chris@324: } Chris@324: Chris@324: FileStates::State FileStates::stateOf(QString file) const Chris@92: { Chris@94: if (m_stateMap.contains(file)) { Chris@94: return m_stateMap[file]; Chris@92: } Chris@92: DEBUG << "FileStates: WARNING: getStateOfFile: file " Chris@92: << file << " is unknown to us: returning Unknown state, " Chris@92: << "but unknown to us is not supposed to be the same " Chris@92: << "thing as unknown state..." Chris@92: << endl; Chris@92: return Unknown; Chris@92: } Chris@324: Chris@421: bool FileStates::isKnown(QString file) const Chris@421: { Chris@421: return (m_stateMap.contains(file)); Chris@421: } Chris@421: Chris@541: QStringList FileStates::trackedFiles() const Chris@541: { Chris@541: QStringList all; Chris@541: all << filesInState(Modified); Chris@541: all << filesInState(Added); Chris@541: all << filesInState(Removed); Chris@541: all << filesInState(InConflict); Chris@541: all << filesInState(Missing); Chris@541: all << filesInState(Clean); Chris@541: return all; Chris@541: } Chris@541: Chris@324: FileStates::Activities FileStates::activitiesSupportedBy(State s) Chris@324: { Chris@324: Activities a; Chris@324: Chris@324: switch (s) { Chris@324: Chris@324: case Modified: sam@624: a << Annotate << Diff << Commit << Revert << Rename << Copy << Remove << ShowIn; Chris@324: break; Chris@324: Chris@324: case Added: sam@624: a << Commit << Revert << Rename << Copy << Remove << ShowIn; Chris@324: break; Chris@324: Chris@324: case Removed: Chris@324: a << Commit << Revert << Add; Chris@324: break; Chris@324: Chris@324: case InConflict: sam@624: a << Annotate << Diff << RedoMerge << MarkResolved << Revert << ShowIn; Chris@324: break; Chris@324: Chris@324: case Missing: Chris@324: a << Revert << Remove; Chris@324: break; Chris@324: Chris@324: case Unknown: sam@625: a << Add << Ignore << ShowIn; Chris@324: break; Chris@324: Chris@324: case Clean: sam@624: a << Annotate << Rename << Copy << Remove << ShowIn; Chris@324: break; Chris@324: Chris@324: case Ignored: sam@624: a << UnIgnore << ShowIn; Chris@324: break; Chris@324: } Chris@324: Chris@324: return a; Chris@324: } Chris@324: Chris@324: bool FileStates::supportsActivity(State s, Activity a) Chris@324: { Chris@324: return activitiesSupportedBy(s).contains(a); Chris@324: } Chris@324: Chris@325: int FileStates::activityGroup(Activity a) Chris@325: { Chris@325: switch (a) { Chris@325: case Annotate: case Diff: return 0; Chris@325: case Commit: case Revert: return 1; Chris@361: case Rename: case Copy: return 2; Chris@361: case Add: case Remove: return 3; Chris@361: case RedoMerge: case MarkResolved: return 4; Chris@361: case Ignore: case UnIgnore: return 5; Chris@639: case ShowIn: return 6; Chris@325: } Chris@326: return 0; Chris@325: } Chris@325: Chris@324: bool FileStates::supportsActivity(QString file, Activity a) const Chris@324: { Chris@324: return supportsActivity(stateOf(file), a); Chris@324: } Chris@324: Chris@324: QStringList FileStates::filesSupportingActivity(Activity a) const Chris@324: { Chris@324: QStringList f; Chris@324: for (int i = int(FirstState); i <= int(LastState); ++i) { Chris@324: State s = (State)i; Chris@326: if (supportsActivity(s, a)) { Chris@326: f << filesInState(s); Chris@326: } Chris@324: } Chris@324: return f; Chris@324: } Chris@324: Chris@324: FileStates::Activities FileStates::activitiesSupportedBy(QString file) const Chris@324: { Chris@324: return activitiesSupportedBy(stateOf(file)); Chris@324: } Chris@324: