/*************************************************************************** * Copyright (C) 2003-2006 Jason Kivlighn (jkivlighn@gmail.com) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "similarcategoriesdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "widgets/categorycombobox.h" #include "backends/recipedb.h" SimilarCategoriesDialog::SimilarCategoriesDialog( ElementList &list, TQWidget* parent ) : TQDialog( parent, "SimilarCategoriesDialog", true ), m_elementList(list) { SimilarCategoriesDialogLayout = new TQVBoxLayout( this, 11, 6, "SimilarCategoriesDialogLayout"); layout6 = new TQHBoxLayout( 0, 0, 6, "layout6"); layout4 = new TQGridLayout( 0, 1, 1, 0, 6, "layout4"); categoriesBox = new KLineEdit( this ); layout4->addWidget( categoriesBox, 0, 1 ); thresholdSlider = new TQSlider( this, "thresholdSlider" ); thresholdSlider->setValue( 40 ); thresholdSlider->setOrientation( TQSlider::Horizontal ); layout4->addWidget( thresholdSlider, 1, 1 ); thresholdLabel = new TQLabel( this, "thresholdLabel" ); layout4->addWidget( thresholdLabel, 1, 0 ); categoryLabel = new TQLabel( this, "categoryLabel" ); layout4->addWidget( categoryLabel, 0, 0 ); layout6->addLayout( layout4 ); layout5 = new TQVBoxLayout( 0, 0, 6, "layout5"); searchButton = new TQPushButton( this, "searchButton" ); layout5->addWidget( searchButton ); spacer4 = new TQSpacerItem( 20, 51, TQSizePolicy::Minimum, TQSizePolicy::Expanding ); layout5->addItem( spacer4 ); layout6->addLayout( layout5 ); SimilarCategoriesDialogLayout->addLayout( layout6 ); layout9 = new TQHBoxLayout( 0, 0, 6, "layout9"); layout8 = new TQVBoxLayout( 0, 0, 6, "layout8"); allLabel = new TQLabel( this, "allLabel" ); layout8->addWidget( allLabel ); allListView = new TDEListView( this, "allListView" ); allListView->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)7, (TQSizePolicy::SizeType)7, 0, 1, allListView->sizePolicy().hasHeightForWidth() ) ); layout8->addWidget( allListView ); layout9->addLayout( layout8 ); layout1 = new TQVBoxLayout( 0, 0, 6, "layout1"); removeButton = new TQPushButton( this, "removeButton" ); layout1->addWidget( removeButton ); addButton = new TQPushButton( this, "addButton" ); layout1->addWidget( addButton ); spacer1 = new TQSpacerItem( 20, 61, TQSizePolicy::Minimum, TQSizePolicy::Expanding ); layout1->addItem( spacer1 ); layout9->addLayout( layout1 ); layout7 = new TQVBoxLayout( 0, 0, 6, "layout7"); toMergeLabel = new TQLabel( this, "toMergeLabel" ); layout7->addWidget( toMergeLabel ); toMergeListView = new TDEListView( this, "toMergeListView" ); toMergeListView->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)7, (TQSizePolicy::SizeType)7, 0, 1, toMergeListView->sizePolicy().hasHeightForWidth() ) ); layout7->addWidget( toMergeListView ); layout9->addLayout( layout7 ); SimilarCategoriesDialogLayout->addLayout( layout9 ); layout10 = new TQHBoxLayout( 0, 0, 6, "layout10"); spacer2 = new TQSpacerItem( 310, 20, TQSizePolicy::Expanding, TQSizePolicy::Minimum ); layout10->addItem( spacer2 ); mergeButton = new TQPushButton( this, "mergeButton" ); layout10->addWidget( mergeButton ); cancelButton = new TQPushButton( this, "cancelButton" ); layout10->addWidget( cancelButton ); SimilarCategoriesDialogLayout->addLayout( layout10 ); languageChange(); resize( TQSize(573, 429).expandedTo(minimumSizeHint()) ); clearWState( WState_Polished ); connect( searchButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(findMatches()) ); connect( mergeButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(mergeMatches()) ); connect( cancelButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(reject()) ); connect( addButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(addCategory()) ); connect( removeButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(removeCategory()) ); } /* * Destroys the object and frees any allocated resources */ SimilarCategoriesDialog::~SimilarCategoriesDialog() { // no need to delete child widgets, TQt does it all for us } /* * Sets the strings of the subwidgets using the current * language. */ void SimilarCategoriesDialog::languageChange() { setCaption( i18n( "Similar Categories" ) ); thresholdLabel->setText( i18n( "Threshold:" ) ); categoryLabel->setText( i18n( "Category:" ) ); searchButton->setText( i18n( "Search" ) ); allLabel->setText( i18n( "Similar Categories:" ) ); removeButton->setText( i18n( "<<" ) ); addButton->setText( i18n( ">>" ) ); toMergeLabel->setText( i18n( "Categories to Merge:" ) ); mergeButton->setText( i18n( "Merge" ) ); cancelButton->setText( i18n( "Cancel" ) ); allListView->addColumn( i18n( "Category" ) ); //allListView->addColumn( i18n( "Id" ) ); toMergeListView->addColumn( i18n( "Category" ) ); //toMergeListView->addColumn( i18n( "Id" ) ); } /*****************************************************/ /*Function prototypes and libraries needed to compile*/ /*****************************************************/ #include #include #include int levenshtein_distance(const char *s,const char*t); int minimum(int a,int b,int c); /****************************************/ /*Implementation of Levenshtein distance*/ /****************************************/ int levenshtein_distance(const char *s,const char*t) /*Compute levenshtein distance between s and t*/ { //Step 1 int k,i,j,n,m,cost,*d,distance; n=strlen(s); m=strlen(t); if(n!=0&&m!=0) { d=(int*)malloc((sizeof(int))*(m+1)*(n+1)); m++; n++; //Step 2 for(k=0;k wordLetterPairs(const TQString &str) { TQValueList allPairs; // Tokenize the string and put the tokens/words into an array TQStringList words = TQStringList::split("\\s",str); // For each word for (uint w=0; w < words.count(); w++) { // Find the pairs of characters TQStringList pairsInWord = letterPairs(words[w]); for (uint p=0; p < pairsInWord.count(); p++) { allPairs.append(pairsInWord[p]); } } return allPairs; } /** @return lexical similarity value in the range [0,1] */ double compareStrings(const TQString &str1, const TQString &str2) { TQValueList pairs1 = wordLetterPairs(str1.upper()); TQValueList pairs2 = wordLetterPairs(str2.upper()); int intersection = 0; int size_union = pairs1.count() + pairs2.count(); for (uint i=0; i #if 0 void RecipeActionsHandler::mergeSimilar() { TQPtrList items = parentListView->selectedItems(); if ( items.count() > 1 ) KMessageBox::sorry( kapp->mainWidget(), i18n("Please select only one category."), TQString::null ); else if ( items.count() == 1 && items.at(0)->rtti() == 1001 ) { CategoryListItem * cat_it = ( CategoryListItem* ) items.at(0); TQString name = cat_it->categoryName(); const double max_allowed_distance = 0.60; const int length = name.length(); ElementList categories; database->loadCategories( &categories ); ElementList matches; for ( ElementList::const_iterator it = categories.begin(); it != categories.end(); ++it ) { #if 0 if ( levenshtein_distance(name.latin1(),(*it).name.latin1())/double(TQMAX(length,(*it).name.length())) >= max_allowed_distance ) { #else if ( compareStrings(name,(*it).name) >= max_allowed_distance ) { #endif kdDebug()<<(*it).name<<" matches"<categoryId() != (*it).id ) matches.append(*it); } } for ( ElementList::const_iterator it = categories.begin(); it != categories.end(); ++it ) { database->mergeCategories(cat_it->categoryId(),(*it).id); } } else //either nothing was selected or a recipe was selected KMessageBox::sorry( kapp->mainWidget(), i18n("No recipes selected."), i18n("Edit Recipe") ); } #endif void SimilarCategoriesDialog::findMatches() { allListView->clear(); toMergeListView->clear(); const double threshold = (100 - thresholdSlider->value())/100.0; const TQString name = categoriesBox->text(); for ( ElementList::const_iterator it = m_elementList.begin(); it != m_elementList.end(); ++it ) { //kdDebug()<<(*it).name<<" (result/threshold): "<= max_allowed_distance ) { #else if ( compareStrings(name,(*it).name) >= threshold ) { #endif kdDebug()<<(*it).name<<" matches"<firstChild() ) { KMessageBox::sorry( this, i18n("No categories selected to merge."), TQString::null ); return; } //const int id = categoriesBox->id(categoriesBox->currentItem()); //for ( TQListViewItem *item = toMergeListView->firstChild(); item; item = item->nextSibling() ) { // m_database->mergeCategories(id,item->text(1).toInt()); //} allListView->clear(); //toMergeListView->clear(); TQDialog::accept(); } TQValueList SimilarCategoriesDialog::matches() const { TQValueList ids; for ( TQListViewItem *item = toMergeListView->firstChild(); item; item = item->nextSibling() ) { ids << item->text(1).toInt(); } return ids; } TQString SimilarCategoriesDialog::element() const { return categoriesBox->text(); } void SimilarCategoriesDialog::addCategory() { TQListViewItem *item = allListView->selectedItem(); if ( item ) { //make sure it isn't already in the list for ( TQListViewItem *search_it = toMergeListView->firstChild(); search_it; search_it = search_it->nextSibling() ) { if ( search_it->text(0) == item->text(0) ) return; } (void) new TQListViewItem(toMergeListView,item->text(0),item->text(1)); } } void SimilarCategoriesDialog::removeCategory() { TQListViewItem *item = toMergeListView->selectedItem(); if ( item ) delete item; } #include "similarcategoriesdialog.moc"