]> git.lyx.org Git - lyx.git/blob - src/frontends/gnome/FormCitation.C
John's KDE FormRef patch
[lyx.git] / src / frontends / gnome / FormCitation.C
1 // -*- C++ -*-
2 /* This file is part of
3  * ====================================================== 
4  *
5  *           LyX, The Document Processor
6  *
7  *           Copyright 2000 The LyX Team.
8  *
9  * ======================================================
10  */
11
12 #include <config.h>
13
14 #include <algorithm>
15
16 #ifdef __GNUG__
17 #pragma implementation
18 #endif
19
20
21 #include "gettext.h"
22 #include "Dialogs.h"
23 #include "FormCitation.h"
24 #include "LyXView.h"
25 #include "buffer.h"
26 #include "lyxfunc.h"
27 #include "support/filetools.h"
28
29 extern "C" {
30 #include "diainsertcitation_interface.h"
31 #include "support.h"
32 }
33
34 #include <gtk--/scrolledwindow.h>
35 #include <gnome--/pixmap.h>
36
37 using std::vector;
38 using std::pair;
39 using std::max;
40 using std::min;
41 using std::find;
42
43 #ifdef SIGC_CXX_NAMESPACES
44 using SigC::slot;
45 using SigC::bind;
46 #endif
47
48 // gnome configuration file keys
49 #define LOCAL_CONFIGURE_PREFIX "FormCitation"
50
51 #define CONF_DIALOG_WIDTH               "width"
52 #define CONF_DIALOG_WIDTH_DEFAULT       "=550"
53
54 #define CONF_DIALOG_HEIGTH              "heigth"
55 #define CONF_DIALOG_HEIGTH_DEFAULT      "=550"
56
57 #define CONF_PANE_INFO                  "paneinfo"
58 #define CONF_PANE_INFO_DEFAULT          "=300"
59
60 #define CONF_PANE_KEY                   "panekey"
61 #define CONF_PANE_KEY_DEFAULT           "=225"
62
63 #define CONF_COLUMN                     "column"
64 #define CONF_COLUMN_DEFAULT             "=50"
65
66
67 FormCitation::FormCitation(LyXView * lv, Dialogs * d)
68         : lv_(lv), d_(d), u_(0), h_(0), ih_(0), inset_(0), dialog_(NULL)
69 {
70   // let the dialog be shown
71   // These are permanent connections so we won't bother
72   // storing a copy because we won't be disconnecting.
73   d->showCitation.connect(slot(this, &FormCitation::showInset));
74   d->createCitation.connect(slot(this, &FormCitation::createInset));
75 }
76
77
78 FormCitation::~FormCitation()
79 {
80   hide();
81 }
82
83 void FormCitation::showInset( InsetCommand * const inset )
84 {
85   if( dialog_!=NULL || inset == 0 ) return;
86   
87   inset_ = inset;
88   ih_ = inset_->hide.connect(slot(this, &FormCitation::hide));
89   
90   params = inset->params();
91   show();
92 }
93
94
95 void FormCitation::createInset( string const & arg )
96 {
97   if( dialog_!=NULL ) return;
98   
99   params.setFromString( arg );
100   show();
101 }
102
103 static
104 void parseBibTeX(string data,
105                  string const & findkey,
106                  string & keyvalue)
107 {
108   unsigned int i;
109
110   keyvalue = "";
111   
112   for (i=0; i<data.length(); ++i)
113     if (data[i]=='\n' || data[i]=='\t')
114       data[i] = ' ';
115   
116   data = frontStrip(data);
117   while (!data.empty()
118          && data[0]!='='
119          && (data.find(' ')!=string::npos ||
120              data.find('=')!=string::npos) )
121     {
122       unsigned int keypos = min(data.find(' '), data.find('='));
123       string key = lowercase( data.substr(0, keypos) );
124       string value, tmp;
125       char enclosing;
126       
127       data = data.substr(keypos, data.length()-1);
128       data = frontStrip(strip(data));
129       if (data.length() > 1 && data[0]=='=')
130         {
131           data = frontStrip(data.substr(1, data.length()-1));
132           if (!data.empty())
133             {
134               keypos = 1;
135               if (data[0]=='{') enclosing = '}';
136               else if (data[0]=='"') enclosing = '"';
137               else { keypos=0; enclosing=' '; }
138
139               if (keypos &&
140                   data.find(enclosing)!=string::npos &&
141                   data.length()>1)
142                 {
143                   tmp = data.substr(keypos, data.length()-1);
144                   while (tmp.find('{')!=string::npos &&
145                          tmp.find('}')!=string::npos &&
146                          tmp.find('{') < tmp.find('}') &&
147                          tmp.find('{') < tmp.find(enclosing))
148                     {
149                       keypos += tmp.find('{')+1;
150                       tmp = data.substr(keypos, data.length()-1);
151                       keypos += tmp.find('}')+1;
152                       tmp = data.substr(keypos, data.length()-1);
153                     }
154
155                   if (tmp.find(enclosing)==string::npos) return;
156                   else
157                     {
158                       keypos += tmp.find(enclosing);
159                       tmp = data.substr(keypos, data.length()-1);
160                     }
161
162                   value = data.substr(1, keypos-1);
163
164                   if (keypos+1<data.length()-1) data = frontStrip(data.substr(keypos+1, data.length()-1));
165                   else data = "";
166                 }
167               else if (!keypos &&
168                        (data.find(' ') ||
169                         data.find(','))
170                        ) // numerical value ?
171                 {
172                   keypos = data.length()-1;
173                   if (data.find(' ')!=string::npos) keypos = data.find(' ');
174                   if (data.find(',')!=string::npos &&
175                       keypos > data.find(','))
176                     keypos = data.find(',');
177
178                   value = data.substr(0, keypos);
179                   
180                   if (keypos+1<data.length()-1) data = frontStrip(data.substr(keypos+1, data.length()-1));
181                   else data = "";
182                 }
183               else return;
184
185               if (findkey == key) { keyvalue = value; return; } 
186
187               data = frontStrip(frontStrip(data,','));
188             }
189         }
190       else return;
191     }
192 }
193
194 void FormCitation::show()
195 {
196   if (!dialog_)
197     {
198       GtkWidget * pd = create_DiaInsertCitation();
199
200       dialog_ = Gtk::wrap(pd);
201       clist_selected_ = Gtk::wrap( GTK_CLIST( lookup_widget(pd, "clist_selected") ) );
202       info_ = Gtk::wrap( GNOME_LESS( lookup_widget(pd, "info") ) );
203       text_after_ = Gtk::wrap( GNOME_ENTRY( lookup_widget(pd, "text_after") ) );
204       search_text_ = Gtk::wrap( GNOME_ENTRY( lookup_widget(pd, "search_text") ) );
205         
206       button_select_ = Gtk::wrap( GTK_BUTTON( lookup_widget(pd, "button_select") ) );
207       button_unselect_ = Gtk::wrap( GTK_BUTTON( lookup_widget(pd, "button_unselect") ) );
208       button_up_ = Gtk::wrap( GTK_BUTTON( lookup_widget(pd, "button_up") ) );
209       button_down_ = Gtk::wrap( GTK_BUTTON( lookup_widget(pd, "button_down") ) );
210       button_search_ = Gtk::wrap( GTK_BUTTON( lookup_widget(pd, "button_search") ) );
211
212       paned_info_ = Gtk::wrap( GTK_PANED( lookup_widget(pd, "vpaned_info") ) );
213       paned_key_ = Gtk::wrap( GTK_PANED( lookup_widget(pd, "hpaned_key") ) );
214       box_keys_ =  Gtk::wrap( GTK_BOX( lookup_widget(pd, "vbox_keys") ) );
215
216       b_ok = Gtk::wrap( GTK_BUTTON( lookup_widget(pd, "button_ok") ) );
217       b_cancel = Gtk::wrap( GTK_BUTTON( lookup_widget(pd, "button_cancel") ) );
218
219       // constructing and packing CList
220       vector<string> colnames;
221       colnames.push_back("INVISIBLE");
222       colnames.push_back(N_("Key"));
223       colnames.push_back(N_("Author(s)"));
224       colnames.push_back(N_("Title"));
225       colnames.push_back(N_("Year"));
226       colnames.push_back(N_("Journal"));
227       clist_bib_ = manage( new Gtk::CList(colnames) );
228       clist_bib_->column(0).set_visiblity(false);
229       
230       Gtk::ScrolledWindow * sw_ = Gtk::wrap( GTK_SCROLLED_WINDOW( lookup_widget(pd, "scrolledwindow_bib") ) );
231       sw_->add(*clist_bib_);
232
233       // populating buttons with icons
234       Gnome::Pixmap * p;
235       p = Gtk::wrap( GNOME_PIXMAP( gnome_stock_pixmap_widget(NULL, GNOME_STOCK_PIXMAP_BACK) ) ); 
236       button_select_->add(*p);
237       p = Gtk::wrap( GNOME_PIXMAP( gnome_stock_pixmap_widget(NULL, GNOME_STOCK_PIXMAP_TRASH) ) ); 
238       button_unselect_->add(*p);
239       p = Gtk::wrap( GNOME_PIXMAP( gnome_stock_pixmap_widget(NULL, GNOME_STOCK_PIXMAP_UP) ) ); 
240       button_up_->add(*p);
241       p = Gtk::wrap( GNOME_PIXMAP( gnome_stock_pixmap_widget(NULL, GNOME_STOCK_PIXMAP_DOWN) ) ); 
242       button_down_->add(*p);
243       
244
245       // connecting signals
246       clist_bib_->click_column.connect(slot(this, &FormCitation::sortBibList));
247
248       clist_selected_->select_row.connect(bind(slot(this, &FormCitation::selection_toggled),
249                                                true, true));
250       clist_bib_->select_row.connect(bind(slot(this, &FormCitation::selection_toggled),
251                                           true, false));
252       clist_selected_->unselect_row.connect(bind(slot(this, &FormCitation::selection_toggled),
253                                                  false, true));
254       clist_bib_->unselect_row.connect(bind(slot(this, &FormCitation::selection_toggled),
255                                             false, false));
256       
257       button_select_->clicked.connect(slot(this, &FormCitation::newCitation));
258       button_unselect_->clicked.connect(slot(this, &FormCitation::removeCitation));
259       button_up_->clicked.connect(slot(this, &FormCitation::moveCitationUp));
260       button_down_->clicked.connect(slot(this, &FormCitation::moveCitationDown));
261
262       search_text_->get_entry()->activate.connect(slot(this, &FormCitation::search));
263       button_search_->clicked.connect(slot(this, &FormCitation::search));
264       
265       b_ok->clicked.connect(slot(this, &FormCitation::apply));
266       b_ok->clicked.connect(dialog_->destroy.slot());
267       b_cancel->clicked.connect(dialog_->destroy.slot());
268       dialog_->destroy.connect(slot(this, &FormCitation::free));
269
270       u_ = d_->updateBufferDependent.connect(slot(this, &FormCitation::update));
271       h_ = d_->hideBufferDependent.connect(slot(this, &FormCitation::hide));
272
273       // setting sizes of the widgets
274       string path;
275       string w, h;
276       path  += PACKAGE "/" LOCAL_CONFIGURE_PREFIX;
277       w = path + "/" + CONF_DIALOG_WIDTH + CONF_DIALOG_WIDTH_DEFAULT;
278       h = path + "/" + CONF_DIALOG_HEIGTH + CONF_DIALOG_HEIGTH_DEFAULT;
279       dialog_->set_usize(gnome_config_get_int(w.c_str()),
280                          gnome_config_get_int(h.c_str()));
281
282       w = path + "/" + CONF_PANE_INFO + CONF_PANE_INFO_DEFAULT;
283       paned_info_->set_position( gnome_config_get_int(w.c_str()) );
284
285       w = path + "/" + CONF_PANE_KEY + CONF_PANE_KEY_DEFAULT;
286       paned_key_->set_position( gnome_config_get_int(w.c_str()) );
287
288       int i, sz;
289       for (i = 0, sz = clist_bib_->columns().size(); i < sz; ++i)
290         {
291           w = path + "/" + CONF_COLUMN + "_" + tostr(i) + CONF_COLUMN_DEFAULT;
292           clist_bib_->column(i).set_width( gnome_config_get_int(w.c_str()) );
293         }
294       
295       // ready to go...
296       if (!dialog_->is_visible()) dialog_->show_all();
297
298       update();  // make sure its up-to-date
299     }
300   else
301     {
302       Gdk_Window dialog_win(dialog_->get_window());
303       dialog_win.raise();
304     }
305 }
306
307 void FormCitation::addItemToBibList(int i)
308 {
309   vector<string> r;
310   string key, info;
311   string val;
312
313   key = bibkeys[i];
314   info = bibkeysInfo[i];
315
316   // don't change the order of these first two items:
317   // callback functions depend on the data stored in the first column (its hided)
318   // and in the second column (shown to user)
319   r.push_back( tostr(i) ); 
320   r.push_back( key );
321   
322   // this can be changed (configured by user?)
323   parseBibTeX( info, "author", val);  r.push_back(val);
324   parseBibTeX( info, "title", val);  r.push_back(val);
325   parseBibTeX( info, "year", val);  r.push_back(val);
326   parseBibTeX( info, "journal", val);  r.push_back(val);
327   
328   clist_bib_->rows().push_back(r);
329 }
330
331 void FormCitation::update()
332 {
333   bibkeys.clear();
334   bibkeysInfo.clear();
335
336   clist_selected_->rows().clear();
337   clist_bib_->rows().clear();
338
339   // populating clist_bib_
340   clist_bib_->freeze();
341
342   vector<pair<string,string> > blist =
343     lv_->buffer()->getBibkeyList();
344
345   int i, sz;
346   for ( i = 0, sz = blist.size(); i < sz; ++i )
347     {
348       bibkeys.push_back(blist[i].first);
349       bibkeysInfo.push_back(blist[i].second);
350     }
351
352   blist.clear();
353
354   for ( i = 0, sz = bibkeys.size(); i < sz; ++i )
355     addItemToBibList(i);
356
357   clist_bib_->sort();
358   clist_bib_->thaw();
359   // clist_bib_: done
360
361   // populating clist_selected_
362   vector<string> r;
363   string tmp, keys( params.getContents() );
364   keys = frontStrip( split(keys, tmp, ',') );
365   while( !tmp.empty() )
366     {
367       r.clear();
368       r.push_back(tmp);
369       clist_selected_->rows().push_back(r);
370
371       keys = frontStrip( split(keys, tmp, ',') );
372     }
373   // clist_selected_: done
374
375   text_after_->get_entry()->set_text(params.getOptions());
376   
377   updateButtons();
378 }
379
380 void FormCitation::updateButtons()
381 {
382   bool sens;
383
384   sens = (clist_selected_->selection().size()>0);
385   button_unselect_->set_sensitive(sens);
386   button_up_->set_sensitive(sens &&
387                             clist_selected_->selection().operator[](0).get_row_num()>0);
388   button_down_->set_sensitive(sens &&
389                               clist_selected_->selection().operator[](0).get_row_num() <
390                               clist_selected_->rows().size()-1);
391
392   sens = (clist_bib_->selection().size()>0);
393   button_select_->set_sensitive( (clist_bib_->selection().size()>0) );
394 }
395
396 void FormCitation::selection_toggled(gint            row,
397                                      gint            ,//column,
398                                      GdkEvent        * ,//event,
399                                      bool selected,
400                                      bool citeselected)
401 {
402   if (selected)
403     {
404       bool keyfound = false;
405       string info;
406       if (citeselected)
407         {
408           // lookup the record with the same key in bibkeys and show additional Info
409           int i;
410           int sz = bibkeys.size();
411           string key = clist_selected_->cell(row,0).get_text();
412           for (i=0; !keyfound && i<sz; ++i)
413             if (bibkeys[i] == key)
414               {
415                 info = bibkeysInfo[i];
416                 keyfound = true;
417               }   
418         }
419       else
420         {
421           // the first column in clist_bib_ contains the index
422           keyfound = true;
423           info = bibkeysInfo[ strToInt(clist_bib_->cell(row,0).get_text()) ];
424         }
425
426       if (keyfound)
427         info_->show_string(info);
428       else
429         info_->show_string(N_("--- No such key in the database ---"));
430     }
431   else
432     {
433       info_->show_string("");
434     }
435   updateButtons();
436 }
437
438 void FormCitation::removeCitation()
439 {
440   clist_selected_->rows().remove(clist_selected_->selection().operator[](0));
441   updateButtons();
442 }
443
444 void FormCitation::moveCitationUp()
445 {
446   int i = clist_selected_->selection().operator[](0).get_row_num();
447   clist_selected_->swap_rows( i-1, i );
448   clist_selected_->row(i-1).select();
449   updateButtons();
450 }
451
452 void FormCitation::moveCitationDown()
453 {
454   int i = clist_selected_->selection().operator[](0).get_row_num();
455   clist_selected_->swap_rows( i+1, i );
456   clist_selected_->row(i+1).select();
457   updateButtons();
458 }
459
460 void FormCitation::newCitation()
461 {
462   // citation key is in the first column of clist_bib_ list
463   vector<string> r;
464   r.push_back( clist_bib_->selection().operator[](0).operator[](1).get_text() );
465   clist_selected_->rows().push_back(r);
466   clist_selected_->row( clist_selected_->rows().size()-1 ).select();
467   updateButtons();
468 }
469
470 void FormCitation::hide()
471 {
472   if (dialog_!=NULL) dialog_->destroy();
473 }
474
475 void FormCitation::free()
476 {
477   if (dialog_!=NULL)
478     {
479       // storing configuration
480       string path;
481       string w, h;
482       path  = PACKAGE "/" LOCAL_CONFIGURE_PREFIX;
483       w = path + "/" + CONF_DIALOG_WIDTH;
484       h = path + "/" + CONF_DIALOG_HEIGTH;
485
486       gnome_config_set_int(w.c_str(), dialog_->width());
487       gnome_config_set_int(h.c_str(), dialog_->height());
488
489       w = path + "/" + CONF_PANE_INFO;
490       gnome_config_set_int(w.c_str(), paned_key_->height());
491
492       w = path + "/" + CONF_PANE_KEY;
493       gnome_config_set_int(w.c_str(), box_keys_->width());
494
495       int i, sz;
496       for (i = 0, sz = clist_bib_->columns().size(); i < sz; ++i)
497         {
498           w = path + "/" + CONF_COLUMN + "_" + tostr(i);
499           gnome_config_set_int(w.c_str(), clist_bib_->get_column_width(i));
500         }
501
502       gnome_config_sync();
503
504       // cleaning up
505       dialog_ = NULL;
506       u_.disconnect();
507       h_.disconnect();
508       inset_ = 0;
509       ih_.disconnect();
510     }
511 }
512
513 void FormCitation::apply()
514 {
515   if( lv_->buffer()->isReadonly() ) return;
516
517   string contents;
518   for( unsigned int i = 0; i < clist_selected_->rows().size(); ++i )
519     {
520       if (i > 0) contents += ", ";
521       contents += clist_selected_->cell(i, 0).get_text();
522     }
523
524   params.setContents( contents );
525   params.setOptions( text_after_->get_entry()->get_text() );
526
527   if( inset_ != 0 )
528     {
529       // Only update if contents have changed
530       if( params != inset_->params() )
531         {
532           inset_->setParams( params );
533           lv_->view()->updateInset( inset_, true );
534         }
535     }
536   else
537     {
538       lv_->getLyXFunc()->Dispatch( LFUN_CITATION_INSERT,
539                                    params.getAsString().c_str() );
540     }
541 }
542
543 void FormCitation::sortBibList(gint col)
544 {
545   clist_bib_->set_sort_column(col);
546   clist_bib_->sort();
547 }
548
549 // looking for entries which contain all the words specified in search_text entry
550 void FormCitation::search()
551 {
552   vector<string> searchwords;
553   string tmp, stext( search_text_->get_entry()->get_text() );
554   stext = frontStrip( strip( stext ) );
555   stext = frontStrip( split(stext, tmp, ' ') );
556   while( !tmp.empty() )
557     {
558       searchwords.push_back(tmp);
559       stext = frontStrip( split(stext, tmp, ' ') );
560     }
561   
562   // populating clist_bib_
563   clist_bib_->rows().clear();
564
565   clist_bib_->freeze();
566
567   int i, sz;
568   bool additem;
569   for ( i = 0, sz = bibkeys.size(); i < sz; ++i )
570     {
571       string data = bibkeys[i] + bibkeysInfo[i];
572
573       additem = true;
574
575       int j, szs;
576       for (j = 0, szs = searchwords.size();
577            additem && j < szs; ++j )
578         if ( data.find(searchwords[j]) == string::npos )
579           additem = false;
580              
581       if ( additem ) addItemToBibList(i);
582     }
583
584   clist_bib_->sort();
585   clist_bib_->thaw();
586   // clist_bib_: done
587   updateButtons();
588 }