Logo Search packages:      
Sourcecode: packagesearch version File versions

filenameplugin.cpp

#include <fstream>

#include <assert.h>

#include <qfileinfo.h>
#include <qtimer.h>
#include <qlineedit.h>
#include <qstatusbar.h>
#include <qcheckbox.h>
#include <qprocess.h>

#include <iprovider.h>

#include <helpers.h>
#include <extalgorithm.h>

#include "filenameplugin.h"

#include "filenameview.h"
#include "filenamesearchinput.h"
#include "filenamefeedbackwidget.h"

#include "singlehandlemaker.h"

#include "runcommandforoutput.h"


using namespace std;

namespace NPlugin
{


FilenamePlugin::FilenamePlugin()
{
      _pProcess = 0;
      _pFilenameFeedbackWidget = 0;
      _pFileView = 0;
      _pProvider = 0;
      _pInputWidget = 0;
      _pDelayTimer = new QTimer(this, "delayTimer");
      _delayTime=2000;
      connect(_pDelayTimer, SIGNAL(timeout()), SLOT(evaluateSearch()));
}

FilenamePlugin::~FilenamePlugin()
{
      delete _pFileView;
      delete _pInputWidget;
      delete _pFilenameFeedbackWidget;
      delete _pDelayTimer;
      delete _pProcess;
}

/////////////////////////////////////////////////////
// Plugin Interface
/////////////////////////////////////////////////////

QString FilenamePlugin::title() const
{ 
      return tr("Filename Plugin"); 
}

QString FilenamePlugin::briefDescription() const
{
      return tr("This shows the files a package uses.");
}

QString FilenamePlugin::description() const
{
      return tr("This shows the files a package uses.\n"
                         "It shows only those of packages currently installed.");
}

void FilenamePlugin::init(IProvider* pProvider)
{
      _pProvider = pProvider;
      QMainWindow* pWindow = pProvider->mainWindow();
      _pFileView = new FilenameView(pWindow, "FileView");
      _pInputWidget = new FilenameSearchInput(pWindow, "FilenamePatternInput");
      _pFilenameFeedbackWidget = new FilenameFeedbackWidget(pWindow, "FilenameFeedbackWidget");
      connect( _pInputWidget->_pFilenamePatternInput, SIGNAL(textChanged(const QString&)), 
            SLOT(onInputTextChanged(const QString&)) );
      connect( _pInputWidget->_pFilenamePatternInput, SIGNAL(returnPressed()),
            SLOT(evaluateSearch()) );
      connect( _pInputWidget->_pSearchInstalledOnlyCheck, SIGNAL(toggled(bool)), 
            SLOT(evaluateSearch()) );
      connect(_pFileView, SIGNAL(showRequested()), SLOT(onShowRequested()));
}

/////////////////////////////////////////////////////
// Information Plugin Interface
/////////////////////////////////////////////////////


QWidget* FilenamePlugin::informationWidget() const    
{ 
      return _pFileView; 
}

QString FilenamePlugin::informationWidgetTitle() const 
{
      return tr("Files"); 
}

void FilenamePlugin::updateInformationWidget(int packageID)
{
      string newPackage = SingleHandleMaker::instance()->getItem(packageID);
      if ( _currentPackage == toQString(newPackage) ) return;
      _currentPackage = toQString(newPackage);
      _pFileView->clear();
      // prevent showing of information if we have only slow access to the file list (i.e. 
      // apt-file
      if (hasFastFilelist(newPackage))    
      {
            onShowRequested();
      }
      else
      {
            _pFileView->setErrorMessage
            (
                  "<font color=#606060>For packages <b>not installed</b>, the files are not shown "
                  "by default. This is because listing those will take some time.<br>"
                  "Please click the <b>&quot;Show&quot;</b> button to show the filelist for the "
                  "selected package.</font>" 
            );
      }
}

void FilenamePlugin::clearInformationWidget()
{
      _pFileView->clear();
}

QString FilenamePlugin::informationText (int packageID)
{
      return _emptyString;
}


/////////////////////////////////////////////////////
// Search Plugin Interface
/////////////////////////////////////////////////////

QWidget* FilenamePlugin::shortInputAndFeedbackWidget() const
{
      return _pFilenameFeedbackWidget;
}

QWidget* FilenamePlugin::inputWidget() const
{
      return _pInputWidget;
}

QString FilenamePlugin::inputWidgetTitle() const 
{ 
      return QString("Filenames"); 
};


void FilenamePlugin::clearSearch()
{
      _pInputWidget->_pFilenamePatternInput->clear();
      _pDelayTimer->stop();
      evaluateSearch();
}


bool FilenamePlugin::isInactive() const
{
      return _pInputWidget->_pFilenamePatternInput->text().isEmpty();
}

/////////////////////////////////////////////////////
// Information Helper Methods
/////////////////////////////////////////////////////

bool FilenamePlugin::hasFastFilelist(const string& packageName)
{
      QFileInfo packageList("/var/lib/dpkg/info/" + packageName + ".list");
      return (packageList.isReadable());  // if the package is installed i.e. its list is in the .list file
}

QStringList FilenamePlugin::filesForPackage(const string& packageName) throw (NoInformationException)
{
      QStringList files;      // the files in the given package
      QFileInfo packageList("/var/lib/dpkg/info/" + packageName + ".list");
      if (packageList.isReadable()) // if the package is installed i.e. its list is in the .list file
      {
            string filename = "/var/lib/dpkg/info/" + packageName + ".list";
            ifstream file(filename.c_str());
            while (file)
            {
                  string currentLine;
                  file >> currentLine;
                  if ( !currentLine.empty() )
                        files.push_back(currentLine);
            }
            file.close();
      }
      else
      {
            if (aptFileAvailable())
            {
                  if (!_processMutex.tryLock())
                  {
                        qDebug("The mutex was locked\n");
                        return QStringList();
                  }
                  _pProvider->reportBusy(this, "Querying database for installed files.");
                  _pProvider->setEnabled(false);
                  _pProcess = new QProcess(QString("apt-file"), this, "fileListProcess");
                  _pProcess->addArgument("list");
                  _pProcess->addArgument(toQString(packageName));
                  connect(_pProcess, SIGNAL(readyReadStdout()), SLOT(onStdoutFromFilelist()));
                  connect(_pProcess, SIGNAL(processExited()), SLOT(onFilelistProcessExited()));
                  _pProcess->start();
            }
            else
            {
                  throw NoInformationException(
                         QObject::tr("<p>No information for this package could be retrieved.\n"
                        "If <tt>apt-file</tt> is not installed, the list of files is only available for "
                        "installed packages.</p>"
                        "To get apt-file fetch it via <tt>apt-get install apt-file</tt> and run "
                        "<tt>apt-file update</tt> after this.")
                  );
            }
      }
      return files;     // return the list of files, or an empty list if a process was launched
}

bool FilenamePlugin::fixEntry(QString& entry, const QString& packageName)
{
      
      if (!entry.startsWith(packageName+":"))
            return false;
      entry.replace(packageName+": ", "/");
      return true;
}

void FilenamePlugin::onStdoutFromFilelist()
{
      while ( _pProcess->canReadLineStdout() )
      {
            QString line = _pProcess->readLineStdout();
            if (fixEntry(line, _currentPackage))
                  _pFileView->addEntry(line);
      }
}

void FilenamePlugin::onFilelistProcessExited()
{
      onStdoutFromFilelist(); // evaluate the remaining lines
      _pProvider->reportReady(this);
      delete _pProcess;
      _pProcess = 0;
      _processMutex.unlock();
      _pProvider->setEnabled(true);
}

void FilenamePlugin::onShowRequested()
{
      _pFileView->clear();
      try
      {
            QStringList files = filesForPackage(_currentPackage);
            NExtStd::for_each(files.begin(), files.end(), &FilenameView::addEntry, _pFileView);
      }
      catch (NoInformationException e)    // this should not happen, only for security reasons
      {
            _pFileView->setErrorMessage(e._errorMessage);
      }
}

/////////////////////////////////////////////////////
// Search Helper Methods
/////////////////////////////////////////////////////


void FilenamePlugin::onInputTextChanged(const QString&)
{
      _pProvider->mainWindow()->statusBar()->message( tr("delayed evaluation - waiting for further input") );
      _pDelayTimer->start(_delayTime,true);
}


void FilenamePlugin::evaluateSearch()
{
      // stop the delay timer in case that this evaluateSearch() was triggered by
      // another event
      _pDelayTimer->stop();
      // reportReady will be called on applications exit
      _searchResult.clear();
      QString searchFilename = _pInputWidget->_pFilenamePatternInput->text();
      if ( !searchFilename.isEmpty() )    // if the search is not empty
      {
            if (!aptFileAvailable() && !_pInputWidget->_pSearchInstalledOnlyCheck->isChecked())
            {
                  _pProvider->reportError(
                        tr("Apt file search not availabe"),
                        tr("You need the <tt>apt-file</tt> utility to search files "
                        "in packages not installed.<br>"
                        "To get apt-file fetch it via <tt>apt-get install apt-file</tt> and run "
                        "<tt>apt-file update</tt> after this.")
                  );
                  return;
            }
            if (!_processMutex.tryLock())
            {
                  qDebug("The mutex was locked\n");
                  return;
            }
            assert(_pProcess==0);
            _pProvider->reportBusy(this, tr("Performing search for filenames, this might take a while"));
            _pProvider->setEnabled(false);
            if (_pInputWidget->_pSearchInstalledOnlyCheck->isChecked())
            {
                  _pProcess = new QProcess(QString("dpkg"), this, "dpkgFileSearchProcess");
                  connect(_pProcess, SIGNAL(readyReadStdout()), SLOT(onStdoutFromFilesearch()));
                  connect(_pProcess, SIGNAL(processExited()), SLOT(onSearchProcessExited()));
                  _pProcess->addArgument("-S");
                  _pProcess->addArgument("*"+searchFilename+"*");
                  if (!_pProcess->start())
                        onSearchProcessExited();
            }
            else
            {
                  _pProcess = new QProcess(QString("apt-file"), this, "aptFileSearchProcess");
                  connect(_pProcess, SIGNAL(readyReadStdout()), SLOT(onStdoutFromFilesearch()));
                  connect(_pProcess, SIGNAL(processExited()), SLOT(onSearchProcessExited()));
                  _pProcess->addArgument("search");
                  _pProcess->addArgument(searchFilename);
                  if (!_pProcess->start())
                        onSearchProcessExited();
            }
      }
      else
      {
            // do not show the feedback widget if the search is empty
            _pFilenameFeedbackWidget->setShown(false);      
            emit searchChanged(this);
      }
}


void FilenamePlugin::onStdoutFromFilesearch()
{
      while ( _pProcess->canReadLineStdout() )
      {
            QString line = _pProcess->readLineStdout();
            Tagcoll::HandleMaker<string>* pHm = SingleHandleMaker::instance();
            // if we performed a dpkg -S search
            if (_pInputWidget->_pSearchInstalledOnlyCheck->isChecked())
            {     /// @todo intercept not found message here - not neccessary?
                  /// @todo fix diversion bin entries
                  line = line.left(line.find(':'));   // the packages are listed before the colon
                  QStringList packages = QStringList::split(", ",line);
                  for(QStringList::iterator it = packages.begin(); it != packages.end(); ++it)
                        _searchResult.insert( pHm->getHandle(toString( *it )) );
            }
            // if it was an apt-file search
            else
            {
                  _searchResult.insert( pHm->getHandle(toString( getPackageFromAptFileSearchEntry(line) )) );
            }
      }
}

void FilenamePlugin::onSearchProcessExited()
{
      onStdoutFromFilesearch();     // evaluate the remaining lines
      _pProvider->reportReady(this);
      emit searchChanged(this);
      
      _pFilenameFeedbackWidget->setShown(true);
      _pFilenameFeedbackWidget->_pFilenameDisplay->setText(_pInputWidget->_pFilenamePatternInput->text());
      
      delete _pProcess;
      _pProcess = 0;
      _processMutex.unlock();
      _pProvider->setEnabled(true);
}

/////////////////////////////////////////////////////
// Helper Methods
/////////////////////////////////////////////////////

bool FilenamePlugin::aptFileAvailable()
{
      QFileInfo aptFile("/usr/bin/apt-file");
      return aptFile.isExecutable();
}


}     // namespace NPlugin

Generated by  Doxygen 1.6.0   Back to index