~ubuntu-branches/debian/squeeze/djvulibre/squeeze

« back to all changes in this revision

Viewing changes to gui/shared/QT/qd_search_dialog.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Barak A. Pearlmutter
  • Date: 2004-11-01 16:49:49 UTC
  • Revision ID: james.westby@ubuntu.com-20041101164949-fm4bl2hmkvkseoqw
Tags: upstream-3.5.14
ImportĀ upstreamĀ versionĀ 3.5.14

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//C-  -*- C++ -*-
 
2
//C- -------------------------------------------------------------------
 
3
//C- DjVuLibre-3.5
 
4
//C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
 
5
//C- Copyright (c) 2001  AT&T
 
6
//C-
 
7
//C- This software is subject to, and may be distributed under, the
 
8
//C- GNU General Public License, Version 2. The license should have
 
9
//C- accompanied the software or you may obtain a copy of the license
 
10
//C- from the Free Software Foundation at http://www.fsf.org .
 
11
//C-
 
12
//C- This program is distributed in the hope that it will be useful,
 
13
//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
//C- GNU General Public License for more details.
 
16
//C- 
 
17
//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library
 
18
//C- distributed by Lizardtech Software.  On July 19th 2002, Lizardtech 
 
19
//C- Software authorized us to replace the original DjVu(r) Reference 
 
20
//C- Library notice by the following text (see doc/lizard2002.djvu):
 
21
//C-
 
22
//C-  ------------------------------------------------------------------
 
23
//C- | DjVu (r) Reference Library (v. 3.5)
 
24
//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
 
25
//C- | The DjVu Reference Library is protected by U.S. Pat. No.
 
26
//C- | 6,058,214 and patents pending.
 
27
//C- |
 
28
//C- | This software is subject to, and may be distributed under, the
 
29
//C- | GNU General Public License, Version 2. The license should have
 
30
//C- | accompanied the software or you may obtain a copy of the license
 
31
//C- | from the Free Software Foundation at http://www.fsf.org .
 
32
//C- |
 
33
//C- | The computer code originally released by LizardTech under this
 
34
//C- | license and unmodified by other parties is deemed "the LIZARDTECH
 
35
//C- | ORIGINAL CODE."  Subject to any third party intellectual property
 
36
//C- | claims, LizardTech grants recipient a worldwide, royalty-free, 
 
37
//C- | non-exclusive license to make, use, sell, or otherwise dispose of 
 
38
//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the 
 
39
//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU 
 
40
//C- | General Public License.   This grant only confers the right to 
 
41
//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to 
 
42
//C- | the extent such infringement is reasonably necessary to enable 
 
43
//C- | recipient to make, have made, practice, sell, or otherwise dispose 
 
44
//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to 
 
45
//C- | any greater extent that may be necessary to utilize further 
 
46
//C- | modifications or combinations.
 
47
//C- |
 
48
//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
 
49
//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 
50
//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
 
51
//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 
52
//C- +------------------------------------------------------------------
 
53
// 
 
54
// $Id: qd_search_dialog.cpp,v 1.13 2004/07/07 19:23:36 leonb Exp $
 
55
// $Name: release_3_5_14 $
 
56
 
 
57
#ifdef HAVE_CONFIG_H
 
58
# include "config.h"
 
59
#endif
 
60
#if NEED_GNUG_PRAGMAS
 
61
# pragma implementation
 
62
#endif
 
63
 
 
64
#include "DjVuAnno.h"
 
65
#include "DjVuFile.h"
 
66
#include "DataPool.h"
 
67
#include "ByteStream.h"
 
68
 
 
69
#include "qd_search_dialog.h"
 
70
 
 
71
#include "debug.h"
 
72
#include "qlib.h"
 
73
 
 
74
#include <qlayout.h>
 
75
#include <qpushbutton.h>
 
76
#include <qlabel.h>
 
77
#include <qcheckbox.h>
 
78
#include <qlineedit.h>
 
79
#include <qmessagebox.h>
 
80
#include <qapplication.h>
 
