|
|
|
/*
|
|
|
|
* Copyright (C) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de>
|
|
|
|
* Copyright (c) 2003-2007 André Wöbbeking <Woebbeking@kde.org>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "updateview_items.h"
|
|
|
|
|
|
|
|
#include <cassert>
|
|
|
|
|
|
|
|
#include <tqdir.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <tqregexp.h>
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <tdeglobalsettings.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <kmimetype.h>
|
|
|
|
|
|
|
|
#include "cvsdir.h"
|
|
|
|
#include "entry.h"
|
|
|
|
#include "misc.h"
|
|
|
|
#include "updateview_visitors.h"
|
|
|
|
|
|
|
|
|
|
|
|
using Cervisia::Entry;
|
|
|
|
using Cervisia::EntryStatus;
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
|
|
// UpdateItem
|
|
|
|
// ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
TQString UpdateItem::dirPath() const
|
|
|
|
{
|
|
|
|
TQString path;
|
|
|
|
|
|
|
|
const UpdateItem* item = static_cast<UpdateItem*>(parent());
|
|
|
|
while (item)
|
|
|
|
{
|
|
|
|
const UpdateItem* parentItem = static_cast<UpdateItem*>(item->parent());
|
|
|
|
if (parentItem)
|
|
|
|
{
|
|
|
|
path.prepend(item->m_entry.m_name + TQDir::separator());
|
|
|
|
}
|
|
|
|
|
|
|
|
item = parentItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQString UpdateItem::filePath() const
|
|
|
|
{
|
|
|
|
// the filePath of the root item is '.'
|
|
|
|
return parent() ? dirPath() + m_entry.m_name : TQChar('.');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
|
|
// UpdateDirItem
|
|
|
|
// ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
UpdateDirItem::UpdateDirItem(UpdateDirItem* parent,
|
|
|
|
const Entry& entry)
|
|
|
|
: UpdateItem(parent, entry),
|
|
|
|
m_opened(false)
|
|
|
|
{
|
|
|
|
setExpandable(true);
|
|
|
|
setPixmap(0, SmallIcon("folder"));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UpdateDirItem::UpdateDirItem(UpdateView* parent,
|
|
|
|
const Entry& entry)
|
|
|
|
: UpdateItem(parent, entry),
|
|
|
|
m_opened(false)
|
|
|
|
{
|
|
|
|
setExpandable(true);
|
|
|
|
setPixmap(0, SmallIcon("folder"));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the status of an item; if it doesn't exist yet, create new one
|
|
|
|
*/
|
|
|
|
void UpdateDirItem::updateChildItem(const TQString& name,
|
|
|
|
EntryStatus status,
|
|
|
|
bool isdir)
|
|
|
|
{
|
|
|
|
if (UpdateItem* item = findItem(name))
|
|
|
|
{
|
|
|
|
if (isFileItem(item))
|
|
|
|
{
|
|
|
|
UpdateFileItem* fileItem = static_cast<UpdateFileItem*>(item);
|
|
|
|
fileItem->setStatus(status);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not found, make new entry
|
|
|
|
Entry entry;
|
|
|
|
entry.m_name = name;
|
|
|
|
if (isdir)
|
|
|
|
{
|
|
|
|
entry.m_type = Entry::Dir;
|
|
|
|
createDirItem(entry)->maybeScanDir(true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entry.m_type = Entry::File;
|
|
|
|
createFileItem(entry)->setStatus(status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the revision and tag of an item. Use status only to create
|
|
|
|
* new items and for items which were NotInCVS.
|
|
|
|
*/
|
|
|
|
void UpdateDirItem::updateEntriesItem(const Entry& entry,
|
|
|
|
bool isBinary)
|
|
|
|
{
|
|
|
|
if (UpdateItem* item = findItem(entry.m_name))
|
|
|
|
{
|
|
|
|
if (isFileItem(item))
|
|
|
|
{
|
|
|
|
UpdateFileItem* fileItem = static_cast<UpdateFileItem*>(item);
|
|
|
|
if (fileItem->entry().m_status == Cervisia::NotInCVS ||
|
|
|
|
fileItem->entry().m_status == Cervisia::LocallyRemoved ||
|
|
|
|
entry.m_status == Cervisia::LocallyAdded ||
|
|
|
|
entry.m_status == Cervisia::LocallyRemoved ||
|
|
|
|
entry.m_status == Cervisia::Conflict)
|
|
|
|
{
|
|
|
|
fileItem->setStatus(entry.m_status);
|
|
|
|
}
|
|
|
|
fileItem->setRevTag(entry.m_revision, entry.m_tag);
|
|
|
|
fileItem->setDate(entry.m_dateTime);
|
|
|
|
fileItem->setPixmap(0, isBinary ? SmallIcon("binary") : TQPixmap());
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not found, make new entry
|
|
|
|
if (entry.m_type == Entry::Dir)
|
|
|
|
createDirItem(entry)->maybeScanDir(true);
|
|
|
|
else
|
|
|
|
createFileItem(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UpdateDirItem::scanDirectory()
|
|
|
|
{
|
|
|
|
const TQString& path(filePath());
|
|
|
|
if (!TQFile::exists(path))
|
|
|
|
return;
|
|
|
|
|
|
|
|
const CvsDir dir(path);
|
|
|
|
|
|
|
|
const TQFileInfoList *files = dir.entryInfoList();
|
|
|
|
if (files)
|
|
|
|
{
|
|
|
|
TQFileInfoListIterator it(*files);
|
|
|
|
for (; it.current(); ++it)
|
|
|
|
{
|
|
|
|
Entry entry;
|
|
|
|
entry.m_name = it.current()->fileName();
|
|
|
|
if (it.current()->isDir())
|
|
|
|
{
|
|
|
|
entry.m_type = Entry::Dir;
|
|
|
|
createDirItem(entry);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entry.m_type = Entry::File;
|
|
|
|
entry.m_status = Cervisia::NotInCVS;
|
|
|
|
createFileItem(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UpdateDirItem* UpdateDirItem::createDirItem(const Entry& entry)
|
|
|
|
{
|
|
|
|
UpdateItem* item(insertItem(new UpdateDirItem(this, entry)));
|
|
|
|
assert(isDirItem(item));
|
|
|
|
return static_cast<UpdateDirItem*>(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UpdateFileItem* UpdateDirItem::createFileItem(const Entry& entry)
|
|
|
|
{
|
|
|
|
UpdateItem* item(insertItem(new UpdateFileItem(this, entry)));
|
|
|
|
assert(isFileItem(item));
|
|
|
|
return static_cast<UpdateFileItem*>(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UpdateItem* UpdateDirItem::insertItem(UpdateItem* item)
|
|
|
|
{
|
|
|
|
TQPair<TMapItemsByName::iterator, bool> result
|
|
|
|
= m_itemsByName.insert(TMapItemsByName::value_type(item->entry().m_name, item));
|
|
|
|
if (!result.second)
|
|
|
|
{
|
|
|
|
// OK, an item with that name already exists. If the item type is the
|
|
|
|
// same then keep the old one to preserve it's status information
|
|
|
|
UpdateItem* existingItem = *result.first;
|
|
|
|
if (existingItem->rtti() == item->rtti())
|
|
|
|
{
|
|
|
|
delete item;
|
|
|
|
item = existingItem;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// avoid dangling pointers in the view
|
|
|
|
updateView()->replaceItem(existingItem, item);
|
|
|
|
|
|
|
|
delete existingItem;
|
|
|
|
*result.first = item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UpdateItem* UpdateDirItem::findItem(const TQString& name) const
|
|
|
|
{
|
|
|
|
const TMapItemsByName::const_iterator it = m_itemsByName.find(name);
|
|
|
|
|
|
|
|
return (it != m_itemsByName.end()) ? *it : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TQt-3.3.8 changed the parsing in TQDateTime::fromString() but introduced
|
|
|
|
// a bug which leads to the problem that days with 1 digit will incorrectly being
|
|
|
|
// parsed as day 0 - which is invalid.
|
|
|
|
// workaround with the implementation from TQt-3.3.6
|
|
|
|
TQDateTime parseDateTime(const TQString &s)
|
|
|
|
{
|
|
|
|
static const char * const qt_shortMonthNames[] = {
|
|
|
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
|
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
|
|
|
|
|
|
|
TQString monthName( s.mid( 4, 3 ) );
|
|
|
|
int month = -1;
|
|
|
|
// Assume that English monthnames are the default
|
|
|
|
for ( int i = 0; i < 12; ++i ) {
|
|
|
|
if ( monthName == qt_shortMonthNames[i] ) {
|
|
|
|
month = i + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If English names can't be found, search the localized ones
|
|
|
|
if ( month == -1 ) {
|
|
|
|
for ( int i = 1; i <= 12; ++i ) {
|
|
|
|
if ( monthName == TQDate::shortMonthName( i ) ) {
|
|
|
|
month = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( month < 1 || month > 12 ) {
|
|
|
|
tqWarning( "TQDateTime::fromString: Parameter out of range" );
|
|
|
|
TQDateTime dt;
|
|
|
|
return dt;
|
|
|
|
}
|
|
|
|
int day = s.mid( 8, 2 ).simplifyWhiteSpace().toInt();
|
|
|
|
int year = s.right( 4 ).toInt();
|
|
|
|
TQDate date( year, month, day );
|
|
|
|
TQTime time;
|
|
|
|
int hour, minute, second;
|
|
|
|
int pivot = s.find( TQRegExp(TQString::fromLatin1("[0-9][0-9]:[0-9][0-9]:[0-9][0-9]")) );
|
|
|
|
if ( pivot != -1 ) {
|
|
|
|
hour = s.mid( pivot, 2 ).toInt();
|
|
|
|
minute = s.mid( pivot+3, 2 ).toInt();
|
|
|
|
second = s.mid( pivot+6, 2 ).toInt();
|
|
|
|
time.setHMS( hour, minute, second );
|
|
|
|
}
|
|
|
|
return TQDateTime( date, time );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Format of the CVS/Entries file:
|
|
|
|
// /NAME/REVISION/[CONFLICT+]TIMESTAMP/OPTIONS/TAGDATE
|
|
|
|
|
|
|
|
void UpdateDirItem::syncWithEntries()
|
|
|
|
{
|
|
|
|
const TQString path(filePath() + TQDir::separator());
|
|
|
|
|
|
|
|
TQFile f(path + "CVS/Entries");
|
|
|
|
if( f.open(IO_ReadOnly) )
|
|
|
|
{
|
|
|
|
TQTextStream stream(&f);
|
|
|
|
while( !stream.eof() )
|
|
|
|
{
|
|
|
|
TQString line = stream.readLine();
|
|
|
|
|
|
|
|
Cervisia::Entry entry;
|
|
|
|
|
|
|
|
const bool isDir(line[0] == 'D');
|
|
|
|
|
|
|
|
if( isDir )
|
|
|
|
line.remove(0, 1);
|
|
|
|
|
|
|
|
if( line[0] != '/' )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
entry.m_type = isDir ? Entry::Dir : Entry::File;
|
|
|
|
entry.m_name = line.section('/', 1, 1);
|
|
|
|
|
|
|
|
if (isDir)
|
|
|
|
{
|
|
|
|
updateEntriesItem(entry, false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TQString rev(line.section('/', 2, 2));
|
|
|
|
const TQString timestamp(line.section('/', 3, 3));
|
|
|
|
const TQString options(line.section('/', 4, 4));
|
|
|
|
entry.m_tag = line.section('/', 5, 5);
|
|
|
|
|
|
|
|
const bool isBinary(options.find("-kb") >= 0);
|
|
|
|
|
|
|
|
// file date in local time
|
|
|
|
entry.m_dateTime = TQFileInfo(path + entry.m_name).lastModified();
|
|
|
|
|
|
|
|
if( rev == "0" )
|
|
|
|
entry.m_status = Cervisia::LocallyAdded;
|
|
|
|
else if( rev.length() > 2 && rev[0] == '-' )
|
|
|
|
{
|
|
|
|
entry.m_status = Cervisia::LocallyRemoved;
|
|
|
|
rev.remove(0, 1);
|
|
|
|
}
|
|
|
|
else if (timestamp.find('+') >= 0)
|
|
|
|
{
|
|
|
|
entry.m_status = Cervisia::Conflict;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// workaround TQt-3.3.8 bug with our own function (see function above)
|
|
|
|
// const TQDateTime date(TQDateTime::fromString(timestamp)); // UTC Time
|
|
|
|
const TQDateTime date(parseDateTime(timestamp)); // UTC Time
|
|
|
|
TQDateTime fileDateUTC;
|
|
|
|
fileDateUTC.setTime_t(entry.m_dateTime.toTime_t(), Qt::UTC);
|
|
|
|
if (date != fileDateUTC)
|
|
|
|
entry.m_status = Cervisia::LocallyModified;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry.m_revision = rev;
|
|
|
|
|
|
|
|
updateEntriesItem(entry, isBinary);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test if files was removed from repository.
|
|
|
|
*/
|
|
|
|
void UpdateDirItem::syncWithDirectory()
|
|
|
|
{
|
|
|
|
TQDir dir(filePath());
|
|
|
|
|
|
|
|
for (TMapItemsByName::iterator it(m_itemsByName.begin()),
|
|
|
|
itEnd(m_itemsByName.end());
|
|
|
|
it != itEnd; ++it)
|
|
|
|
{
|
|
|
|
// only files
|
|
|
|
if (isFileItem(*it))
|
|
|
|
{
|
|
|
|
UpdateFileItem* fileItem = static_cast<UpdateFileItem*>(*it);
|
|
|
|
|
|
|
|
// is file removed?
|
|
|
|
if (!dir.exists(it.key()))
|
|
|
|
{
|
|
|
|
fileItem->setStatus(Cervisia::Removed);
|
|
|
|
fileItem->setRevTag(TQString(), TQString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Read in the content of the directory. If recursive is false, this
|
|
|
|
* is shallow, otherwise all child directories are scanned recursively.
|
|
|
|
*/
|
|
|
|
void UpdateDirItem::maybeScanDir(bool recursive)
|
|
|
|
{
|
|
|
|
if (!m_opened)
|
|
|
|
{
|
|
|
|
m_opened = true;
|
|
|
|
scanDirectory();
|
|
|
|
syncWithEntries();
|
|
|
|
|
|
|
|
// sort the created items
|
|
|
|
sort();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (recursive)
|
|
|
|
{
|
|
|
|
for (TMapItemsByName::iterator it(m_itemsByName.begin()),
|
|
|
|
itEnd(m_itemsByName.end());
|
|
|
|
it != itEnd; ++it)
|
|
|
|
{
|
|
|
|
if (isDirItem(*it))
|
|
|
|
static_cast<UpdateDirItem*>(*it)->maybeScanDir(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UpdateDirItem::accept(Visitor& visitor)
|
|
|
|
{
|
|
|
|
visitor.preVisit(this);
|
|
|
|
|
|
|
|
for (TMapItemsByName::iterator it(m_itemsByName.begin()),
|
|
|
|
itEnd(m_itemsByName.end());
|
|
|
|
it != itEnd; ++it)
|
|
|
|
{
|
|
|
|
(*it)->accept(visitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
visitor.postVisit(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UpdateDirItem::setOpen(bool open)
|
|
|
|
{
|
|
|
|
if ( open )
|
|
|
|
{
|
|
|
|
const bool openFirstTime(!wasScanned());
|
|
|
|
|
|
|
|
maybeScanDir(false);
|
|
|
|
|
|
|
|
// if new items were created their visibility must be checked
|
|
|
|
// (not while unfoldTree() as this could be slow and unfoldTree()
|
|
|
|
// calls setFilter() itself)
|
|
|
|
UpdateView* view = updateView();
|
|
|
|
if (openFirstTime && !view->isUnfoldingTree())
|
|
|
|
view->setFilter(view->filter());
|
|
|
|
}
|
|
|
|
|
|
|
|
TQListViewItem::setOpen(open);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int UpdateDirItem::compare(TQListViewItem* i,
|
|
|
|
int /*column*/,
|
|
|
|
bool bAscending) const
|
|
|
|
{
|
|
|
|
// UpdateDirItems are always lesser than UpdateFileItems
|
|
|
|
if (isFileItem(i))
|
|
|
|
return bAscending ? -1 : 1;
|
|
|
|
|
|
|
|
const UpdateDirItem* item(static_cast<UpdateDirItem*>(i));
|
|
|
|
|
|
|
|
// for every column just compare the directory name
|
|
|
|
return entry().m_name.localeAwareCompare(item->entry().m_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQString UpdateDirItem::text(int column) const
|
|
|
|
{
|
|
|
|
TQString result;
|
|
|
|
if (column == Name)
|
|
|
|
result = entry().m_name;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
|
|
// UpdateFileItem
|
|
|
|
// ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
UpdateFileItem::UpdateFileItem(UpdateDirItem* parent, const Entry& entry)
|
|
|
|
: UpdateItem(parent, entry),
|
|
|
|
m_undefined(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UpdateFileItem::setStatus(EntryStatus status)
|
|
|
|
{
|
|
|
|
if (status != m_entry.m_status)
|
|
|
|
{
|
|
|
|
m_entry.m_status = status;
|
|
|
|
const bool visible(applyFilter(updateView()->filter()));
|
|
|
|
if (visible)
|
|
|
|
repaint();
|
|
|
|
}
|
|
|
|
m_undefined = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UpdateFileItem::accept(Visitor& visitor)
|
|
|
|
{
|
|
|
|
visitor.visit(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool UpdateFileItem::applyFilter(UpdateView::Filter filter)
|
|
|
|
{
|
|
|
|
bool visible(true);
|
|
|
|
if (filter & UpdateView::OnlyDirectories)
|
|
|
|
visible = false;
|
|
|
|
|
|
|
|
bool unmodified = (entry().m_status == Cervisia::UpToDate) ||
|
|
|
|
(entry().m_status == Cervisia::Unknown);
|
|
|
|
if ((filter & UpdateView::NoUpToDate) && unmodified)
|
|
|
|
visible = false;
|
|
|
|
if ((filter & UpdateView::NoRemoved) && (entry().m_status == Cervisia::Removed))
|
|
|
|
visible = false;
|
|
|
|
if ((filter & UpdateView::NoNotInCVS) && (entry().m_status == Cervisia::NotInCVS))
|
|
|
|
visible = false;
|
|
|
|
|
|
|
|
setVisible(visible);
|
|
|
|
|
|
|
|
return visible;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UpdateFileItem::setRevTag(const TQString& rev, const TQString& tag)
|
|
|
|
{
|
|
|
|
m_entry.m_revision = rev;
|
|
|
|
|
|
|
|
if (tag.length() == 20 && tag[0] == 'D' && tag[5] == '.'
|
|
|
|
&& tag[8] == '.' && tag[11] == '.' && tag[14] == '.'
|
|
|
|
&& tag[17] == '.')
|
|
|
|
{
|
|
|
|
const TQDate tagDate(tag.mid(1, 4).toInt(),
|
|
|
|
tag.mid(6, 2).toInt(),
|
|
|
|
tag.mid(9, 2).toInt());
|
|
|
|
const TQTime tagTime(tag.mid(12, 2).toInt(),
|
|
|
|
tag.mid(15, 2).toInt(),
|
|
|
|
tag.mid(18, 2).toInt());
|
|
|
|
const TQDateTime tagDateTimeUtc(tagDate, tagTime);
|
|
|
|
|
|
|
|
if (tagDateTimeUtc.isValid())
|
|
|
|
{
|
|
|
|
// This is in UTC and must be converted to local time.
|
|
|
|
//
|
|
|
|
// A bit strange but I didn't find anything easier which is portable.
|
|
|
|
// Compute the difference between UTC and local timezone for this
|
|
|
|
// tag date.
|
|
|
|
const unsigned int dateTimeInSeconds(tagDateTimeUtc.toTime_t());
|
|
|
|
TQDateTime dateTime;
|
|
|
|
dateTime.setTime_t(dateTimeInSeconds, Qt::UTC);
|
|
|
|
const int localUtcOffset(dateTime.secsTo(tagDateTimeUtc));
|
|
|
|
|
|
|
|
const TQDateTime tagDateTimeLocal(tagDateTimeUtc.addSecs(localUtcOffset));
|
|
|
|
|
|
|
|
m_entry.m_tag = TDEGlobal::locale()->formatDateTime(tagDateTimeLocal);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_entry.m_tag = tag;
|
|
|
|
}
|
|
|
|
else if (tag.length() > 1 && tag[0] == 'T')
|
|
|
|
m_entry.m_tag = tag.mid(1);
|
|
|
|
else
|
|
|
|
m_entry.m_tag = tag;
|
|
|
|
|
|
|
|
if (isVisible())
|
|
|
|
{
|
|
|
|
widthChanged();
|
|
|
|
repaint();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UpdateFileItem::setDate(const TQDateTime& date)
|
|
|
|
{
|
|
|
|
m_entry.m_dateTime = date;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UpdateFileItem::markUpdated(bool laststage,
|
|
|
|
bool success)
|
|
|
|
{
|
|
|
|
EntryStatus newstatus = m_entry.m_status;
|
|
|
|
|
|
|
|
if (laststage)
|
|
|
|
{
|
|
|
|
if (undefinedState() && m_entry.m_status != Cervisia::NotInCVS)
|
|
|
|
newstatus = success? Cervisia::UpToDate : Cervisia::Unknown;
|
|
|
|
setStatus(newstatus);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
setUndefinedState(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int UpdateFileItem::statusClass() const
|
|
|
|
{
|
|
|
|
int iResult(0);
|
|
|
|
switch (entry().m_status)
|
|
|
|
{
|
|
|
|
case Cervisia::Conflict:
|
|
|
|
iResult = 0;
|
|
|
|
break;
|
|
|
|
case Cervisia::LocallyAdded:
|
|
|
|
iResult = 1;
|
|
|
|
break;
|
|
|
|
case Cervisia::LocallyRemoved:
|
|
|
|
iResult = 2;
|
|
|
|
break;
|
|
|
|
case Cervisia::LocallyModified:
|
|
|
|
iResult = 3;
|
|
|
|
break;
|
|
|
|
case Cervisia::Updated:
|
|
|
|
case Cervisia::NeedsUpdate:
|
|
|
|
case Cervisia::Patched:
|
|
|
|
case Cervisia::Removed:
|
|
|
|
case Cervisia::NeedsPatch:
|
|
|
|
case Cervisia::NeedsMerge:
|
|
|
|
iResult = 4;
|
|
|
|
break;
|
|
|
|
case Cervisia::NotInCVS:
|
|
|
|
iResult = 5;
|
|
|
|
break;
|
|
|
|
case Cervisia::UpToDate:
|
|
|
|
case Cervisia::Unknown:
|
|
|
|
iResult = 6;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return iResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int UpdateFileItem::compare(TQListViewItem* i,
|
|
|
|
int column,
|
|
|
|
bool bAscending) const
|
|
|
|
{
|
|
|
|
// UpdateDirItems are always lesser than UpdateFileItems
|
|
|
|
if (isDirItem(i))
|
|
|
|
return bAscending ? 1 : -1;
|
|
|
|
|
|
|
|
const UpdateFileItem* item = static_cast<UpdateFileItem*>(i);
|
|
|
|
|
|
|
|
int iResult(0);
|
|
|
|
switch (column)
|
|
|
|
{
|
|
|
|
case Name:
|
|
|
|
iResult = entry().m_name.localeAwareCompare(item->entry().m_name);
|
|
|
|
break;
|
|
|
|
case MimeType:
|
|
|
|
iResult = KMimeType::findByPath(entry().m_name)->comment().localeAwareCompare(KMimeType::findByPath(item->entry().m_name)->comment());
|
|
|
|
break;
|
|
|
|
case Status:
|
|
|
|
if ((iResult = ::compare(statusClass(), item->statusClass())) == 0)
|
|
|
|
iResult = entry().m_name.localeAwareCompare(item->entry().m_name);
|
|
|
|
break;
|
|
|
|
case Revision:
|
|
|
|
iResult = ::compareRevisions(entry().m_revision, item->entry().m_revision);
|
|
|
|
break;
|
|
|
|
case TagOrDate:
|
|
|
|
iResult = entry().m_tag.localeAwareCompare(item->entry().m_tag);
|
|
|
|
break;
|
|
|
|
case Timestamp:
|
|
|
|
iResult = ::compare(entry().m_dateTime, item->entry().m_dateTime);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return iResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQString UpdateFileItem::text(int column) const
|
|
|
|
{
|
|
|
|
TQString result;
|
|
|
|
switch (column)
|
|
|
|
{
|
|
|
|
case Name:
|
|
|
|
result = entry().m_name;
|
|
|
|
break;
|
|
|
|
case MimeType:
|
|
|
|
result = KMimeType::findByPath(entry().m_name)->comment();
|
|
|
|
break;
|
|
|
|
case Status:
|
|
|
|
result = toString(entry().m_status);
|
|
|
|
break;
|
|
|
|
case Revision:
|
|
|
|
result = entry().m_revision;
|
|
|
|
break;
|
|
|
|
case TagOrDate:
|
|
|
|
result = entry().m_tag;
|
|
|
|
break;
|
|
|
|
case Timestamp:
|
|
|
|
if (entry().m_dateTime.isValid())
|
|
|
|
result = TDEGlobal::locale()->formatDateTime(entry().m_dateTime);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UpdateFileItem::paintCell(TQPainter *p,
|
|
|
|
const TQColorGroup &cg,
|
|
|
|
int col,
|
|
|
|
int width,
|
|
|
|
int align)
|
|
|
|
{
|
|
|
|
const UpdateView* view(updateView());
|
|
|
|
|
|
|
|
TQColor color;
|
|
|
|
switch (m_entry.m_status)
|
|
|
|
{
|
|
|
|
case Cervisia::Conflict:
|
|
|
|
color = view->conflictColor();
|
|
|
|
break;
|
|
|
|
case Cervisia::LocallyAdded:
|
|
|
|
case Cervisia::LocallyModified:
|
|
|
|
case Cervisia::LocallyRemoved:
|
|
|
|
color = view->localChangeColor();
|
|
|
|
break;
|
|
|
|
case Cervisia::NeedsMerge:
|
|
|
|
case Cervisia::NeedsPatch:
|
|
|
|
case Cervisia::NeedsUpdate:
|
|
|
|
case Cervisia::Patched:
|
|
|
|
case Cervisia::Removed:
|
|
|
|
case Cervisia::Updated:
|
|
|
|
color = view->remoteChangeColor();
|
|
|
|
break;
|
|
|
|
case Cervisia::NotInCVS:
|
|
|
|
color = view->notInCvsColor();
|
|
|
|
break;
|
|
|
|
case Cervisia::Unknown:
|
|
|
|
case Cervisia::UpToDate:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
const TQFont oldFont(p->font());
|
|
|
|
TQColorGroup mycg(cg);
|
|
|
|
if (color.isValid() && color != TDEGlobalSettings::textColor())
|
|
|
|
{
|
|
|
|
TQFont myFont(oldFont);
|
|
|
|
myFont.setBold(true);
|
|
|
|
p->setFont(myFont);
|
|
|
|
mycg.setColor(TQColorGroup::Text, color);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQListViewItem::paintCell(p, mycg, col, width, align);
|
|
|
|
|
|
|
|
if (color.isValid())
|
|
|
|
{
|
|
|
|
p->setFont(oldFont);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Finds or creates the UpdateDirItem with path \a dirPath. If \a dirPath
|
|
|
|
* is "." \a rootItem is returned.
|
|
|
|
*/
|
|
|
|
UpdateDirItem* findOrCreateDirItem(const TQString& dirPath,
|
|
|
|
UpdateDirItem* rootItem)
|
|
|
|
{
|
|
|
|
assert(!dirPath.isEmpty());
|
|
|
|
assert(rootItem);
|
|
|
|
|
|
|
|
UpdateDirItem* dirItem(rootItem);
|
|
|
|
|
|
|
|
if (dirPath != TQChar('.'))
|
|
|
|
{
|
|
|
|
const TQStringList& dirNames(TQStringList::split('/', dirPath));
|
|
|
|
const TQStringList::const_iterator itDirNameEnd(dirNames.end());
|
|
|
|
for (TQStringList::const_iterator itDirName(dirNames.begin());
|
|
|
|
itDirName != itDirNameEnd; ++itDirName)
|
|
|
|
{
|
|
|
|
const TQString& dirName(*itDirName);
|
|
|
|
|
|
|
|
UpdateItem* item = dirItem->findItem(dirName);
|
|
|
|
if (isFileItem(item))
|
|
|
|
{
|
|
|
|
// this happens if you
|
|
|
|
// - add a directory outside of Cervisia
|
|
|
|
// - update status (a file item is created for the directory)
|
|
|
|
// - add new directory in Cervisia
|
|
|
|
// - update status
|
|
|
|
kdDebug(8050) << "findOrCreateDirItem(): file changed to dir " << dirName << endl;
|
|
|
|
|
|
|
|
// just create a new dir item, createDirItem() will delete the
|
|
|
|
// file item and update the m_itemsByName map
|
|
|
|
item = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!item)
|
|
|
|
{
|
|
|
|
kdDebug(8050) << "findOrCreateDirItem(): create dir item " << dirName << endl;
|
|
|
|
Entry entry;
|
|
|
|
entry.m_name = dirName;
|
|
|
|
entry.m_type = Entry::Dir;
|
|
|
|
item = dirItem->createDirItem(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(isDirItem(item));
|
|
|
|
|
|
|
|
dirItem = static_cast<UpdateDirItem*>(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return dirItem;
|
|
|
|
}
|