katefiletype.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2001-2003 Christoph Cullmann <cullmann@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License version 2 as published by the Free Software Foundation. 00007 00008 This library is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 Library General Public License for more details. 00012 00013 You should have received a copy of the GNU Library General Public License 00014 along with this library; see the file COPYING.LIB. If not, write to 00015 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00016 Boston, MA 02110-1301, USA. 00017 */ 00018 00019 //BEGIN Includes 00020 #include "katefiletype.h" 00021 #include "katefiletype.moc" 00022 00023 #include "katedocument.h" 00024 #include "kateconfig.h" 00025 #include "kateview.h" 00026 #include "katefactory.h" 00027 00028 #include <kconfig.h> 00029 #include <kmimemagic.h> 00030 #include <kmimetype.h> 00031 #include <kmimetypechooser.h> 00032 #include <kdebug.h> 00033 #include <kiconloader.h> 00034 #include <knuminput.h> 00035 #include <klocale.h> 00036 #include <kpopupmenu.h> 00037 00038 #include <qregexp.h> 00039 #include <qcheckbox.h> 00040 #include <qcombobox.h> 00041 #include <qgroupbox.h> 00042 #include <qhbox.h> 00043 #include <qheader.h> 00044 #include <qhgroupbox.h> 00045 #include <qlabel.h> 00046 #include <qlayout.h> 00047 #include <qlineedit.h> 00048 #include <qpushbutton.h> 00049 #include <qtoolbutton.h> 00050 #include <qvbox.h> 00051 #include <qvgroupbox.h> 00052 #include <qwhatsthis.h> 00053 #include <qwidgetstack.h> 00054 00055 #define KATE_FT_HOWMANY 1024 00056 //END Includes 00057 00058 //BEGIN KateFileTypeManager 00059 KateFileTypeManager::KateFileTypeManager () 00060 { 00061 m_types.setAutoDelete (true); 00062 00063 update (); 00064 } 00065 00066 KateFileTypeManager::~KateFileTypeManager () 00067 { 00068 } 00069 00070 // 00071 // read the types from config file and update the internal list 00072 // 00073 void KateFileTypeManager::update () 00074 { 00075 KConfig config ("katefiletyperc", false, false); 00076 00077 QStringList g (config.groupList()); 00078 g.sort (); 00079 00080 m_types.clear (); 00081 for (uint z=0; z < g.count(); z++) 00082 { 00083 config.setGroup (g[z]); 00084 00085 KateFileType *type = new KateFileType (); 00086 00087 type->number = z; 00088 type->name = g[z]; 00089 type->section = config.readEntry ("Section"); 00090 type->wildcards = config.readListEntry ("Wildcards", ';'); 00091 type->mimetypes = config.readListEntry ("Mimetypes", ';'); 00092 type->priority = config.readNumEntry ("Priority"); 00093 type->varLine = config.readEntry ("Variables"); 00094 00095 m_types.append (type); 00096 } 00097 } 00098 00099 // 00100 // save the given list to config file + update 00101 // 00102 void KateFileTypeManager::save (QPtrList<KateFileType> *v) 00103 { 00104 KConfig config ("katefiletyperc", false, false); 00105 00106 QStringList newg; 00107 for (uint z=0; z < v->count(); z++) 00108 { 00109 config.setGroup (v->at(z)->name); 00110 00111 config.writeEntry ("Section", v->at(z)->section); 00112 config.writeEntry ("Wildcards", v->at(z)->wildcards, ';'); 00113 config.writeEntry ("Mimetypes", v->at(z)->mimetypes, ';'); 00114 config.writeEntry ("Priority", v->at(z)->priority); 00115 00116 QString varLine = v->at(z)->varLine; 00117 if (QRegExp("kate:(.*)").search(varLine) < 0) 00118 varLine.prepend ("kate: "); 00119 00120 config.writeEntry ("Variables", varLine); 00121 00122 newg << v->at(z)->name; 00123 } 00124 00125 QStringList g (config.groupList()); 00126 00127 for (uint z=0; z < g.count(); z++) 00128 { 00129 if (newg.findIndex (g[z]) == -1) 00130 config.deleteGroup (g[z]); 00131 } 00132 00133 config.sync (); 00134 00135 update (); 00136 } 00137 00138 int KateFileTypeManager::fileType (KateDocument *doc) 00139 { 00140 kdDebug(13020)<<k_funcinfo<<endl; 00141 if (!doc) 00142 return -1; 00143 00144 if (m_types.isEmpty()) 00145 return -1; 00146 00147 QString fileName = doc->url().prettyURL(); 00148 int length = doc->url().prettyURL().length(); 00149 00150 int result; 00151 00152 // Try wildcards 00153 if ( ! fileName.isEmpty() ) 00154 { 00155 static QStringList commonSuffixes = QStringList::split (";", ".orig;.new;~;.bak;.BAK"); 00156 00157 if ((result = wildcardsFind(fileName)) != -1) 00158 return result; 00159 00160 QString backupSuffix = KateDocumentConfig::global()->backupSuffix(); 00161 if (fileName.endsWith(backupSuffix)) { 00162 if ((result = wildcardsFind(fileName.left(length - backupSuffix.length()))) != -1) 00163 return result; 00164 } 00165 00166 for (QStringList::Iterator it = commonSuffixes.begin(); it != commonSuffixes.end(); ++it) { 00167 if (*it != backupSuffix && fileName.endsWith(*it)) { 00168 if ((result = wildcardsFind(fileName.left(length - (*it).length()))) != -1) 00169 return result; 00170 } 00171 } 00172 } 00173 00174 // Even try the document name, if the URL is empty 00175 // This is usefull if the document name is set for example by a plugin which 00176 // created the document 00177 else if ( (result = wildcardsFind(doc->docName())) != -1) 00178 { 00179 kdDebug(13020)<<"KateFiletype::filetype(): got type "<<result<<" using docName '"<<doc->docName()<<"'"<<endl; 00180 return result; 00181 } 00182 00183 // Try content-based mimetype 00184 KMimeType::Ptr mt = doc->mimeTypeForContent(); 00185 00186 QPtrList<KateFileType> types; 00187 00188 for (uint z=0; z < m_types.count(); z++) 00189 { 00190 if (m_types.at(z)->mimetypes.findIndex (mt->name()) > -1) 00191 types.append (m_types.at(z)); 00192 } 00193 00194 if ( !types.isEmpty() ) 00195 { 00196 int pri = -1; 00197 int hl = -1; 00198 00199 for (KateFileType *type = types.first(); type != 0L; type = types.next()) 00200 { 00201 if (type->priority > pri) 00202 { 00203 pri = type->priority; 00204 hl = type->number; 00205 } 00206 } 00207 00208 return hl; 00209 } 00210 00211 00212 return -1; 00213 } 00214 00215 int KateFileTypeManager::wildcardsFind (const QString &fileName) 00216 { 00217 QPtrList<KateFileType> types; 00218 00219 for (uint z=0; z < m_types.count(); z++) 00220 { 00221 for( QStringList::Iterator it = m_types.at(z)->wildcards.begin(); it != m_types.at(z)->wildcards.end(); ++it ) 00222 { 00223 // anders: we need to be sure to match the end of string, as eg a css file 00224 // would otherwise end up with the c hl 00225 QRegExp re(*it, true, true); 00226 if ( ( re.search( fileName ) > -1 ) && ( re.matchedLength() == (int)fileName.length() ) ) 00227 types.append (m_types.at(z)); 00228 } 00229 } 00230 00231 if ( !types.isEmpty() ) 00232 { 00233 int pri = -1; 00234 int hl = -1; 00235 00236 for (KateFileType *type = types.first(); type != 0L; type = types.next()) 00237 { 00238 if (type->priority > pri) 00239 { 00240 pri = type->priority; 00241 hl = type->number; 00242 } 00243 } 00244 00245 return hl; 00246 } 00247 00248 return -1; 00249 } 00250 00251 const KateFileType *KateFileTypeManager::fileType (uint number) 00252 { 00253 if (number < m_types.count()) 00254 return m_types.at(number); 00255 00256 return 0; 00257 } 00258 //END KateFileTypeManager 00259 00260 //BEGIN KateFileTypeConfigTab 00261 KateFileTypeConfigTab::KateFileTypeConfigTab( QWidget *parent ) 00262 : KateConfigPage( parent ) 00263 { 00264 m_types.setAutoDelete (true); 00265 m_lastType = 0; 00266 00267 QVBoxLayout *layout = new QVBoxLayout(this, 0, KDialog::spacingHint() ); 00268 00269 // hl chooser 00270 QHBox *hbHl = new QHBox( this ); 00271 layout->add (hbHl); 00272 hbHl->setSpacing( KDialog::spacingHint() ); 00273 QLabel *lHl = new QLabel( i18n("&Filetype:"), hbHl ); 00274 typeCombo = new QComboBox( false, hbHl ); 00275 lHl->setBuddy( typeCombo ); 00276 connect( typeCombo, SIGNAL(activated(int)), 00277 this, SLOT(typeChanged(int)) ); 00278 00279 QPushButton *btnnew = new QPushButton( i18n("&New"), hbHl ); 00280 connect( btnnew, SIGNAL(clicked()), this, SLOT(newType()) ); 00281 00282 btndel = new QPushButton( i18n("&Delete"), hbHl ); 00283 connect( btndel, SIGNAL(clicked()), this, SLOT(deleteType()) ); 00284 00285 gbProps = new QGroupBox( 2, Qt::Horizontal, i18n("Properties"), this ); 00286 layout->add (gbProps); 00287 00288 // file & mime types 00289 QLabel *lname = new QLabel( i18n("N&ame:"), gbProps ); 00290 name = new QLineEdit( gbProps ); 00291 lname->setBuddy( name ); 00292 00293 // file & mime types 00294 QLabel *lsec = new QLabel( i18n("&Section:"), gbProps ); 00295 section = new QLineEdit( gbProps ); 00296 lsec->setBuddy( section ); 00297 00298 // file & mime types 00299 QLabel *lvar = new QLabel( i18n("&Variables:"), gbProps ); 00300 varLine = new QLineEdit( gbProps ); 00301 lvar->setBuddy( varLine ); 00302 00303 // file & mime types 00304 QLabel *lFileExts = new QLabel( i18n("File e&xtensions:"), gbProps ); 00305 wildcards = new QLineEdit( gbProps ); 00306 lFileExts->setBuddy( wildcards ); 00307 00308 QLabel *lMimeTypes = new QLabel( i18n("MIME &types:"), gbProps); 00309 QHBox *hbMT = new QHBox (gbProps); 00310 mimetypes = new QLineEdit( hbMT ); 00311 lMimeTypes->setBuddy( mimetypes ); 00312 00313 QToolButton *btnMTW = new QToolButton(hbMT); 00314 btnMTW->setIconSet(QIconSet(SmallIcon("wizard"))); 00315 connect(btnMTW, SIGNAL(clicked()), this, SLOT(showMTDlg())); 00316 00317 QLabel *lprio = new QLabel( i18n("Prio&rity:"), gbProps); 00318 priority = new KIntNumInput( gbProps ); 00319 lprio->setBuddy( priority ); 00320 00321 layout->addStretch(); 00322 00323 reload(); 00324 00325 connect( name, SIGNAL( textChanged ( const QString & ) ), this, SLOT( slotChanged() ) ); 00326 connect( section, SIGNAL( textChanged ( const QString & ) ), this, SLOT( slotChanged() ) ); 00327 connect( varLine, SIGNAL( textChanged ( const QString & ) ), this, SLOT( slotChanged() ) ); 00328 connect( wildcards, SIGNAL( textChanged ( const QString & ) ), this, SLOT( slotChanged() ) ); 00329 connect( mimetypes, SIGNAL( textChanged ( const QString & ) ), this, SLOT( slotChanged() ) ); 00330 connect( priority, SIGNAL( valueChanged ( int ) ), this, SLOT( slotChanged() ) ); 00331 00332 QWhatsThis::add( btnnew, i18n("Create a new file type.") ); 00333 QWhatsThis::add( btndel, i18n("Delete the current file type.") ); 00334 QWhatsThis::add( name, i18n( 00335 "The name of the filetype will be the text of the corresponding menu item.") ); 00336 QWhatsThis::add( section, i18n( 00337 "The section name is used to organize the file types in menus.") ); 00338 QWhatsThis::add( varLine, i18n( 00339 "<p>This string allows you to configure Kate's settings for the files " 00340 "selected by this mimetype using Kate variables. You can set almost any " 00341 "configuration option, such as highlight, indent-mode, encoding, etc.</p>" 00342 "<p>For a full list of known variables, see the manual.</p>") ); 00343 QWhatsThis::add( wildcards, i18n( 00344 "The wildcards mask allows you to select files by filename. A typical " 00345 "mask uses an asterisk and the file extension, for example " 00346 "<code>*.txt; *.text</code>. The string is a semicolon-separated list " 00347 "of masks.") ); 00348 QWhatsThis::add( mimetypes, i18n( 00349 "The mime type mask allows you to select files by mimetype. The string is " 00350 "a semicolon-separated list of mimetypes, for example " 00351 "<code>text/plain; text/english</code>.") ); 00352 QWhatsThis::add( btnMTW, i18n( 00353 "Displays a wizard that helps you easily select mimetypes.") ); 00354 QWhatsThis::add( priority, i18n( 00355 "Sets a priority for this file type. If more than one file type selects the same " 00356 "file, the one with the highest priority will be used." ) ); 00357 } 00358 00359 void KateFileTypeConfigTab::apply() 00360 { 00361 if (!changed()) 00362 return; 00363 00364 save (); 00365 00366 KateFactory::self()->fileTypeManager()->save(&m_types); 00367 } 00368 00369 void KateFileTypeConfigTab::reload() 00370 { 00371 m_types.clear(); 00372 for (uint z=0; z < KateFactory::self()->fileTypeManager()->list()->count(); z++) 00373 { 00374 KateFileType *type = new KateFileType (); 00375 00376 *type = *KateFactory::self()->fileTypeManager()->list()->at(z); 00377 00378 m_types.append (type); 00379 } 00380 00381 update (); 00382 } 00383 00384 void KateFileTypeConfigTab::reset() 00385 { 00386 reload (); 00387 } 00388 00389 void KateFileTypeConfigTab::defaults() 00390 { 00391 reload (); 00392 } 00393 00394 void KateFileTypeConfigTab::update () 00395 { 00396 m_lastType = 0; 00397 00398 typeCombo->clear (); 00399 00400 for( uint i = 0; i < m_types.count(); i++) { 00401 if (m_types.at(i)->section.length() > 0) 00402 typeCombo->insertItem(m_types.at(i)->section + QString ("/") + m_types.at(i)->name); 00403 else 00404 typeCombo->insertItem(m_types.at(i)->name); 00405 } 00406 00407 typeCombo->setCurrentItem (0); 00408 00409 typeChanged (0); 00410 00411 typeCombo->setEnabled (typeCombo->count() > 0); 00412 } 00413 00414 void KateFileTypeConfigTab::deleteType () 00415 { 00416 int type = typeCombo->currentItem (); 00417 00418 if ((type > -1) && ((uint)type < m_types.count())) 00419 { 00420 m_types.remove (type); 00421 update (); 00422 } 00423 } 00424 00425 void KateFileTypeConfigTab::newType () 00426 { 00427 QString newN = i18n("New Filetype"); 00428 00429 for( uint i = 0; i < m_types.count(); i++) { 00430 if (m_types.at(i)->name == newN) 00431 { 00432 typeCombo->setCurrentItem (i); 00433 typeChanged (i); 00434 return; 00435 } 00436 } 00437 00438 KateFileType *newT = new KateFileType (); 00439 newT->priority = 0; 00440 newT->name = newN; 00441 00442 m_types.prepend (newT); 00443 00444 update (); 00445 } 00446 00447 void KateFileTypeConfigTab::save () 00448 { 00449 if (m_lastType) 00450 { 00451 m_lastType->name = name->text (); 00452 m_lastType->section = section->text (); 00453 m_lastType->varLine = varLine->text (); 00454 m_lastType->wildcards = QStringList::split (";", wildcards->text ()); 00455 m_lastType->mimetypes = QStringList::split (";", mimetypes->text ()); 00456 m_lastType->priority = priority->value(); 00457 } 00458 } 00459 00460 void KateFileTypeConfigTab::typeChanged (int type) 00461 { 00462 save (); 00463 00464 KateFileType *t = 0; 00465 00466 if ((type > -1) && ((uint)type < m_types.count())) 00467 t = m_types.at(type); 00468 00469 if (t) 00470 { 00471 gbProps->setTitle (i18n("Properties of %1").arg (typeCombo->currentText())); 00472 00473 gbProps->setEnabled (true); 00474 btndel->setEnabled (true); 00475 00476 name->setText(t->name); 00477 section->setText(t->section); 00478 varLine->setText(t->varLine); 00479 wildcards->setText(t->wildcards.join (";")); 00480 mimetypes->setText(t->mimetypes.join (";")); 00481 priority->setValue(t->priority); 00482 } 00483 else 00484 { 00485 gbProps->setTitle (i18n("Properties")); 00486 00487 gbProps->setEnabled (false); 00488 btndel->setEnabled (false); 00489 00490 name->clear(); 00491 section->clear(); 00492 varLine->clear(); 00493 wildcards->clear(); 00494 mimetypes->clear(); 00495 priority->setValue(0); 00496 } 00497 00498 m_lastType = t; 00499 } 00500 00501 void KateFileTypeConfigTab::showMTDlg() 00502 { 00503 00504 QString text = i18n("Select the MimeTypes you want for this file type.\nPlease note that this will automatically edit the associated file extensions as well."); 00505 QStringList list = QStringList::split( QRegExp("\\s*;\\s*"), mimetypes->text() ); 00506 KMimeTypeChooserDialog d( i18n("Select Mime Types"), text, list, "text", this ); 00507 if ( d.exec() == KDialogBase::Accepted ) { 00508 // do some checking, warn user if mime types or patterns are removed. 00509 // if the lists are empty, and the fields not, warn. 00510 wildcards->setText( d.chooser()->patterns().join(";") ); 00511 mimetypes->setText( d.chooser()->mimeTypes().join(";") ); 00512 } 00513 } 00514 //END KateFileTypeConfigTab 00515 00516 //BEGIN KateViewFileTypeAction 00517 void KateViewFileTypeAction::init() 00518 { 00519 m_doc = 0; 00520 subMenus.setAutoDelete( true ); 00521 00522 popupMenu()->insertItem ( i18n("None"), this, SLOT(setType(int)), 0, 0); 00523 00524 connect(popupMenu(),SIGNAL(aboutToShow()),this,SLOT(slotAboutToShow())); 00525 } 00526 00527 void KateViewFileTypeAction::updateMenu (Kate::Document *doc) 00528 { 00529 m_doc = (KateDocument *)doc; 00530 } 00531 00532 void KateViewFileTypeAction::slotAboutToShow() 00533 { 00534 KateDocument *doc=m_doc; 00535 int count = KateFactory::self()->fileTypeManager()->list()->count(); 00536 00537 for (int z=0; z<count; z++) 00538 { 00539 QString hlName = KateFactory::self()->fileTypeManager()->list()->at(z)->name; 00540 QString hlSection = KateFactory::self()->fileTypeManager()->list()->at(z)->section; 00541 00542 if ( !hlSection.isEmpty() && (names.contains(hlName) < 1) ) 00543 { 00544 if (subMenusName.contains(hlSection) < 1) 00545 { 00546 subMenusName << hlSection; 00547 QPopupMenu *menu = new QPopupMenu (); 00548 subMenus.append(menu); 00549 popupMenu()->insertItem (hlSection, menu); 00550 } 00551 00552 int m = subMenusName.findIndex (hlSection); 00553 names << hlName; 00554 subMenus.at(m)->insertItem ( hlName, this, SLOT(setType(int)), 0, z+1); 00555 } 00556 else if (names.contains(hlName) < 1) 00557 { 00558 names << hlName; 00559 popupMenu()->insertItem ( hlName, this, SLOT(setType(int)), 0, z+1); 00560 } 00561 } 00562 00563 if (!doc) return; 00564 00565 for (uint i=0;i<subMenus.count();i++) 00566 { 00567 for (uint i2=0;i2<subMenus.at(i)->count();i2++) 00568 subMenus.at(i)->setItemChecked(subMenus.at(i)->idAt(i2),false); 00569 } 00570 popupMenu()->setItemChecked (0, false); 00571 00572 if (doc->fileType() == -1) 00573 popupMenu()->setItemChecked (0, true); 00574 else 00575 { 00576 const KateFileType *t = 0; 00577 if ((t = KateFactory::self()->fileTypeManager()->fileType (doc->fileType()))) 00578 { 00579 int i = subMenusName.findIndex (t->section); 00580 if (i >= 0 && subMenus.at(i)) 00581 subMenus.at(i)->setItemChecked (doc->fileType()+1, true); 00582 else 00583 popupMenu()->setItemChecked (0, true); 00584 } 00585 } 00586 } 00587 00588 void KateViewFileTypeAction::setType (int mode) 00589 { 00590 KateDocument *doc=m_doc; 00591 00592 if (doc) 00593 doc->updateFileType(mode-1, true); 00594 } 00595 //END KateViewFileTypeAction 00596 // kate: space-indent on; indent-width 2; replace-tabs on;