81
 
 
82
bool    QDSearchDialog::all_pages=true;
 
83
bool    QDSearchDialog::case_sensitive=false;
 
84
bool    QDSearchDialog::whole_word=false;
 
85
bool    QDSearchDialog::search_backwards=false;
 
86
 
 
87
 
 
88
static GList<DjVuTXT::Zone*>
 
89
search_string(DjVuTXT *txt, QString dat, int &pfrom, 
 
90
              bool fwd, bool casep, bool wordp)
 
91
{
 
92
  GList<DjVuTXT::Zone*> res;
 
93
  // Access utf8 string
 
94
  GUTF8String utext = txt->textUTF8;
 
95
  QString qtext = QStringFromGString(utext);
 
96
  // Normalize dat
 
97
  dat = dat.stripWhiteSpace();
 
98
  if (! dat.length())
 
99
    return res;
 
100
  // Normalize from
 
101
  int from = pfrom;
 
102
  if (fwd)
 
103
    {
 
104
      if (from < 0)
 
105
        from = 0;
 
106
      else
 
107
        from += 1;
 
108
    }
 
109
  else
 
110
    {
 
111
      if (from < 0 || from >= (int)qtext.length())
 
112
        from = qtext.length() - 1;
 
113
      else
 
114
        from -= 1;
 
115
    }
 
116
  // Search
 
117
  int found;
 
118
  int foundx;
 
119
  for(;;)
 
120
    {
 
121
      if (fwd)
 
122
        found = qtext.find(dat, from, casep);
 
123
      else
 
124
        found = qtext.findRev(dat, from, casep);
 
125
      if (found < 0)
 
126
        return res;
 
127
      foundx = found + dat.length();
 
128
      if (!wordp)
 
129
        break;
 
130
      if (found==0 || !qtext[found-1].isLetterOrNumber())
 
131
        if (foundx==(int)qtext.length() || !qtext[foundx].isLetterOrNumber())
 
132
          break;
 
133
      if (fwd) {
 
134
        if (++pfrom >= (int)qtext.length())
 
135
          return res;
 
136
      } else {
 
137
        if (--pfrom < 0)
 
138
          return res;
 
139
      }
 
140
    }
 
141
  // Compute indices into utf8 string
 
142
  int ufound = -1;
 
143
  int ufoundx = -1;
 
144
  const char *ctext = (const char*)utext;
 
145
  int qi = 0;
 
146
  int ui = 0;
 
147
  while (ctext[ui] && ufoundx<0)
 
148
    {
 
149
      if (ufound<0 && qi == found)
 
150
        ufound = ui;
 
151
      if (ufoundx<0 && qi == foundx)
 
152
        ufoundx = ui;
 
153
      ui += 1;
 
154
      if ( (ctext[ui] & 0xc0) != 0x80)
 
155
        qi += 1;
 
156
    }
 
157
  // Retrieve zones
 
158
  if (ufoundx > ufound && ufound >= 0) 
 
159
    {
 
160
      txt->page_zone.find_zones(res, ufound, ufoundx);
 
161
      pfrom = found;
 
162
    }
 
163
  return res;
 
164
}
 
165
 
 
166
 
 
167
void
 
168
QDSearchDialog::slotSearch(void)
 
169
{
 
170
   if (in_search)
 
171
   {
 
172
      stop=true;
 
173
      return;
 
174
   }
 
175
   
 
176
   if (text->text()=="") return;
 
177
   
 
178
   try
 
179
   {
 
180
      bool fwd=!back_butt->isChecked();
 
181
      in_search=true;
 
182
      stop=false;
 
183
      search_butt->setText(tr("&Stop"));
 
184
      text->setEnabled(FALSE);
 
185
      clear_butt->setEnabled(FALSE);
 
186
 
 
187
         // 'asked_once' is useful for one-page searches
 
188
      bool asked_once=false;
 
189
         // 'start_page_num' is for the document search
 
190
      int start_page_num=page_num;
 
191
         // Will be true if no TXT chunks have been found
 
192
      bool no_txt=true;
 
193
 
 
194
         // We want to place 'anno' here because to keep it alive as long
 
195
         // as zone_list is alive.
 
196
      GP<DjVuText> anno;
 
197
      GList<DjVuTXT::Zone *> zone_list;
 
198
      while(true)
 
199
      {
 
200
         GP<DjVuFile> page_file=doc->get_djvu_file(page_num);
 
201
 
 
202
         if (!page_file->is_all_data_present())
 
203
         {
 
204
            GP<DataPool> pool=page_file->get_init_data_pool();
 
205
            int last_done=-1;
 
206
               // Wait until we have data for this file
 
207
            while(!stop && !page_file->is_all_data_present())
 
208
            {
 
209
               int done=5*(20*pool->get_size()/pool->get_length());
 
210
               if (done!=last_done)
 
211
               {
 
212
                 QString buffer=tr("Loading page %1: %2%...")
 
213
                   .arg(page_num+1)
 
214
                   .arg(done);
 
215
                 status_label->setText(buffer);
 
216
                 last_done=done;
 
217
               }
 
218
               qApp->processEvents(100);
 
219
            }
 
220
         }
 
221
         if (stop)
 
222
         {
 
223
            page_num=seen_page_num;
 
224
            break;
 
225
         }
 
226
         
 
227
         GP<ByteStream> str=page_file->get_text();
 
228
         if (str)
 
229
         {
 
230
            str->seek(0);
 
231
            anno=DjVuText::create();
 
232
            anno->decode(str);
 
233
            GP<DjVuTXT> txt=anno->txt;
 
234
            if (txt)
 
235
              {
 
236
               no_txt = false;
 
237
               zone_list = search_string(txt, text->text(), page_pos,
 
238
                                         fwd, case_butt->isChecked(),
 
239
                                         whole_word_butt->isChecked());
 
240
               if (zone_list.size()) 
 
241
                 break;
 
242
            }
 
243
         }
 
244
            // Didn't find anything. Switch to the next page or give up
 
245
         int pages_num=doc->get_pages_num();
 
246
         if (!all_pages_butt->isChecked() ||
 
247
             fwd && page_num>=pages_num-1 ||
 
248
             !fwd && page_num==0)
 
249
         {
 
250
            if (asked_once)
 
251
            {
 
252
               page_num=seen_page_num;
 
253
               break;
 
254
            } 
 
255
            else
 
256
            {
 
257
               asked_once=true;
 
258
               QString msg;
 
259
               if (all_pages_butt->isChecked())
 
260
                 {
 
261
                   if (fwd)
 
262
                     msg=tr("End of document reached. "
 
263
                            "Continue from the beginning?");
 
264
                   else
 
265
                     msg=tr("Beginning of document reached. "
 
266
                            "Continue from the end?");
 
267
                 }
 
268
               else
 
269
                 {
 
270
                   if (fwd)
 
271
                     msg=tr("End of page reached. "
 
272
                            "Continue from the beginning?");
 
273
                   else
 
274
                     msg=tr("Beginning of page reached. "
 
275
                            "Continue from the end?");
 
276
                 }
 
277
 
 
278
               if (QMessageBox::information(this, "DjVu", msg, 
 
279
                                            tr("&Yes"), tr("&No"))==0)
 
280
               {
 
281
                  if (all_pages_butt->isChecked())
 
282
                  {
 
283
                     if (fwd) 
 
284
                       page_num=-1;
 
285
                     else 
 
286
                       page_num=doc->get_pages_num();
 
287
                  } 
 
288
                  else
 
289
                  {
 
290
                     if (fwd) 
 
291
                       page_num--;
 
292
                     else 
 
293
                       page_num++;
 
294
                  }
 
295
               } 
 
296
               else
 
297
               {
 
298
                  page_num=seen_page_num;
 
299
                  break;
 
300
               }
 
301
            }
 
302
         }
 
303
            // Going to the next page (or rewinding to the other side of
 
304
            // this page if asked to)
 
305
         if (fwd)
 
306
         {
 
307
            page_num++;
 
308
            page_pos = -1;
 
309
         } 
 
310
         else
 
311
         {
 
312
            page_num--;
 
313
            page_pos = -1;
 
314
         }
 
315
 
 
316
         {
 
317
           QString mesg=tr("Page ")+QString::number(page_num+1);
 
318
           status_label->setText(mesg);
 
319
         }
 
320
 
 
321
            // Wrapped back and returned
 
322
         if (all_pages_butt->isChecked() && page_num==start_page_num)
 
323
           {
 
324
             page_num=seen_page_num;
 
325
             break;
 
326
           }
 
327
      } // while(true)
 
328
 
 
329
      emit sigDisplaySearchResults(seen_page_num=page_num, zone_list);
 
330
      if (zone_list.size()==0)
 
331
      {
 
332
         if (no_txt)
 
333
         {
 
334
           if (all_pages_butt->isChecked())
 
335
             showMessage(this, tr("DjVu Search Failed"),
 
336
                         tr("After looking through every page of this document,\n"
 
337
                            "we have found that none of them contain\n"
 
338
                            "textual information. This means that either the document\n"
 
339
                            "creator did not run an OCR engine on this document,\n"
 
340
                            "or the OCR engine did not recognize any text.\n"
 
341
                            "\n"
 
342
                            "The search is impossible."), 
 
343
                         true, false, true);
 
344
           else
 
345
             showMessage(this, tr("DjVu Search Failed"),
 
346
                         tr("This page does not contain textual information,\n"
 
347
                            "which means that either the creator of this document\n" 
 
348
                            "did not run an OCR engine on it, or the OCR engine\n"
 
349
                            "did not recognize any text on this page.\n"
 
350
                            "\n"
 
351
                            "The search is impossible."), 
 
352
                         true, false, true);
 
353
         } else 
 
354
           showInfo(this, "DjVu", tr("Search string not found"));
 
355
      }
 
356
      
 
357
      in_search=false;
 
358
      search_butt->setText(tr("&Find"));
 
359
      {
 
360
        QString mesg=tr("Page ")+QString::number(page_num+1);
 
361
        status_label->setText(mesg);
 
362
      }
 
363
      text->setEnabled(TRUE);
 
364
      clear_butt->setEnabled(TRUE);
 
365
   } 
 
366
   catch(const GException & exc)
 
367
   {
 
368
      status_label->hide();
 
369
      in_search=false;
 
370
      search_butt->setText(tr("&Find"));
 
371
      {
 
372
        QString mesg=tr("Page ")+QString::number(page_num+1);
 
373
        status_label->setText(mesg);
 
374
      }
 
375
      text->setEnabled(TRUE);
 
376
      clear_butt->setEnabled(TRUE);
 
377
      showError(this, exc);
 
378
   }
 
379
}
 
