📄 kfileinfocontents.cpp
字号:
/* This file is part of the KDE libraries Copyright (C) 1998 Stephan Kulow <coolo@kde.org> 1998 Daniel Grana <grana@ie.iwi.unibe.ch> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/#include "kfileinfocontents.h"#include <qpixmap.h>#include <qsignal.h>#include <kapp.h>#include "config-kfile.h"#include <stdlib.h>#ifdef Unsorted // the "I hate X.h" modus#undef Unsorted#endifQPixmap *KFileInfoContents::folder_pixmap = 0;QPixmap *KFileInfoContents::locked_folder = 0; QPixmap *KFileInfoContents::file_pixmap = 0;QPixmap *KFileInfoContents::locked_file = 0; KFileInfoContents::KFileInfoContents( bool use, QDir::SortSpec sorting ){ sorted_max = 10000; sortedArray = new KFileInfo*[sorted_max]; sorted_length = 0; reversed = false; // defaults mySortMode = Increasing; mySorting = sorting; keepDirsFirst = true; useSingleClick = use; nameList = 0; // don't use IconLoader to always get the same icon, // it looks very strange, if the icons differ from application // to application. if (!folder_pixmap) folder_pixmap = new QPixmap(KApplication::kde_icondir() + "/mini/folder.xpm"); if (!locked_folder) locked_folder = new QPixmap(KApplication::kde_icondir() + "/mini/lockedfolder.xpm"); if (!file_pixmap) file_pixmap = new QPixmap(KApplication::kde_icondir() + "/mini/unknown.xpm"); if (!locked_file) locked_file = new QPixmap(KApplication::kde_icondir() + "/mini/locked.xpm"); sig = new KFileInfoContentsSignaler(); filesNumber = 0; dirsNumber = 0;}KFileInfoContents::~KFileInfoContents(){ delete [] sortedArray; delete nameList; delete sig;}bool KFileInfoContents::addItem(const KFileInfo *i) { if (!acceptsFiles() && i->isFile()) return false; if (!acceptsDirs() && i->isDir()) return false; if (i->isDir()) dirsNumber++; else filesNumber++; return addItemInternal(i);}void KFileInfoContents::addItemList(const KFileInfoList *list){ setAutoUpdate(false); bool repaint_needed = false; KFileInfoListIterator it(*list); for (; it.current(); ++it) { debugC("insert %s", it.current()->fileName()); repaint_needed |= addItem(it.current()); } setAutoUpdate(true); if (repaint_needed) repaint(true);}void KFileInfoContents::setSorting(QDir::SortSpec new_sort){ QDir::SortSpec old_sort = static_cast<QDir::SortSpec>(sorting() & QDir::SortByMask); QDir::SortSpec sortflags = static_cast<QDir::SortSpec>(sorting() & (~QDir::SortByMask)); if (mySortMode == Switching) { if (new_sort == old_sort) reversed = !reversed; else reversed = false; } else reversed = (mySortMode == Decreasing); mySorting = static_cast<QDir::SortSpec>(new_sort | sortflags); if (count() <= 1) // nothing to do in this case return; if ( mySorting & QDir::DirsFirst ) keepDirsFirst = true; else keepDirsFirst = false; setAutoUpdate(false); clearView(); debugC("qsort %ld", time(0)); QuickSort(sortedArray, 0, sorted_length - 1); debugC("qsort %ld", time(0)); for (uint i = 0; i < sorted_length; i++) insertItem(sortedArray[i], -1); debugC("qsort %ld", time(0)); setAutoUpdate(true); repaint(true);}void KFileInfoContents::clear(){ sorted_length = 0; delete nameList; nameList = 0; clearView(); filesNumber = 0; dirsNumber = 0;}void KFileInfoContents::connectDirSelected( QObject *receiver, const char *member){ sig->connect(sig, SIGNAL(dirActivated(KFileInfo*)), receiver, member);}void KFileInfoContents::connectFileHighlighted( QObject *receiver, const char *member){ sig->connect(sig, SIGNAL(fileHighlighted(KFileInfo*)), receiver, member);}void KFileInfoContents::connectFileSelected( QObject *receiver, const char *member){ sig->connect(sig, SIGNAL(fileSelected(KFileInfo*)), receiver, member);}// this implementation is from the jdk demo Sortingvoid KFileInfoContents::QuickSort(KFileInfo* a[], int lo0, int hi0){ int lo = lo0; int hi = hi0; const KFileInfo *mid; if ( hi0 > lo0) { /* Arbitrarily establishing partition element as the midpoint of * the array. */ mid = a[ ( lo0 + hi0 ) / 2 ]; // loop through the array until indices cross while( lo <= hi ) { /* find the first element that is greater than or equal to * the partition element starting from the left Index. */ while( ( lo < hi0 ) && ( compareItems(a[lo], mid) < 0 ) ) ++lo; /* find an element that is smaller than or equal to * the partition element starting from the right Index. */ while( ( hi > lo0 ) && ( compareItems(a[hi], mid) > 0) ) --hi; // if the indexes have not crossed, swap if( lo <= hi ) { if (lo != hi) { const KFileInfo *T = a[lo]; a[lo] = a[hi]; a[hi] = const_cast<KFileInfo*>(T); } ++lo; --hi; } } /* If the right index has not reached the left side of array * must now sort the left partition. */ if( lo0 < hi ) QuickSort( a, lo0, hi ); /* If the left index has not reached the right side of array * must now sort the right partition. */ if( lo < hi0 ) QuickSort( a, lo, hi0 ); }}int KFileInfoContents::compareItems(const KFileInfo *fi1, const KFileInfo *fi2){ static int counter = 0; counter++; if (counter % 1000 == 0) debugC("compare %d", counter); bool bigger = true; if (keepDirsFirst && (fi1->isDir() != fi2->isDir())) bigger = !fi1->isDir(); else { QDir::SortSpec sort = static_cast<QDir::SortSpec>(mySorting & QDir::SortByMask); if (fi1->isDir()) sort = QDir::Name; switch (sort) { case QDir::Unsorted: bigger = true; // nothing break; case QDir::Size: bigger = (fi1->size() > fi2->size()); break; case QDir::Name: default: bigger = (stricmp(fi1->fileName(), fi2->fileName()) > 0); } } if (reversed) bigger = !bigger; // debugC("compare %s against %s: %s", fi1->fileName(), fi2->fileName(), bigger ? "bigger" : "smaller"); return (bigger ? 1 : -1);}int KFileInfoContents::findPosition(const KFileInfo *i, int left){ int pos = left; int right = sorted_length - 1; while (left < right-1) { pos = (left + right) / 2; if (compareItems(i, sortedArray[pos]) < 0) right = pos; else left = pos; } // if pos is the left side (rounded), it may be, that we haven't // compared to the right side and gave up too early if (pos == left && compareItems(i, sortedArray[right]) > 0) pos = right+1; else pos = right; if (pos == -1) pos = sorted_length; // debugC("findPosition %s %d", i->fileName(), pos); return pos;}bool KFileInfoContents::addItemInternal(const KFileInfo *i){ int pos = -1; if ( sorted_length > 1 && mySorting != QDir::Unsorted) { // insertation using log(n) pos = findPosition(i, 0); } else { if (sorted_length == 1 && compareItems(i, sortedArray[0]) < 0) pos = 0; else pos = sorted_length; } // if the namelist already exist, we can use inSort. In general // this is too slow if (nameList) nameList->inSort(i->fileName()); insertSortedItem(i, pos); return insertItem(i, pos);} const char *KFileInfoContents::text(uint index) const{ if (index < sorted_length) return sortedArray[index]->fileName(); else return "";}void KFileInfoContents::select( int index ){ select(sortedArray[index]);}void KFileInfoContents::select( KFileInfo *entry){ if ( entry->isDir() ) { debugC("selectDir %s",entry->fileName()); sig->activateDir(entry); } else { sig->activateFile(entry); }}void KFileInfoContents::highlight( KFileInfo *entry ){ sig->highlightFile(entry);}void KFileInfoContents::highlight( int index ){ highlight(sortedArray[index]);}void KFileInfoContents::repaint(bool f){ widget()->repaint(f);}void KFileInfoContents::setCurrentItem(const char *item, const KFileInfo *entry){ uint i; if (item != 0) { for (i = 0; i < sorted_length; i++) if (!strcmp(sortedArray[i]->fileName(),item)) { highlightItem(i); highlight(i); return; } } else for (i = 0; i < sorted_length; i++) if (sortedArray[i] == entry) { highlightItem(i); return; } warning("setCurrentItem: no match found.");}QString KFileInfoContents::findCompletion( const char *base, bool activateFound ){ if (!nameList) { uint i; nameList = new QStrIList(); // prepare an array for quicksort. This is much faster than // calling n times inSort const char **nameArray = new const char*[sorted_length]; // fill it for (i = 0; i < sorted_length; i++) nameArray[i] = sortedArray[i]->fileName(); qsort(nameArray, sorted_length, sizeof(const char*), (int (*)(const void *, const void *)) stricmp); // insert into list. Keeps deep copies for (i = 0; i < sorted_length; i++) nameList->append(nameArray[i]); delete [] nameArray; } if ( strlen(base) == 0 ) return 0; QString remainder = base; const char *name; for ( name = nameList->first(); name; name = nameList->next() ) { if ( strlen(name) < remainder.length()) continue; if (strncmp(name, remainder, remainder.length()) == 0) break; } if (name) { QString body = name; QString backup = name; // get the possible text completions and store the smallest // common denominator in QString body unsigned int counter = strlen(base); for ( const char *extra = nameList->next(); extra; extra = nameList->next() ) { counter = strlen(base); // case insensitive comparison needed because items are stored insensitively // so next instruction stop loop when first letter does no longer match if ( strnicmp( extra, remainder, 1 ) != 0 ) break; // this is case sensitive again! // goto next item if no completion possible with current item (->extra) if ( strncmp(extra, remainder, remainder.length()) != 0 ) continue; // get smallest common denominator for ( ; counter <= strlen(extra) ; counter++ ) { if (strncmp( extra, body, counter) != 0) break; } // truncate body, we have the smalles common denominator so far if ( counter == 1 ) body.truncate(counter); else body.truncate(counter-1); // this is needed because we want to highlight the first item in list // so we separately keep the "smallest" item separate, // we need the biggest in case the list is reversed if ( extra && ( reversed ? (strcmp( extra, backup ) > 0) : (strcmp( extra, backup ) < 0) ) ) backup = extra; } name = backup; debugC("completion base (%s) name (%s) body (%s)", base, name, body.data()); bool matchExactly = (name == body); if (matchExactly && (activateFound || useSingleClick)) { for (uint j = 0; j < sorted_length; j++) { KFileInfo *i = sortedArray[j]; if (i->fileName() == name) { if (sortedArray[j]->isDir()) body += "/"; highlightItem(j); if (activateFound) select(j); else highlight(j); break; } } } else setCurrentItem(name); // the first matching name return body; } else { debugC("no completion for %s", base); return 0; } }void KFileInfoContents::insertSortedItem(const KFileInfo *item, uint pos){ // debug("insert %s %d", item->fileName(), pos); if (sorted_length == sorted_max) { sorted_max *= 2; KFileInfo **newArray = new KFileInfo*[sorted_max]; int found = 0; for (uint j = 0; j < sorted_length; j++) { if (j == pos) { found = 1; newArray[j] = const_cast<KFileInfo*>(item); } newArray[j+found] = sortedArray[j]; } if (!found) newArray[pos] = const_cast<KFileInfo*>(item); delete [] sortedArray; sortedArray = newArray; sorted_length++; return; } // faster repositioning (very fast :) memmove(sortedArray + pos+1, sortedArray + pos, (sorted_max - 1 - pos) * sizeof(KFileInfo*)); sortedArray[pos] = const_cast<KFileInfo*>(item); sorted_length++;}#include "kfileinfocontents.moc" // for the signaler
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -