00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "filegroupswidget.h"
00013
00014 #include <qfileinfo.h>
00015 #include <qdir.h>
00016 #include <qheader.h>
00017 #include <qtimer.h>
00018 #include <qvbox.h>
00019 #include <qregexp.h>
00020
00021 #include <kdebug.h>
00022 #include <kdialogbase.h>
00023 #include <kiconloader.h>
00024 #include <klocale.h>
00025 #include <kpopupmenu.h>
00026 #include <kaction.h>
00027 #include <kdeversion.h>
00028
00029 #include "kdevcore.h"
00030 #include "kdevproject.h"
00031 #include "kdevmainwindow.h"
00032 #include "kdevpartcontroller.h"
00033 #include "domutil.h"
00034
00035 #include "filegroupspart.h"
00036 #include "filegroupsconfigwidget.h"
00037
00038
00039
00040 static const char *translations[] = {
00041 I18N_NOOP("Sources"),
00042 I18N_NOOP("Translations"),
00043 I18N_NOOP("User Interface"),
00044 I18N_NOOP("Others")
00045 };
00046
00047 class FileComparator {
00048 public:
00049 virtual ~FileComparator(){
00050 };
00051 virtual bool matches(const QString& name) const = 0;
00052 };
00053
00054 class RegExpComparator : public FileComparator {
00055 public:
00056 RegExpComparator(const QString& pattern) : m_exp(pattern, true, true){
00057 }
00058 bool matches(const QString& name) const{
00059 return m_exp.exactMatch(name);
00060 }
00061 private:
00062 const QRegExp m_exp;
00063 };
00064
00065 class EndingComparator : public FileComparator {
00066 public:
00067 EndingComparator(const QString& pattern) : m_pattern ( pattern){
00068 }
00069 bool matches(const QString& name) const{
00070 return name.endsWith(m_pattern);
00071 }
00072 private:
00073 const QString m_pattern;
00074 };
00075
00076 class FileViewFolderItem : public QListViewItem
00077 {
00078 public:
00079 FileViewFolderItem(QListView *parent, const QString &name, const QString &pattern);
00080 bool matches(const QString &fileName);
00081
00082 private:
00083 QPtrList<FileComparator> m_patterns;
00084 };
00085
00086
00087 FileViewFolderItem::FileViewFolderItem(QListView *parent, const QString &name, const QString &pattern)
00088 : QListViewItem(parent, name)
00089 {
00090 setPixmap(0, SmallIcon("folder"));
00091 m_patterns.setAutoDelete(true);
00092 QStringList patternstring = QStringList::split(';', pattern);
00093 QStringList::ConstIterator theend = patternstring.end();
00094 for (QStringList::ConstIterator ci = patternstring.begin(); ci != theend; ++ci)
00095 {
00096 QString pattern = *ci;
00097 QString tail = pattern.right( pattern.length() - 1 );
00098
00099 if ( (tail).contains('*') || pattern.contains('?') || pattern.contains('[') || pattern.contains(']') )
00100 {
00101 m_patterns.append( new RegExpComparator( pattern ) );
00102 }
00103 else
00104 {
00105 if ( pattern.startsWith("*") )
00106 {
00107 m_patterns.append( new EndingComparator( tail ) );
00108 }
00109 else
00110 {
00111 m_patterns.append( new EndingComparator( pattern ) );
00112 }
00113 }
00114 }
00115 }
00116
00117
00118 bool FileViewFolderItem::matches(const QString &fileName)
00119 {
00120
00121 QString fName = QFileInfo(fileName).filePath();
00122
00123 QPtrList<FileComparator>::ConstIterator theend = m_patterns.end();
00124 for (QPtrList<FileComparator>::ConstIterator ci = m_patterns.begin(); ci != theend; ++ci)
00125 if ((*ci)->matches(fName))
00126 return true;
00127
00128 return false;
00129 }
00130
00131
00132 class FileGroupsFileItem : public QListViewItem
00133 {
00134 public:
00135 FileGroupsFileItem(QListViewItem *parent, const QString &fileName);
00136 QString fileName() const
00137 { return fullname; }
00138
00139 private:
00140 QString fullname;
00141 };
00142
00143
00144 FileGroupsFileItem::FileGroupsFileItem(QListViewItem *parent, const QString &fileName)
00145 : QListViewItem(parent), fullname(fileName)
00146 {
00147 setPixmap(0, SmallIcon("document"));
00148 QFileInfo fi(fileName);
00149 setText(0, fi.fileName());
00150 setText(1, "./" + fi.dirPath());
00151 }
00152
00153 FileGroupsWidget::FileGroupsWidget(FileGroupsPart *part)
00154 : KListView(0, "file view widget"),
00155 m_actionToggleShowNonProjectFiles( 0 ), m_actionToggleDisplayLocation( 0 )
00156 {
00157
00158
00159
00160
00161
00162 LocationID=-1;
00163
00164 setFocusPolicy(ClickFocus);
00165 setRootIsDecorated(true);
00166 setResizeMode(QListView::LastColumn);
00167 setSorting(-1);
00168 addColumn(i18n("Name"));
00169
00170
00171 connect( this, SIGNAL(executed(QListViewItem*)),
00172 this, SLOT(slotItemExecuted(QListViewItem*)) );
00173 connect( this, SIGNAL(returnPressed(QListViewItem*)),
00174 this, SLOT(slotItemExecuted(QListViewItem*)) );
00175 connect( this, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)),
00176 this, SLOT(slotContextMenu(KListView*, QListViewItem*, const QPoint&)) );
00177
00178 m_actionToggleShowNonProjectFiles = new KToggleAction( i18n("Show Non Project Files"), KShortcut(),
00179 this, SLOT(slotToggleShowNonProjectFiles()), this, "actiontoggleshowshownonprojectfiles" );
00180 #if KDE_IS_VERSION(3,2,90)
00181 m_actionToggleShowNonProjectFiles->setCheckedState(i18n("Hide Non Project Files"));
00182 #endif
00183 m_actionToggleShowNonProjectFiles->setWhatsThis(i18n("<b>Show non project files</b><p>Shows files that do not belong to a project in a file tree."));
00184
00185 m_actionToggleDisplayLocation = new KToggleAction( i18n("Display Location Column"), KShortcut(),
00186 this, SLOT(slotToggleDisplayLocation()), this, "actiontoggleshowlocation" );
00187 m_actionToggleDisplayLocation->setWhatsThis(i18n("<b>Display the Location Column</b><p>Displays a column with the location of the files."));
00188
00189 m_part = part;
00190 (void) translations;
00191
00192 QDomDocument &dom = *m_part->projectDom();
00193 m_actionToggleShowNonProjectFiles->setChecked( !DomUtil::readBoolEntry(dom, "/kdevfileview/groups/hidenonprojectfiles") );
00194 m_actionToggleDisplayLocation->setChecked( !DomUtil::readBoolEntry(dom, "/kdevfileview/groups/hidenonlocation") );
00195 }
00196
00197
00198 FileGroupsWidget::~FileGroupsWidget()
00199 {
00200 QDomDocument &dom = *m_part->projectDom();
00201 DomUtil::writeBoolEntry( dom, "/kdevfileview/groups/hidenonprojectfiles", !m_actionToggleShowNonProjectFiles->isChecked() );
00202 DomUtil::writeBoolEntry( dom, "/kdevfileview/groups/hidenonlocation", !m_actionToggleDisplayLocation->isChecked() );
00203 }
00204
00205
00206 void FileGroupsWidget::slotItemExecuted(QListViewItem *item)
00207 {
00208 if (!item)
00209 return;
00210
00211
00212 if (item->childCount() > 0)
00213 setOpen(item, !isOpen(item));
00214
00215
00216 if (!item->parent())
00217 return;
00218
00219 FileGroupsFileItem *fgfitem = static_cast<FileGroupsFileItem*>(item);
00220 m_part->partController()->editDocument(KURL::fromPathOrURL( m_part->project()->projectDirectory() + "/" + fgfitem->fileName() ));
00221 }
00222
00223
00224 void FileGroupsWidget::slotContextMenu(KListView *, QListViewItem *item, const QPoint &p)
00225 {
00226 KPopupMenu popup(i18n("File Groups"), this);
00228 int customizeId = popup.insertItem(i18n("Customize..."));
00229 popup.setWhatsThis(customizeId, i18n("<b>Customize</b><p>Opens <b>Customize File Groups</b> dialog where the groups can be managed."));
00230 if (item) {
00231 if (item->parent()) {
00232
00233 FileGroupsFileItem *fvfitem = static_cast<FileGroupsFileItem*>(item);
00234 QString pathName = m_part->project()->projectDirectory() + QDir::separator() + fvfitem->fileName();
00235 FileContext context( pathName, false);
00236 m_part->core()->fillContextMenu(&popup, &context);
00237 }
00238 else{
00239 QStringList file_list;
00240 QListViewItem* i = item->firstChild();
00241 while(i){
00242 FileGroupsFileItem *fvgitem = static_cast<FileGroupsFileItem*>(i);
00243 file_list << fvgitem->fileName();
00244 i = i->nextSibling();
00245 }
00246 FileContext context(file_list);
00247 m_part->core()->fillContextMenu(&popup, &context);
00248 }
00249 }
00250 m_actionToggleShowNonProjectFiles->plug( &popup );
00251 m_actionToggleDisplayLocation->plug( &popup );
00252
00253 int res = popup.exec(p);
00254 if (res == customizeId) {
00255 KDialogBase dlg(KDialogBase::TreeList, i18n("Customize File Groups"),
00256 KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, this,
00257 "customization dialog");
00258 QVBox *vbox = dlg.addVBoxPage(i18n("File Groups"));
00259 FileGroupsConfigWidget *w = new FileGroupsConfigWidget(m_part, vbox, "file groups config widget");
00260 connect(&dlg, SIGNAL(okClicked()), w, SLOT(accept()));
00261 dlg.exec();
00262 }
00263 }
00264
00265 QStringList FileGroupsWidget::allFilesRecursively( QString const & dir )
00266 {
00267 QStringList filelist;
00268 QString reldir = dir.mid( m_part->project()->projectDirectory().length() +1 );
00269
00270
00271 QStringList subdirs = QDir( dir ).entryList( QDir::Dirs );
00272 QValueListIterator<QString> it = subdirs.begin();
00273 while ( it != subdirs.end() )
00274 {
00275 if ( *it != "." && *it != ".." )
00276 {
00277 filelist += allFilesRecursively( dir + "/"+ *it );
00278 }
00279 ++it;
00280 }
00281
00282
00283 QStringList dirlist = QDir( dir ).entryList( QDir::Files );
00284 QValueListIterator<QString> itt = dirlist.begin();
00285 while ( itt != dirlist.end() )
00286 {
00287 if ( reldir.isEmpty() )
00288 {
00289 filelist << *itt;
00290 }
00291 else
00292 {
00293 filelist << reldir + "/" + *itt;
00294 }
00295 ++itt;
00296 }
00297
00298 return filelist;
00299 }
00300
00301 void FileGroupsWidget::refresh()
00302 {
00303 while (firstChild())
00304 delete firstChild();
00305
00306 if (m_actionToggleDisplayLocation->isChecked()) {
00307
00308 LocationID=addColumn(i18n("Location"));
00309 }
00310 else {
00311
00312
00313 if (LocationID!=-1)
00314 removeColumn(LocationID);
00315 }
00316 QDomDocument &dom = *m_part->projectDom();
00317 DomUtil::PairList list =
00318 DomUtil::readPairListEntry(dom, "/kdevfileview/groups", "group", "name", "pattern");
00319
00320 FileViewFolderItem *lastGroup = 0;
00321
00322 DomUtil::PairList::ConstIterator git;
00323 for (git = list.begin(); git != list.end(); ++git) {
00324 FileViewFolderItem *newItem = new FileViewFolderItem(this, (*git).first, (*git).second);
00325 if (lastGroup)
00326 newItem->moveItem(lastGroup);
00327 lastGroup = newItem;
00328 }
00329
00330 QStringList allFiles;
00331 if (m_actionToggleShowNonProjectFiles->isChecked()) {
00332
00333 allFiles = allFilesRecursively( m_part->project()->projectDirectory() );
00334 }
00335 else {
00336
00337 allFiles = m_part->project()->allFiles();
00338 }
00339 QStringList::ConstIterator fit;
00340 for (fit = allFiles.begin(); fit != allFiles.end(); ++fit) {
00341 QListViewItem *item = firstChild();
00342 while (item) {
00343 FileViewFolderItem *fvgitem = static_cast<FileViewFolderItem*>(item);
00344 if (fvgitem->matches(*fit)) {
00345 (void) new FileGroupsFileItem(fvgitem, *fit);
00346 break;
00347 }
00348 item = item->nextSibling();
00349 }
00350 }
00351
00352 QListViewItem *item = firstChild();
00353 while (item) {
00354 item->sortChildItems(0, true);
00355 item = item->nextSibling();
00356 }
00357 }
00358
00359
00360 void FileGroupsWidget::addFile(const QString &fileName)
00361 {
00362 kdDebug(9017) << "FileView add " << fileName << endl;
00363
00364 QListViewItem *item = firstChild();
00365 while (item) {
00366 FileViewFolderItem *fvgitem = static_cast<FileViewFolderItem*>(item);
00367 if (fvgitem->matches(fileName))
00368 {
00369 QString f = fileName;
00370 if (fileName.contains(m_part->project()->projectDirectory()))
00371 f = fileName.mid(m_part->project()->projectDirectory().length()+1);
00372 (void) new FileGroupsFileItem(fvgitem, f);
00373 fvgitem->sortChildItems(0, true);
00374 break;
00375 }
00376 item = item->nextSibling();
00377 }
00378 }
00379
00380 void FileGroupsWidget::addFiles ( const QStringList& fileList )
00381 {
00382 QStringList::ConstIterator it;
00383
00384 for ( it = fileList.begin(); it != fileList.end(); ++it )
00385 {
00386 this->addFile ( *it );
00387 }
00388 }
00389
00390 void FileGroupsWidget::removeFile(const QString &fileName)
00391 {
00392 kdDebug(9017) << "FileView remove " << fileName << endl;
00393
00394 QListViewItem *item = firstChild();
00395 while (item)
00396 {
00397 FileViewFolderItem *fvgitem = static_cast<FileViewFolderItem*>(item);
00398 QListViewItem *childItem = fvgitem->firstChild();
00399 while (childItem)
00400 {
00401 FileGroupsFileItem *fgfitem = static_cast<FileGroupsFileItem*>(childItem);
00402 kdDebug ( 9017 ) << "fvfitem->fileName() is " << fgfitem->fileName() << endl;
00403 if (fgfitem->fileName() == fileName )
00404 {
00405 kdDebug ( 9017 ) << "Deleting: " << fgfitem->fileName() << endl;
00406
00407 delete fgfitem;
00408 return;
00409 }
00410 childItem = childItem->nextSibling();
00411 }
00412 item = item->nextSibling();
00413 }
00414 }
00415
00416 void FileGroupsWidget::removeFiles ( const QStringList& fileList )
00417 {
00418 QStringList::ConstIterator it;
00419
00420 for ( it = fileList.begin(); it != fileList.end(); ++it )
00421 {
00422 removeFile ( *it );
00423 }
00424 }
00425
00426 void FileGroupsWidget::slotToggleShowNonProjectFiles()
00427 {
00428 refresh();
00429 }
00430
00431 void FileGroupsWidget::slotToggleDisplayLocation()
00432 {
00433 refresh();
00434 }
00435
00436
00437 #include "filegroupswidget.moc"
00438