380
 
 
381
void
 
382
QDSearchDialog::slotSetPageNum(int page_num_)
 
383
{
 
384
   seen_page_num=page_num_;
 
385
 
 
386
   if (!in_search)
 
387
   {
 
388
      if (page_num!=page_num_)
 
389
         page_pos = -1;
 
390
      page_num = seen_page_num;
 
391
   }
 
392
   
 
393
   QString mesg=tr("Page ")+QString::number(page_num+1);
 
394
   status_label->setText(mesg);
 
395
}
 
396
 
 
397
void
 
398
QDSearchDialog::slotTextChanged(const QString & qtext)
 
399
{
 
400
   const char * const str=qtext;
 
401
   search_butt->setEnabled(str && strlen(str));
 
402
}
 
403
 
 
404
void
 
405
QDSearchDialog::done(int rc)
 
406
{
 
407
   stop=true;
 
408
   all_pages=all_pages_butt->isChecked();
 
409
   case_sensitive=case_butt->isChecked();
 
410
   whole_word=whole_word_butt->isChecked();
 
411
   search_backwards=back_butt->isChecked();
 
412
   emit sigDone();
 
413
   QDialog::done(rc);
 
414
}
 
415
 
 
416
QDSearchDialog::QDSearchDialog(int page_num_, const GP<DjVuDocument> & doc_,
 
417
                               QWidget * parent, const char * name, bool modal) :
 
