summaryrefslogtreecommitdiffstats
path: root/src/part/part.cpp
blob: 9a4742a9b08158c8498016809b34b6bf733af25b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
//Author:    Max Howell <[email protected]>, (C) 2003-4
//Copyright: See COPYING file that comes with this distribution

#include "Config.h"
#include "debug.h"
#include "define.h"
#include "fileTree.h"
#include "part.h"
#include "progressBox.h"
#include "radialMap/widget.h"
#include "scan.h"
#include "settingsDialog.h"
#include "summaryWidget.h"

#include <kaboutdata.h>   //::createAboutData()
#include <kaction.h>
#include <klocale.h>
#include <kmessagebox.h>  //::start()
//#include <konq_operations.h>
#include <kparts/genericfactory.h>
#include <kstatusbar.h>
#include <kstdaction.h>
#include <qfile.h>        //encodeName()
#include <qtimer.h>       //postInit() hack
#include <qvbox.h>
#include <unistd.h>       //access()


namespace Filelight {


typedef KParts::GenericFactory<Filelight::Part> Factory;
K_EXPORT_COMPONENT_FACTORY( libfilelight, Filelight::Factory )


BrowserExtension::BrowserExtension( Part *parent, const char *name )
  : KParts::BrowserExtension( parent, name )
{}


Part::Part( QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name, const QStringList& )
        : ReadOnlyPart( parent, name )
        , m_ext( new BrowserExtension( this ) )
        , m_statusbar( new StatusBarExtension( this ) )
        , m_map( 0 )
        , m_manager( new ScanManager( this ) )
        , m_started( false )
{
    QPixmap::setDefaultOptimization( QPixmap::BestOptim );

    Config::read();

    setInstance( Factory::instance() );
    setWidget( new QVBox( parentWidget, widgetName ) );
    setXMLFile( "filelight_partui.rc" );

    m_map = new RadialMap::Widget( widget() );
    m_map->hide();

    KStdAction::zoomIn( m_map, SLOT(zoomIn()), actionCollection() );
    KStdAction::zoomOut( m_map, SLOT(zoomOut()), actionCollection() );
    KStdAction::preferences( this, SLOT(configFilelight()), actionCollection(), "configure_filelight" )->setText( i18n( "Configure Filelight..." ) );

    connect( m_map, SIGNAL(created( const Directory* )), SIGNAL(completed()) );
    connect( m_map, SIGNAL(created( const Directory* )), SLOT(mapChanged( const Directory* )) );
    connect( m_map, SIGNAL(activated( const KURL& )), SLOT(updateURL( const KURL& )) );

    // TODO make better system
    connect( m_map, SIGNAL(giveMeTreeFor( const KURL& )), SLOT(updateURL( const KURL& )) );
    connect( m_map, SIGNAL(giveMeTreeFor( const KURL& )), SLOT(openURL( const KURL& )) );

    connect( m_manager, SIGNAL(completed( Directory* )), SLOT(scanCompleted( Directory* )) );
    connect( m_manager, SIGNAL(aboutToEmptyCache()), m_map, SLOT(invalidate()) );

    QTimer::singleShot( 0, this, SLOT(postInit()) );
}

void
Part::postInit()
{
   if( m_url.isEmpty() ) //if url is not empty openURL() has been called immediately after ctor, which happens
   {
      QWidget *summary = new SummaryWidget( widget(), "summaryWidget" );
      connect( summary, SIGNAL(activated( const KURL& )), SLOT(openURL( const KURL& )) );
      summary->show();

      //FIXME KXMLGUI is b0rked, it should allow us to set this
      //BEFORE createGUI is called but it doesn't
      stateChanged( "scan_failed" );
   }
}

bool
Part::openURL( const KURL &u )
{
   //we don't want to be using the summary screen anymore
   delete widget()->child( "summaryWidget" );
   m_map->show();

   //TODO everyone hates dialogs, instead render the text in big fonts on the Map
   //TODO should have an empty KURL until scan is confirmed successful
   //TODO probably should set caption to QString::null while map is unusable

   #define KMSG( s ) KMessageBox::information( widget(), s )

   KURL url = u;
   url.cleanPath( true );
   const QString path = url.path( 1 );
   const QCString path8bit = QFile::encodeName( path );
   const bool isLocal = url.protocol() == "file";

   if( url.isEmpty() )
   {
      //do nothing, chances are the user accidently pressed ENTER
   }
   else if( !url.isValid() )
   {
      KMSG( i18n( "The entered URL cannot be parsed; it is invalid." ) );
   }
   else if( path[0] != '/' )
   {
      KMSG( i18n( "Filelight only accepts absolute paths, eg. /%1" ).arg( path ) );
   }
   else if( isLocal && access( path8bit, F_OK ) != 0 ) //stat( path, &statbuf ) == 0
   {
      KMSG( i18n( "Directory not found: %1" ).arg( path ) );
   }
   else if( isLocal && access( path8bit, R_OK | X_OK ) != 0 )
   {
      KMSG( i18n( "Unable to enter: %1\nYou do not have access rights to this location." ).arg( path ) );
   }
   else
   {
      if( url == m_url )
         m_manager->emptyCache(); //same as rescan()

      return start( url );
   }

   return false;
}

bool
Part::closeURL()
{
   if( m_manager->abort() )
      statusBar()->message( i18n( "Aborting Scan..." ) );

   m_url = KURL();

   return true;
}

void
Part::updateURL( const KURL &u )
{
   //the map has changed internally, update the interface to reflect this
   emit m_ext->openURLNotify(); //must be done first
   emit m_ext->setLocationBarURL( u.prettyURL() );

   //do this last, or it breaks Konqi location bar
   m_url = u;
}

void
Part::configFilelight()
{
    QWidget *dialog = new SettingsDialog( widget(), "settings_dialog" );

    connect( dialog, SIGNAL(canvasIsDirty( int )), m_map, SLOT(refresh( int )) );
    connect( dialog, SIGNAL(mapIsInvalid()), m_manager, SLOT(emptyCache()) );

    dialog->show(); //deletes itself
}

KAboutData*
Part::createAboutData()
{
    return new KAboutData( APP_NAME, I18N_NOOP( APP_PRETTYNAME ), APP_VERSION );
}

bool
Part::start( const KURL &url )
{
   if( !m_started ) {
      m_statusbar->addStatusBarItem( new ProgressBox( statusBar(), this ), 0, true );
      connect( m_map, SIGNAL(mouseHover( const QString& )), statusBar(), SLOT(message( const QString& )) );
      connect( m_map, SIGNAL(created( const Directory* )), statusBar(), SLOT(clear()) );
      m_started = true;
   }

   if( m_manager->start( url ) ) {
      m_url = url;

      const QString s = i18n( "Scanning: %1" ).arg( prettyURL() );
      stateChanged( "scan_started" );
      emit started( 0 ); //as a Part, we have to do this
      emit setWindowCaption( s );
      statusBar()->message( s );
      m_map->invalidate(); //to maintain ui consistency

      return true;
   }

   return false;
}

void
Part::rescan()
{
   //FIXME we have to empty the cache because otherwise rescan picks up the old tree..
   m_manager->emptyCache(); //causes canvas to invalidate
   start( m_url );
}

void
Part::scanCompleted( Directory *tree )
{
   if( tree ) {
      statusBar()->message( i18n( "Scan completed, generating map..." ) );

      m_map->create( tree );

      //do after creating map
      stateChanged( "scan_complete" );
   }
   else {
      stateChanged( "scan_failed" );
      emit canceled( i18n( "Scan failed: %1" ).arg( prettyURL() ) );
      emit setWindowCaption( QString::null );

      statusBar()->clear();
//      QTimer::singleShot( 2000, statusBar(), SLOT(clear()) );

      m_url = KURL();
   }
}

void
Part::mapChanged( const Directory *tree )
{
   //IMPORTANT -> m_url has already been set

   emit setWindowCaption( prettyURL() );

   ProgressBox *progress = static_cast<ProgressBox *>(statusBar()->child( "ProgressBox" ));

   if( progress )
      progress->setText( tree->children() );
}

} //namespace Filelight

#include "part.moc"