~ubuntu-branches/ubuntu/oneiric/valkyrie/oneiric

« back to all changes in this revision

Viewing changes to valkyrie/help/context_help.cpp

  • Committer: Package Import Robot
  • Author(s): Clint Byrum
  • Date: 2011-09-02 22:08:34 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: package-import@ubuntu.com-20110902220834-kigsixteppj9epp5
Tags: 2.0.0-0ubuntu1
* New upstream release. (LP: #635129, LP: #832886, LP: #721298)
* Standards bumped to 3.9.2, no changes required.
* d/control, d/rules: cdbs removed, dh minimal rule instead.
* d/control: build system is qmake not autotools
* d/control: bump required qt to qt4
* d/valkyrie.install: installing html docs manually as make install
  no longer does so.
* d/patches/valkyrie-2.0.0-fix-doc.dir.patch: Fix doc path to match
  policy. Also corrects LP: #588074 since the documentation link now
  works.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* ---------------------------------------------------------------------
2
 
 * Implementation of ContextHelp                        context_help.cpp
3
 
 * Context-sensitive help 
4
 
 * --------------------------------------------------------------------- 
5
 
 * This file is part of Valkyrie, a front-end for Valgrind
6
 
 * Copyright (C) 2000-2008, OpenWorks LLP <info@open-works.co.uk>
7
 
 * This program is released under the terms of the GNU GPL v.2
8
 
 * See the file COPYING for the full license details.
9
 
 */
10
 
 
11
 
#include "context_help.h"
12
 
#include "hand_book.h"
13
 
#include "vk_utils.h"              // VK_DEBUG
14
 
 
15
 
#include <qapplication.h>
16
 
 
17
 
 
18
 
static const char * const context_help_xpm[] = {
19
 
   "16 16 3 1",
20
 
   "   c None",
21
 
   "+  c #000000",
22
 
   "*  c #000080",
23
 
   "+        *****  ",
24
 
   "++      *** *** ",
25
 
   "+++    ***   ***",
26
 
   "++++   **     **",
27
 
   "+++++  **     **",
28
 
   "++++++  *    ***",
29
 
   "+++++++     *** ",
30
 
   "++++++++   ***  ",
31
 
   "+++++++++ ***   ",
32
 
   "+++++     ***   ",
33
 
   "++ +++          ",
34
 
   "+  +++    ***   ",
35
 
   "    +++   ***   ",
36
 
   "    +++         ",
37
 
   "     +++        ",
38
 
   "     +++        "};
39
 
 
40
 
 
41
 
/* static, but static the less-typing way */
42
 
static ContextHelp * ctxt = 0;
43
 
 
44
 
 
45
 
/* class ContextHelpButton --------------------------------------------- */
46
 
ContextHelpButton::~ContextHelpButton()
47
 
{
48
 
   if ( ctxt && ctxt->buttons ) {
49
 
      ctxt->buttons->take( (void*)this );
50
 
   }
51
 
}
52
 
 
53
 
 
54
 
ContextHelpButton::ContextHelpButton( QWidget* parent, HandBook* book )
55
 
   : QToolButton( parent, "ctxt_help_tb" )
56
 
{
57
 
   ContextHelp::setUp();
58
 
 
59
 
   ctxt->buttons->insert( (void*)this, this );
60
 
   ctxt->hbook = book;
61
 
 
62
 
   QPixmap p( (const char**)context_help_xpm );
63
 
   setIconSet( p );
64
 
   setToggleButton( true );
65
 
   setAutoRaise( true );
66
 
   setFocusPolicy( NoFocus );
67
 
   setTextLabel( "Context Help" );
68
 
 
69
 
   connect( this, SIGNAL( released() ),
70
 
            this, SLOT( mouseReleased() ) );
71
 
}
72
 
 
73
 
 
74
 
void ContextHelpButton::mouseReleased()
75
 
{
76
 
   if ( ctxt->state == ContextHelp::Inactive && isOn() ) {
77
 
      ContextHelp::setUp();
78
 
      QApplication::setOverrideCursor( whatsThisCursor, false );
79
 
      ctxt->state = ContextHelp::Waiting;
80
 
      qApp->installEventFilter( ctxt );
81
 
   }
82
 
}
83
 
 
84
 
 
85
 
 
86
 
 
87
 
/* class ContextHelp --------------------------------------------------- */
88
 
static void qContextHelpCleanup()
89
 
{
90
 
   if ( ctxt ) {
91
 
      delete ctxt;
92
 
      ctxt = 0;
93
 
   }
94
 
}
95
 
 
96
 
 
97
 
ContextHelp::UrlItem::~UrlItem()
98
 
{
99
 
   if ( count ) {
100
 
      VK_DEBUG("Internal error (%d)", count);
101
 
   }
102
 
}
103
 
 
104
 
 
105
 
ContextHelp::ContextHelp()
106
 
   : QObject( 0, "global context help" )
107
 
{
108
 
   ctxt    = this;
109
 
   state   = Inactive;
110
 
   wdict   = new QPtrDict<ContextHelp::UrlItem>;
111
 
   tlw     = new QPtrDict<QWidget>;
112
 
   buttons = new QPtrDict<ContextHelpButton>;
113
 
}
114
 
 
115
 
 
116
 
ContextHelp::~ContextHelp()
117
 
{
118
 
   if ( state == Waiting && qApp )
119
 
      QApplication::restoreOverrideCursor();
120
 
 
121
 
   /* delete the two straight-and-simple dicts */
122
 
   delete tlw;
123
 
   delete buttons;
124
 
  
125
 
   /* then delete the complex one. */
126
 
   QPtrDictIterator<UrlItem> it( *wdict );
127
 
   UrlItem * item;
128
 
   QWidget * w;
129
 
   while( ( item = it.current() ) != 0 ) {
130
 
      w = (QWidget *)it.currentKey();
131
 
      ++it;
132
 
      wdict->take( w );
133
 
      if ( item->deref() )
134
 
         delete item;
135
 
   }
136
 
 
137
 
   delete wdict;
138
 
   ctxt = 0;
139
 
}
140
 
 
141
 
 
142
 
/* removes the Context help associated with the widget.
143
 
   this happens automatically if the widget is destroyed. */
144
 
void ContextHelp::remove( QWidget * widget )
145
 
{
146
 
   setUp();
147
 
   ContextHelp::UrlItem * i = wdict->find( (void *)widget );
148
 
   if ( !i )
149
 
      return;
150
 
 
151
 
   wdict->take( (void *)widget );
152
 
   i->deref();
153
 
   if ( !i->count )
154
 
      delete i;
155
 
}
156
 
 
157
 
 
158
 
bool ContextHelp::eventFilter( QObject * obj, QEvent * ev )
159
 
{
160
 
   switch ( state ) {
161
 
 
162
 
   case Waiting: {
163
 
      if ( ev->type() == QEvent::MouseButtonPress && 
164
 
           obj->isWidgetType() ) {
165
 
         QWidget * w = (QWidget *) obj;
166
 
         if ( ( (QMouseEvent*)ev)->button() == RightButton )
167
 
            return false;   /* ignore RMB */
168
 
         ContextHelp::UrlItem * item = 0;
169
 
         QMouseEvent* me = (QMouseEvent*) ev;
170
 
         QPoint p = me->pos();
171
 
         while ( w && !item ) {
172
 
            if (w->isA("QMenuBar")) {
173
 
               /* If we're a qmenubar, allow event to pass on so menus work... */
174
 
               // TODO: find what menuitem we're sitting on, if any, and get that widget...
175
 
               return false;
176
 
            }
177
 
            item = wdict->find( w );
178
 
            if ( !item ) {
179
 
               p += w->pos();
180
 
               w = w->parentWidget( true );
181
 
            }
182
 
         }
183
 
         shutDown();
184
 
         if ( !item )
185
 
            return true;
186
 
         say( w, item->url );
187
 
         return true;
188
 
      } else if ( ev->type() == QEvent::MouseButtonRelease ) {
189
 
         if ( ( (QMouseEvent*)ev)->button() == RightButton )
190
 
            return false;   /* ignore RMB */
191
 
         return !obj->isWidgetType();
192
 
      } else if ( ev->type() == QEvent::MouseMove ) {
193
 
         return !obj->isWidgetType();
194
 
      } else if ( ev->type() == QEvent::KeyPress ) {
195
 
         QKeyEvent* kev = (QKeyEvent*)ev;
196
 
         if ( kev->key() == Qt::Key_Escape ) {
197
 
            shutDown();
198
 
            return true;
199
 
         } else if ( kev->key() == Key_Menu ||
200
 
                     ( kev->key() == Key_F10 &&
201
 
                       kev->state() == ShiftButton ) ) {
202
 
            /* don't react to these keys: they are used for context
203
 
               menus */
204
 
            return false;
205
 
         } else if ( kev->state() == kev->stateAfter() &&
206
 
                     kev->key() != Key_Meta ) { 
207
 
            /* not a modifier key */
208
 
            shutDown();
209
 
         }
210
 
      } else if ( ev->type() == QEvent::MouseButtonDblClick ) {
211
 
         return true;
212
 
      }
213
 
   } /* break; */
214
 
 
215
 
   case Inactive:
216
 
      break;
217
 
   }
218
 
 
219
 
   return false;
220
 
}
221
 
 
222
 
 
223
 
void ContextHelp::setUp()
224
 
{
225
 
   if ( !ctxt ) {
226
 
      ctxt = new ContextHelp();
227
 
 
228
 
      /* it is necessary to use a post routine, because the destructor
229
 
         deletes pixmaps and other stuff that needs a working X
230
 
         connection under X11. */
231
 
      qAddPostRoutine( qContextHelpCleanup );
232
 
   }
233
 
}
234
 
 
235
 
 
236
 
void ContextHelp::shutDown()
237
 
{
238
 
   if ( state == Waiting ) {
239
 
      QPtrDictIterator<ContextHelpButton> it( *(ctxt->buttons) );
240
 
      ContextHelpButton * b;
241
 
      while( ( b=it.current()) != 0 ) {
242
 
         ++it;
243
 
         b->setOn( false );
244
 
      }
245
 
      QApplication::restoreOverrideCursor();
246
 
      state = Inactive;
247
 
      qApp->removeEventFilter( this );
248
 
   }
249
 
}
250
 
 
251
 
 
252
 
void ContextHelp::say( QWidget* widget, const QString &text )
253
 
{
254
 
   if ( text.isEmpty() || !widget )
255
 
      return;
256
 
 
257
 
   if ( !hbook->isVisible() ) {
258
 
 
259
 
      /* find out where MainWindow is, and park up beside it */
260
 
      QWidget * mw = qApp->mainWidget();
261
 
      int scr = QApplication::desktop()->screenNumber( mw );
262
 
      QRect screen = QApplication::desktop()->screenGeometry( scr );
263
 
 
264
 
      int x;
265
 
      int hw = hbook->width();
266
 
 
267
 
      /* get the global co-ords of the top-left pixel of MainWin */
268
 
      QPoint pos = mw->mapToGlobal( QPoint( 0,0 ) );
269
 
      if ( hw < ( pos.x() - screen.x() ) )
270
 
         x = pos.x() - hw;
271
 
      else 
272
 
         x = pos.x() + mw->width();
273
 
 
274
 
      hbook->move( x, pos.y() );
275
 
      hbook->show();
276
 
   }
277
 
 
278
 
   hbook->raise();
279
 
   hbook->openUrl( text );
280
 
}
281
 
 
282
 
 
283
 
void ContextHelp::cleanupWidget() 
284
 
{
285
 
   const QObject* obj = sender();
286
 
   if ( obj->isWidgetType() ) {   /* sanity check */
287
 
      remove( (QWidget*)obj );
288
 
   }
289
 
}
290
 
 
291
 
 
292
 
void ContextHelp::newItem( QWidget* widget, const QString& url )
293
 
{
294
 
   UrlItem* item = wdict->find( (void *)widget );
295
 
   if ( item ) {
296
 
      remove( widget );
297
 
   }
298
 
   item = new UrlItem;
299
 
   wdict->insert( (void*)widget, item );
300
 
   QWidget* t = widget->topLevelWidget();
301
 
   if ( !tlw->find( (void*)t ) ) {
302
 
      tlw->insert( (void*)t, t );
303
 
      t->installEventFilter( this );
304
 
   }
305
 
 
306
 
   connect( widget, SIGNAL(destroyed()), 
307
 
            this,   SLOT(cleanupWidget()) );
308
 
 
309
 
   item->url = url;
310
 
}
311
 
 
312
 
 
313
 
/* adds url as context help for this widget.  
314
 
   the text is destroyed if the widget is later destroyed, so it need
315
 
   not be explicitly removed. */
316
 
void ContextHelp::add( QWidget* widget, const QString& url )
317
 
{
318
 
   vk_assert( widget != NULL );
319
 
   if ( !url.isEmpty() ) {
320
 
      setUp();
321
 
      ctxt->newItem( widget, url );
322
 
   }
323
 
}
324