418
      QeDialog(parent, name, modal), page_num(page_num_), doc(doc_)
 
419
{
 
420
   seen_page_num = page_num;
 
421
   page_pos = -1;
 
422
   in_search=false;
 
423
   
 
424
   setCaption(tr("DjVu: Find"));
 
425
   
 
426
   QWidget * start=startWidget();
 
427
   QLabel * label;
 
428
   
 
429
   QVBoxLayout * vlay=new QVBoxLayout(start, 10, 10);
 
430
 
 
431
   QHBoxLayout * hlay=new QHBoxLayout(10);
 
432
   vlay->addLayout(hlay);
 
433
   label=new QLabel(tr("Find: "), start);
 
434
   hlay->addWidget(label);
 
435
   text=new QLineEdit(start, "search_text");
 
436
   label->setBuddy(text);
 
437
   hlay->addWidget(text, 1);
 
438
 
 
439
   hlay=new QHBoxLayout(10);
 
440
   vlay->addLayout(hlay);
 
441
 
 
442
   all_pages_butt=new QCheckBox(tr("Search &all pages"), start, "all_pages_butt");
 
443
   if (doc->get_pages_num()>1)
 
444
      all_pages_butt->setChecked(all_pages);
 
445
   else
 
446
   {
 
447
      all_pages_butt->setChecked(TRUE);
 
448
      all_pages_butt->setEnabled(FALSE);
 
449
   }
 
450
   hlay->addWidget(all_pages_butt);
 
451
   hlay->addStretch(1);
 
452
   
 
453
   case_butt=new QCheckBox(tr("&Case sensitive"), start, "case_butt");
 
454
   case_butt->setChecked(case_sensitive);
 
455
   hlay->addWidget(case_butt);
 
456
   hlay->addStretch(1);
 
457
 
 
458
   whole_word_butt=new QCheckBox(tr("&Whole word"), start, "whole_word_butt");
 
459
   whole_word_butt->setChecked(whole_word);
 
460
   hlay->addWidget(whole_word_butt);
 
461
   hlay->addStretch(1);
 
462
 
 
463
   back_butt=new QCheckBox(tr("Search &backwards"), start, "back_butt");
 
464
   back_butt->setChecked(search_backwards);
 
465
   hlay->addWidget(back_butt);
 
466
   
 
467
   QHBoxLayout * butt_lay=new QHBoxLayout(10);
 
468
   vlay->addLayout(butt_lay);
 
469
   status_label=new QLabel(tr("Loading page WWWWWWW"), start);
 
470
   status_label->setMinimumSize(status_label->sizeHint());
 
471
   {
 
472
     QString mesg=tr("Page ")+QString::number(page_num+1);
 
473
     status_label->setText(mesg);
 
474
   }
 
475
   butt_lay->addWidget(status_label);
 
476
   butt_lay->addStretch(1);
 
477
   search_butt=new QPushButton(tr("&Find"), start, "search_butt");
 
478
   search_butt->setEnabled(FALSE);
 
479
   butt_lay->addWidget(search_butt);
 
480
   clear_butt=new QPushButton(tr("&Clear"), start, "clear_butt");
 
481
   butt_lay->addWidget(clear_butt);
 
482
   QPushButton * close_butt=new QPushButton(tr("C&lose"), start, "close_butt");
 
483
   butt_lay->addWidget(close_butt);
 
484
   search_butt->setDefault(TRUE);
 
485
 
 
486
   connect(search_butt, SIGNAL(clicked(void)), this, SLOT(slotSearch(void)));
 
487
   connect(clear_butt, SIGNAL(clicked(void)), text, SLOT(clear(void)));
 
488
   connect(close_butt, SIGNAL(clicked(void)), this, SLOT(reject(void)));
 
489
 
 
490
   connect(text, SIGNAL(textChanged(const QString &)),
 
491
           this, SLOT(slotTextChanged(const QString &)));
 
492
}