From 4aed2c8219774f5d797760606b8489a92ddc5163 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kcontrol/filetypes/filetypesview.cpp | 440 +++++++++++++++++++++++++++++++++++ 1 file changed, 440 insertions(+) create mode 100644 kcontrol/filetypes/filetypesview.cpp (limited to 'kcontrol/filetypes/filetypesview.cpp') diff --git a/kcontrol/filetypes/filetypesview.cpp b/kcontrol/filetypes/filetypesview.cpp new file mode 100644 index 000000000..4088e9eee --- /dev/null +++ b/kcontrol/filetypes/filetypesview.cpp @@ -0,0 +1,440 @@ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "newtypedlg.h" +#include "filetypedetails.h" +#include "filegroupdetails.h" +#include "filetypesview.h" +#include + +FileTypesView::FileTypesView(QWidget *p, const char *name) + : KCModule(p, name) +{ + m_konqConfig = KSharedConfig::openConfig("konquerorrc", false, false); + + setQuickHelp( i18n("

File Associations

" + " This module allows you to choose which applications are associated" + " with a given type of file. File types are also referred to MIME types" + " (MIME is an acronym which stands for \"Multipurpose Internet Mail" + " Extensions\".)

A file association consists of the following:" + "

  • Rules for determining the MIME-type of a file, for example" + " the filename pattern *.kwd, which means 'all files with names that end" + " in .kwd', is associated with the MIME type \"x-kword\";
  • " + "
  • A short description of the MIME-type, for example the description" + " of the MIME type \"x-kword\" is simply 'KWord document';
  • " + "
  • An icon to be used for displaying files of the given MIME-type," + " so that you can easily identify the type of file in, say, a Konqueror" + " view (at least for the types you use often);
  • " + "
  • A list of the applications which can be used to open files of the" + " given MIME-type -- if more than one application can be used then the" + " list is ordered by priority.
" + " You may be surprised to find that some MIME types have no associated" + " filename patterns; in these cases, Konqueror is able to determine the" + " MIME-type by directly examining the contents of the file.")); + + setButtons(Help | Apply | Cancel | Ok); + QString wtstr; + + QHBoxLayout *l = new QHBoxLayout(this, 0, KDialog::marginHint()); + QGridLayout *leftLayout = new QGridLayout(0, 4, 3); + leftLayout->setSpacing( KDialog::spacingHint() ); + leftLayout->setColStretch(1, 1); + + l->addLayout( leftLayout ); + + QLabel *patternFilterLBL = new QLabel(i18n("F&ind filename pattern:"), this); + leftLayout->addMultiCellWidget(patternFilterLBL, 0, 0, 0, 2); + + patternFilterLE = new KLineEdit(this); + patternFilterLBL->setBuddy( patternFilterLE ); + leftLayout->addMultiCellWidget(patternFilterLE, 1, 1, 0, 2); + + connect(patternFilterLE, SIGNAL(textChanged(const QString &)), + this, SLOT(slotFilter(const QString &))); + + wtstr = i18n("Enter a part of a filename pattern. Only file types with a " + "matching file pattern will appear in the list."); + + QWhatsThis::add( patternFilterLE, wtstr ); + QWhatsThis::add( patternFilterLBL, wtstr ); + + typesLV = new KListView(this); + typesLV->setRootIsDecorated(true); + typesLV->setFullWidth(true); + + typesLV->addColumn(i18n("Known Types")); + leftLayout->addMultiCellWidget(typesLV, 2, 2, 0, 2); + connect(typesLV, SIGNAL(selectionChanged(QListViewItem *)), + this, SLOT(updateDisplay(QListViewItem *))); + connect(typesLV, SIGNAL(doubleClicked(QListViewItem *)), + this, SLOT(slotDoubleClicked(QListViewItem *))); + + QWhatsThis::add( typesLV, i18n("Here you can see a hierarchical list of" + " the file types which are known on your system. Click on the '+' sign" + " to expand a category, or the '-' sign to collapse it. Select a file type" + " (e.g. text/html for HTML files) to view/edit the information for that" + " file type using the controls on the right.") ); + + QPushButton *addTypeB = new QPushButton(i18n("Add..."), this); + connect(addTypeB, SIGNAL(clicked()), SLOT(addType())); + leftLayout->addWidget(addTypeB, 3, 0); + + QWhatsThis::add( addTypeB, i18n("Click here to add a new file type.") ); + + m_removeTypeB = new QPushButton(i18n("&Remove"), this); + connect(m_removeTypeB, SIGNAL(clicked()), SLOT(removeType())); + leftLayout->addWidget(m_removeTypeB, 3, 2); + m_removeTypeB->setEnabled(false); + + QWhatsThis::add( m_removeTypeB, i18n("Click here to remove the selected file type.") ); + + // For the right panel, prepare a widget stack + m_widgetStack = new QWidgetStack(this); + + l->addWidget( m_widgetStack ); + + // File Type Details + m_details = new FileTypeDetails( m_widgetStack ); + connect( m_details, SIGNAL( changed(bool) ), + this, SLOT( setDirty(bool) ) ); + connect( m_details, SIGNAL( embedMajor(const QString &, bool &) ), + this, SLOT( slotEmbedMajor(const QString &, bool &))); + m_widgetStack->addWidget( m_details, 1 /*id*/ ); + + // File Group Details + m_groupDetails = new FileGroupDetails( m_widgetStack ); + connect( m_groupDetails, SIGNAL( changed(bool) ), + this, SLOT( setDirty(bool) ) ); + m_widgetStack->addWidget( m_groupDetails, 2 /*id*/ ); + + // Widget shown on startup + m_emptyWidget = new QLabel( i18n("Select a file type by name or by extension"), m_widgetStack); + m_emptyWidget->setAlignment(AlignCenter); + + m_widgetStack->addWidget( m_emptyWidget, 3 /*id*/ ); + + m_widgetStack->raiseWidget( m_emptyWidget ); + + QTimer::singleShot( 0, this, SLOT( init() ) ); // this takes some time + + connect( KSycoca::self(), SIGNAL( databaseChanged() ), SLOT( slotDatabaseChanged() ) ); +} + +FileTypesView::~FileTypesView() +{ +} + +void FileTypesView::setDirty(bool state) +{ + emit changed(state); + m_dirty = state; +} + +void FileTypesView::init() +{ + show(); + setEnabled( false ); + + setCursor( KCursor::waitCursor() ); + readFileTypes(); + unsetCursor(); + + setDirty(false); + setEnabled( true ); +} + +// only call this method once on startup, then never again! Otherwise, newly +// added Filetypes will be lost. +void FileTypesView::readFileTypes() +{ + typesLV->clear(); + m_majorMap.clear(); + m_itemList.clear(); + TypesListItem::reset(); + + TypesListItem *groupItem; + KMimeType::List mimetypes = KMimeType::allMimeTypes(); + QValueListIterator it2(mimetypes.begin()); + for (; it2 != mimetypes.end(); ++it2) { + QString mimetype = (*it2)->name(); + int index = mimetype.find("/"); + QString maj = mimetype.left(index); + QString min = mimetype.right(mimetype.length() - index+1); + + QMapIterator mit = m_majorMap.find( maj ); + if ( mit == m_majorMap.end() ) { + groupItem = new TypesListItem( typesLV, maj ); + m_majorMap.insert( maj, groupItem ); + } + else + groupItem = mit.data(); + + TypesListItem *item = new TypesListItem(groupItem, (*it2)); + m_itemList.append( item ); + } + updateDisplay(0L); + +} + +void FileTypesView::slotEmbedMajor(const QString &major, bool &embed) +{ + TypesListItem *groupItem; + QMapIterator mit = m_majorMap.find( major ); + if ( mit == m_majorMap.end() ) + return; + + groupItem = mit.data(); + + embed = (groupItem->autoEmbed() == 0); +} + +void FileTypesView::slotFilter(const QString & patternFilter) +{ + // one of the few ways to clear a listview without destroying the + // listviewitems and without making QListView crash. + QListViewItem *item; + while ( (item = typesLV->firstChild()) ) { + while ( item->firstChild() ) + item->takeItem( item->firstChild() ); + + typesLV->takeItem( item ); + } + + // insert all items and their group that match the filter + QPtrListIterator it( m_itemList ); + while ( it.current() ) { + if ( patternFilter.isEmpty() || + !((*it)->patterns().grep( patternFilter, false )).isEmpty() ) { + + TypesListItem *group = m_majorMap[ (*it)->majorType() ]; + // QListView makes sure we don't insert a group-item more than once + typesLV->insertItem( group ); + group->insertItem( *it ); + } + ++it; + } +} + +void FileTypesView::addType() +{ + QStringList allGroups; + QMapIterator it = m_majorMap.begin(); + while ( it != m_majorMap.end() ) { + allGroups.append( it.key() ); + ++it; + } + + NewTypeDialog m(allGroups, this); + + if (m.exec()) { + QListViewItemIterator it(typesLV); + QString loc = m.group() + "/" + m.text() + ".desktop"; + loc = locateLocal("mime", loc); + KMimeType::Ptr mimetype = new KMimeType(loc, + m.group() + "/" + m.text(), + QString(), QString(), + QStringList()); + + TypesListItem *group = m_majorMap[ m.group() ]; + if ( !group ) + { + //group = new TypesListItem( + //TODO ! (The combo in NewTypeDialog must be made editable again when that happens) + Q_ASSERT(group); + } + + // find out if our group has been filtered out -> insert if necessary + QListViewItem *item = typesLV->firstChild(); + bool insert = true; + while ( item ) { + if ( item == group ) { + insert = false; + break; + } + item = item->nextSibling(); + } + if ( insert ) + typesLV->insertItem( group ); + + TypesListItem *tli = new TypesListItem(group, mimetype, true); + m_itemList.append( tli ); + + group->setOpen(true); + typesLV->setSelected(tli, true); + + setDirty(true); + } +} + +void FileTypesView::removeType() +{ + TypesListItem *current = (TypesListItem *) typesLV->currentItem(); + + if ( !current ) + return; + + // Can't delete groups + if ( current->isMeta() ) + return; + // nor essential mimetypes + if ( current->isEssential() ) + return; + + QListViewItem *li = current->itemAbove(); + if (!li) + li = current->itemBelow(); + if (!li) + li = current->parent(); + + removedList.append(current->name()); + current->parent()->takeItem(current); + m_itemList.removeRef( current ); + setDirty(true); + + if ( li ) + typesLV->setSelected(li, true); +} + +void FileTypesView::slotDoubleClicked(QListViewItem *item) +{ + if ( !item ) return; + item->setOpen( !item->isOpen() ); +} + +void FileTypesView::updateDisplay(QListViewItem *item) +{ + if (!item) + { + m_widgetStack->raiseWidget( m_emptyWidget ); + m_removeTypeB->setEnabled(false); + return; + } + + bool wasDirty = m_dirty; + + TypesListItem *tlitem = (TypesListItem *) item; + if (tlitem->isMeta()) // is a group + { + m_widgetStack->raiseWidget( m_groupDetails ); + m_groupDetails->setTypeItem( tlitem ); + m_removeTypeB->setEnabled(false); + } + else + { + m_widgetStack->raiseWidget( m_details ); + m_details->setTypeItem( tlitem ); + m_removeTypeB->setEnabled( !tlitem->isEssential() ); + } + + // Updating the display indirectly called change(true) + if ( !wasDirty ) + setDirty(false); +} + +bool FileTypesView::sync( QValueList& itemsModified ) +{ + bool didIt = false; + // first, remove those items which we are asked to remove. + QStringList::Iterator it(removedList.begin()); + QString loc; + + for (; it != removedList.end(); ++it) { + didIt = true; + KMimeType::Ptr m_ptr = KMimeType::mimeType(*it); + + loc = m_ptr->desktopEntryPath(); + loc = locateLocal("mime", loc); + + KDesktopFile config(loc, false, "mime"); + config.writeEntry("Type", "MimeType"); + config.writeEntry("MimeType", m_ptr->name()); + config.writeEntry("Hidden", true); + } + + // now go through all entries and sync those which are dirty. + // don't use typesLV, it may be filtered + QMapIterator it1 = m_majorMap.begin(); + while ( it1 != m_majorMap.end() ) { + TypesListItem *tli = *it1; + if (tli->isDirty()) { + kdDebug() << "Entry " << tli->name() << " is dirty. Saving." << endl; + tli->sync(); + itemsModified.append( tli ); + didIt = true; + } + ++it1; + } + QPtrListIterator it2( m_itemList ); + while ( it2.current() ) { + TypesListItem *tli = *it2; + if (tli->isDirty()) { + kdDebug() << "Entry " << tli->name() << " is dirty. Saving." << endl; + tli->sync(); + itemsModified.append( tli ); + didIt = true; + } + ++it2; + } + + m_konqConfig->sync(); + + setDirty(false); + return didIt; +} + +void FileTypesView::load() +{ + readFileTypes(); +} + +void FileTypesView::save() +{ + m_itemsModified.clear(); + if (sync(m_itemsModified)) { + // only rebuild if sync() was necessary + KService::rebuildKSycoca(this); + KIPC::sendMessageAll(KIPC::SettingsChanged); + } +} + +void FileTypesView::slotDatabaseChanged() +{ + if ( KSycoca::self()->isChanged( "mime" ) ) + { + // ksycoca has new KMimeTypes objects for us, make sure to update + // our 'copies' to be in sync with it. Not important for OK, but + // important for Apply (how to differentiate those 2?). + // See BR 35071. + QValueList::Iterator it = m_itemsModified.begin(); + for( ; it != m_itemsModified.end(); ++it ) { + QString name = (*it)->name(); + if ( removedList.find( name ) == removedList.end() ) // if not deleted meanwhile + (*it)->refresh(); + } + m_itemsModified.clear(); + } +} + +void FileTypesView::defaults() +{ +} + +#include "filetypesview.moc" + -- cgit v1.2.1