|
|
|
/*
|
|
|
|
knarticlecollection.cpp
|
|
|
|
|
|
|
|
KNode, the KDE newsreader
|
|
|
|
Copyright (c) 1999-2001 the KNode authors.
|
|
|
|
See file AUTHORS for details
|
|
|
|
|
|
|
|
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.
|
|
|
|
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, US
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
#include "knglobals.h"
|
|
|
|
#include "knarticlecollection.h"
|
|
|
|
#include "knarticle.h"
|
|
|
|
|
|
|
|
|
|
|
|
static const int sizeIncr=50;
|
|
|
|
|
|
|
|
KNArticleVector::KNArticleVector(KNArticleVector *master, SortingType sorting)
|
|
|
|
: m_aster(master), l_en(0), s_ize(0), l_ist(0), s_ortType(sorting)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KNArticleVector::~KNArticleVector()
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KNArticleVector::resize(int s)
|
|
|
|
{
|
|
|
|
KNArticle **bak=l_ist;
|
|
|
|
int nSize;
|
|
|
|
|
|
|
|
if(s==0)
|
|
|
|
nSize=s_ize+sizeIncr;
|
|
|
|
else
|
|
|
|
nSize=((s/sizeIncr)+1)*sizeIncr;
|
|
|
|
|
|
|
|
l_ist=(KNArticle**) realloc(l_ist, sizeof(KNArticle*)*nSize);
|
|
|
|
|
|
|
|
if(!l_ist) {
|
|
|
|
KMessageBox::error(knGlobals.topWidget, i18n("Memory allocation failed.\nYou should close this application now\nto avoid data loss."));
|
|
|
|
l_ist=bak;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
s_ize=nSize;
|
|
|
|
//kdDebug(5003) << "size : " << siz << "\n" << endl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KNArticleVector::append(KNArticle *a, bool autoSort)
|
|
|
|
{
|
|
|
|
if( (l_en+1 > s_ize) && !resize()) // array too small => try to realloc
|
|
|
|
return false; // allocation failed !!
|
|
|
|
|
|
|
|
l_ist[l_en++]=a;
|
|
|
|
|
|
|
|
if(autoSort) sort();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNArticleVector::remove(int pos, bool autoDel, bool autoCompact)
|
|
|
|
{
|
|
|
|
|
|
|
|
if(pos < 0 || pos > l_en-1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(autoDel)
|
|
|
|
delete l_ist[pos];
|
|
|
|
|
|
|
|
l_ist[pos]=0;
|
|
|
|
|
|
|
|
if(autoCompact)
|
|
|
|
compact();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNArticleVector::clear()
|
|
|
|
{
|
|
|
|
if(l_ist){
|
|
|
|
if(m_aster==0)
|
|
|
|
for(int i=0; i<l_en; i++) delete l_ist[i];
|
|
|
|
free(l_ist);
|
|
|
|
}
|
|
|
|
|
|
|
|
l_ist=0; l_en=0; s_ize=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNArticleVector::compact()
|
|
|
|
{
|
|
|
|
int newLen, nullStart=0, nullCnt=0, ptrStart=0, ptrCnt=0;
|
|
|
|
|
|
|
|
for(int idx=0; idx<l_en; idx++) {
|
|
|
|
if(l_ist[idx]==0) {
|
|
|
|
ptrStart=-1;
|
|
|
|
ptrCnt=-1;
|
|
|
|
nullStart=idx;
|
|
|
|
nullCnt=1;
|
|
|
|
for(int idx2=idx+1; idx2<l_en; idx2++) {
|
|
|
|
if(l_ist[idx2]==0) nullCnt++;
|
|
|
|
else {
|
|
|
|
ptrStart=idx2;
|
|
|
|
ptrCnt=1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(ptrStart!=-1) {
|
|
|
|
for(int idx2=ptrStart+1; idx2<l_en; idx2++) {
|
|
|
|
if(l_ist[idx2]!=0) ptrCnt++;
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
memmove(&(l_ist[nullStart]), &(l_ist[ptrStart]), ptrCnt*sizeof(KNArticle*));
|
|
|
|
for(int idx2=nullStart+ptrCnt; idx2<nullStart+ptrCnt+nullCnt; idx2++)
|
|
|
|
l_ist[idx2]=0;
|
|
|
|
idx=nullStart+ptrCnt-1;
|
|
|
|
}
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
newLen=0;
|
|
|
|
while(l_ist[newLen]!=0) newLen++;
|
|
|
|
l_en=newLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNArticleVector::syncWithMaster()
|
|
|
|
{
|
|
|
|
if(!m_aster) return;
|
|
|
|
|
|
|
|
if(resize(m_aster->l_en)) {
|
|
|
|
memcpy(l_ist, m_aster->l_ist, (m_aster->l_en) * sizeof(KNArticle*));
|
|
|
|
l_en=m_aster->l_en;
|
|
|
|
sort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNArticleVector::sort()
|
|
|
|
{
|
|
|
|
int (*cmp)(const void*,const void*) = 0;
|
|
|
|
|
|
|
|
switch(s_ortType) {
|
|
|
|
case STid:
|
|
|
|
cmp=compareById;
|
|
|
|
break;
|
|
|
|
case STmsgId:
|
|
|
|
cmp=compareByMsgId;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cmp=0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(cmp) {
|
|
|
|
//compact(); // remove null-pointers
|
|
|
|
qsort(l_ist, l_en, sizeof(KNArticle*), cmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int KNArticleVector::compareById(const void *p1, const void *p2)
|
|
|
|
{
|
|
|
|
KNArticle *a1, *a2;
|
|
|
|
int rc=0, id1, id2;
|
|
|
|
|
|
|
|
a1=*((KNArticle**)(p1));
|
|
|
|
a2=*((KNArticle**)(p2));
|
|
|
|
|
|
|
|
id1=a1->id(),
|
|
|
|
id2=a2->id();
|
|
|
|
|
|
|
|
if( id1 < id2 ) rc=-1;
|
|
|
|
else if( id1 > id2 ) rc=1;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int KNArticleVector::compareByMsgId(const void *p1, const void *p2)
|
|
|
|
{
|
|
|
|
KNArticle *a1, *a2;
|
|
|
|
TQCString mid1, mid2;
|
|
|
|
|
|
|
|
a1=*(KNArticle**)(p1);
|
|
|
|
a2=*(KNArticle**)(p2);
|
|
|
|
|
|
|
|
mid1=a1->messageID(true)->as7BitString(false);
|
|
|
|
mid2=a2->messageID(true)->as7BitString(false);
|
|
|
|
|
|
|
|
if(mid1.isNull()) mid1="";
|
|
|
|
if(mid2.isNull()) mid2="";
|
|
|
|
|
|
|
|
return strcmp( mid1.data(), mid2.data() );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KNArticle* KNArticleVector::bsearch(int id)
|
|
|
|
{
|
|
|
|
int idx=indexForId(id);
|
|
|
|
|
|
|
|
return ( idx>-1 ? l_ist[idx] : 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KNArticle* KNArticleVector::bsearch(const TQCString &id)
|
|
|
|
{
|
|
|
|
int idx=indexForMsgId(id);
|
|
|
|
|
|
|
|
return ( idx>-1 ? l_ist[idx] : 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int KNArticleVector::indexForId(int id)
|
|
|
|
{
|
|
|
|
if(s_ortType!=STid) return -1;
|
|
|
|
|
|
|
|
int start=0, end=l_en, mid=0, currentId=0;
|
|
|
|
bool found=false;
|
|
|
|
KNArticle *current=0;
|
|
|
|
|
|
|
|
while(start!=end && !found) {
|
|
|
|
mid=(start+end)/2;
|
|
|
|
current=l_ist[mid];
|
|
|
|
currentId=current->id();
|
|
|
|
|
|
|
|
if(currentId==id)
|
|
|
|
found=true;
|
|
|
|
else if(currentId < id)
|
|
|
|
start=mid+1;
|
|
|
|
else
|
|
|
|
end=mid;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(found)
|
|
|
|
return mid;
|
|
|
|
else {
|
|
|
|
#ifndef NDEBUG
|
|
|
|
tqDebug("knode: KNArticleVector::indexForId() : id=%d not found", id);
|
|
|
|
#endif
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int KNArticleVector::indexForMsgId(const TQCString &id)
|
|
|
|
{
|
|
|
|
if(s_ortType!=STmsgId) return -1;
|
|
|
|
|
|
|
|
int start=0, end=l_en, mid=0;
|
|
|
|
TQCString currentMid=0;
|
|
|
|
bool found=false;
|
|
|
|
KNArticle *current=0;
|
|
|
|
int cnt=0;
|
|
|
|
|
|
|
|
while(start!=end && !found) {
|
|
|
|
mid=(start+end)/2;
|
|
|
|
current=l_ist[mid];
|
|
|
|
currentMid=current->messageID(true)->as7BitString(false);
|
|
|
|
|
|
|
|
if(currentMid==id)
|
|
|
|
found=true;
|
|
|
|
else if( strcmp(currentMid.data(), id.data()) < 0 )
|
|
|
|
start=mid+1;
|
|
|
|
else
|
|
|
|
end=mid;
|
|
|
|
|
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(found) {
|
|
|
|
/*#ifndef NDEBUG
|
|
|
|
tqDebug("KNArticleVector::indexForMsgID() : msgID=%s found after %d compares", id.data(), cnt);
|
|
|
|
#endif*/
|
|
|
|
return mid;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/*#ifndef NDEBUG
|
|
|
|
tqDebug("knode: KNArticleVector::indexForMsgID() : msgID=%s not found", id.data());
|
|
|
|
#endif*/
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
KNArticleCollection::KNArticleCollection(KNCollection *p)
|
|
|
|
: KNCollection(p), l_astID(0), l_ockedArticles(0), n_otUnloadable(false)
|
|
|
|
{
|
|
|
|
a_rticles.setSortMode(KNArticleVector::STid);
|
|
|
|
m_idIndex.setSortMode(KNArticleVector::STmsgId);
|
|
|
|
m_idIndex.setMaster(&a_rticles);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
KNArticleCollection::~KNArticleCollection()
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool KNArticleCollection::resize(int s)
|
|
|
|
{
|
|
|
|
return a_rticles.resize(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool KNArticleCollection::append(KNArticle *a, bool autoSync)
|
|
|
|
{
|
|
|
|
if(a_rticles.append(a, false)) {
|
|
|
|
if(a->id()==-1)
|
|
|
|
a->setId(++l_astID);
|
|
|
|
if(autoSync)
|
|
|
|
syncSearchIndex();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void KNArticleCollection::clear()
|
|
|
|
{
|
|
|
|
a_rticles.clear();
|
|
|
|
m_idIndex.clear();
|
|
|
|
l_astID=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void KNArticleCollection::compact()
|
|
|
|
{
|
|
|
|
a_rticles.compact();
|
|
|
|
m_idIndex.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KNArticle* KNArticleCollection::byId(int id)
|
|
|
|
{
|
|
|
|
return a_rticles.bsearch(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KNArticle* KNArticleCollection::byMessageId(const TQCString &mid)
|
|
|
|
{
|
|
|
|
if(m_idIndex.isEmpty()) {
|
|
|
|
m_idIndex.syncWithMaster();
|
|
|
|
kdDebug(5003) << "KNArticleCollection::byMessageId() : created index" << endl;
|
|
|
|
}
|
|
|
|
return m_idIndex.bsearch(mid);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNArticleCollection::setLastID()
|
|
|
|
{
|
|
|
|
if(a_rticles.length()>0)
|
|
|
|
l_astID=a_rticles.at(a_rticles.length()-1)->id();
|
|
|
|
else
|
|
|
|
l_astID=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNArticleCollection::syncSearchIndex()
|
|
|
|
{
|
|
|
|
m_idIndex.syncWithMaster();
|
|
|
|
|
|
|
|
/*for(int i=0; i<m_idIndex.length(); i++) {
|
|
|
|
kdDebug(5003) << m_idIndex.at(i)->id() << " , " << m_idIndex.at(i)->messageID()->as7BitString(false) << endl;
|
|
|
|
} */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNArticleCollection::clearSearchIndex()
|
|
|
|
{
|
|
|
|
m_idIndex.clear();
|
|
|
|
}
|