PDA

View Full Version : QAbstractItemModel Subclass duplicate entries



pvdk
27th June 2008, 16:00
Hello people,

I've successfully subclassed QAbstractItemModel to fit my needs. It acts as a frontend for the ls command. Ls feeds output in the following form to my model:

./parentfolder:
subfolder1/
subfolder2/

./parentfolder/subfolder1:
dir/
dir2/
textfile.txt

./parentfolder/subfolder1/dir:

./parentfolder/subfolder1/dir2:

./parentfolder/subfolder2:
textfile1.txt
textfile2.txt
textfile3.txt


And displays it like in the attached image.
The only thing I can't get fixed is the multiple occurence of parents. I've been struggeling with it the whole day so I hope someone with a fresh mind can see what's wrong with my code:


void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent)
{
QList<TreeItem*> parents;
QList<int> indentations;
parents << parent;
indentations << 0;

for( int r=0; r<lines.count(); r++ ) {
QString lineData = lines[r].trimmed();

if (!lineData.isEmpty()) {
qDebug() << QString(lineData) << "\n";

// Line is a dir
if (lineData.endsWith(":")) {
// Get rid of the colon
lineData.chop(1);

// Check if the string is a dot from the beginning of the ls output
if (lineData == ".") {
// Get rid of the string
lineData.clear();
}

// Check if the line starts with a dot and get rid of it before we replace the backslashes
if (lineData.startsWith("./")) {
lineData.replace(QString("./"), QString("/"));
}
qDebug() << lineData;

QStringList list = lineData.split("/", QString::SkipEmptyParts);
qDebug() << list << "start appending parent/child shit \n ";

// Reset the parent FIXME: horrible method
parents << parents.first();
for(int p = 0; p < list.size(); p++) {

QList<QVariant> column;
column << list[p];

parents.last()->appendChild(new TreeItem(column, parents.last()));
parents << parents.last()->child(parents.last()->childCount()-1);
}

} else if (lineData.endsWith("/")) {
qDebug() << "is a directory conjo!!!" << lineData << "\n";
} else {
QList<QVariant> column;
column << lineData;

parents.last()->appendChild(new TreeItem(column, parents.last()));
qDebug() << "appended file: " << lineData << "\n";
}
}
}
}

So, in short: I need my QAbstractItemModel to treat items with the same name under the same parent as one item, and not as duplicates.

Thanks in advance,
pvdk

caduel
27th June 2008, 19:55
You have to remember the last parent chain.
If the next directory chain (your list in line 31) shares a common prefix with the last line you parsed, then remove only all those parents that do not match.

Example:


path list parents
/a/b/c/d -> [a,b,c,d] [p1, p2, p3, p4]
/a/b/e -> [a,b,e]

Then you reduce parents to [p1, p2] and insert your new item under that chain.
You must not create a new parent chain all over for each line you parse.


Note: this algorithm assumes that the lines are sorted properly, which they should be in your case.

HTH

PS: I did not quite see where you "clear" your parent list.
Line 35 is beyond my understanding, too. Looks strange to me.
(I did not study your code in detail, sorry.)

pvdk
14th July 2008, 16:07
Hello caduel,

First of all hanks for your quick reply. I reply now because I was on vacation. Your suggestion put me on the right track but I still can't get it to work right. Could you explain your suggestion with a little more detail, maybe with code examples? As for your PS: that line is in there because it gave me the idea it worked a bit, but it should be replaced/removed with something better.

Thanks alot!

Regards,
pvdk

caduel
14th July 2008, 17:54
basically, replace

// Reset the parent FIXME: horrible method
parents << parents.first();
for(int p = 0; p < list.size(); p++) {
QList<QVariant> column;
column << list[p];

parents.last()->appendChild(new TreeItem(column, parents.last()));
parents << parents.last()->child(parents.last()->childCount()-1);
}


by



// store last parent directory chain in a QStringList
// add at top of your function
QStringList lLastDirChain;

...

// and then replace the code above by
QStringList common = common_prefix(lLastDirChain, list);
// remove the un-common dirs from parents
while (parents.count()>common.count()) parents.pop_back();

// now parents should be the common ones:
for(int p=common.count(); p<list.size(); ++p) {
QList<QVariant> column;
column << list[p];
TreeItem * const item = new TreeItem(column, parents.last());
parents.last()->appendChild(item);
parents << item;
}

lLastDirChain = list;


untested, probably does not compile. hopefully still helpful.

PS: use ++p instead of p++ (at least when free standing); faster for iterators.

PPS: common_prefix could be implemented as

static QStringList common_prefix(const QStringList &lhs, const QStringList &rhs)
{
QStringList res;
int minlen = qMin(lhs.count(), rhs.count());
for (int i=0; i<minlen; ++i)
{
if (lhs[i]==rhs[i])
res << lhs[i];
else break;
}
return res;
}