1 /*  cdrdao - write audio CD-Rs in disc-at-once mode
2  *
3  *  Copyright (C) 1998-2001  Andreas Mueller <mueller@daneb.ping.de>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 #include "CdTextDialog.h"
21 
22 #include <gtkmm.h>
23 #include <gnome.h>
24 #include <libgnomeuimm.h>
25 
26 #include <stddef.h>
27 #include <string.h>
28 
29 #include "TocEdit.h"
30 #include "Toc.h"
31 #include "util.h"
32 
33 #include "guiUpdate.h"
34 
CdTextDialog()35 CdTextDialog::CdTextDialog()
36 {
37   int i;
38   Gtk::VBox *contents = manage(new Gtk::VBox);
39   char buf[20];
40 
41   active_ = false;
42   tocEdit_ = NULL;
43   trackEntries_ = 0;
44 
45   languages_ = manage(new Gtk::Notebook);
46 
47   for (i = 0; i < 8; i++) {
48     page_[i].table = new Gtk::Table(3, 3, false);
49     page_[i].table->set_row_spacings(5);
50     page_[i].table->set_col_spacings(5);
51     page_[i].performer = manage(new Gtk::Entry);
52     page_[i].title = manage(new Gtk::Entry);
53     page_[i].tabLabel = new Gtk::Label("");
54     page_[i].performerButton =
55       new Gtk::CheckButton(_("Enable Perfomer Entries"));
56     page_[i].performerButton->set_active(false);
57     page_[i].performerButton->signal_toggled().
58       connect(bind(mem_fun(*this, &CdTextDialog::activatePerformerAction), i));
59     page_[i].tracks = NULL;
60     page_[i].table->attach(*(new Gtk::Label(_("Performer"))), 1, 2, 0, 1);
61     page_[i].table->attach(*(new Gtk::Label(_("Title"))), 2, 3, 0, 1);
62 
63     {
64       Gtk::HBox *hbox = manage(new Gtk::HBox);
65       hbox->pack_end(*(new Gtk::Label(_("Album"))));
66 
67       page_[i].table->attach(*hbox, 0, 1, 1, 2, Gtk::FILL);
68       page_[i].table->attach(*(page_[i].title), 2, 3, 1, 2);
69       page_[i].table->attach(*(page_[i].performer), 1, 2, 1, 2);
70     }
71 
72     {
73       Gtk::HBox *hbox = manage(new Gtk::HBox);
74 
75       hbox->pack_start(*(page_[i].performerButton));
76       page_[i].table->attach(*hbox, 1, 2, 2, 3);
77     }
78 
79     {
80       Gtk::HBox *hbox1 = manage(new Gtk::HBox);
81       Gtk::VBox *vbox1 = manage(new Gtk::VBox);
82 
83       hbox1->pack_start(*(page_[i].table), true, true, 5);
84       vbox1->pack_start(*hbox1, false, false, 5);
85 
86       Gtk::ScrolledWindow *swin = manage(new Gtk::ScrolledWindow);
87       swin->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
88       swin->show_all();
89       swin->add(*vbox1);
90 
91       sprintf(buf, " %d ", i);
92       languages_->pages().
93         push_back(Gtk::Notebook_Helpers::TabElem(*swin,
94                                                  *(page_[i].tabLabel)));
95     }
96   }
97 
98   contents->pack_start(*languages_);
99 
100   {
101     Gtk::HBox *hbox = manage(new Gtk::HBox);
102 
103     hbox->pack_start(*contents, true, true, 10);
104     get_vbox()->pack_start(*hbox, true, true, 10);
105   }
106 
107   Gtk::HButtonBox *bbox = new Gtk::HButtonBox(Gtk::BUTTONBOX_SPREAD);
108 
109   applyButton_ = new Gtk::Button(Gtk::StockID(Gtk::Stock::APPLY));
110   bbox->pack_start(*applyButton_);
111   applyButton_->signal_clicked().connect(mem_fun(*this, &CdTextDialog::applyAction));
112 
113   Gtk::Button *fillButton = new Gtk::Button(_(" Fill Performer "));
114   bbox->pack_start(*fillButton);
115   fillButton->signal_clicked().connect(mem_fun(*this, &CdTextDialog::fillPerformerAction));
116 
117   Gtk::Button *cancelButton = new Gtk::Button(Gtk::StockID(Gtk::Stock::CLOSE));
118   bbox->pack_start(*cancelButton);
119   cancelButton->signal_clicked().connect(mem_fun(*this, &CdTextDialog::stop));
120 
121   get_action_area()->pack_start(*bbox);
122 
123   show_all_children();
124   set_title(_("CD-TEXT Entry"));
125 }
126 
~CdTextDialog()127 CdTextDialog::~CdTextDialog()
128 {
129 }
130 
on_delete_event(GdkEventAny *)131 bool CdTextDialog::on_delete_event(GdkEventAny*)
132 {
133   stop();
134   return 1;
135 }
136 
updateTabLabels()137 void CdTextDialog::updateTabLabels()
138 {
139   const Toc *toc = tocEdit_->toc();
140   int l;
141 
142   for (l = 0; l < 8; l++) {
143     const char *s = CdTextContainer::languageName(toc->cdTextLanguage(l));
144 
145     if (page_[l].tabLabel->get_label() != s)
146       page_[l].tabLabel->set_label(s);
147   }
148 }
149 
adjustTableEntries(int n)150 void CdTextDialog::adjustTableEntries(int n)
151 {
152   int i, l;
153   char buf[20];
154 
155   if (trackEntries_ == n)
156     return;
157 
158   for (l = 0; l < 8; l++) {
159     if (n < trackEntries_) {
160       page_[l].table->resize(3 + n, 3);
161 
162       for (i = n; i < trackEntries_; i++) {
163 	delete page_[l].tracks[i].performer;
164 	delete page_[l].tracks[i].title;
165 	delete page_[l].tracks[i].hbox;
166 	delete page_[l].tracks[i].label;
167       }
168     }
169     else {
170       int performerActive = page_[l].performerButton->get_active();
171 
172       TableEntry *newTracks = new TableEntry[n];
173 
174       for (i = 0; i < trackEntries_; i++)
175 	newTracks[i] = page_[l].tracks[i];
176 
177       delete[] page_[l].tracks;
178       page_[l].tracks = newTracks;
179 
180       page_[l].table->resize(3 + n, 3);
181 
182       for (i = trackEntries_; i < n; i++) {
183 	sprintf(buf, _("Track %02d"), i + 1);
184 
185 	page_[l].tracks[i].performer = manage(new Gtk::Entry);
186 	page_[l].tracks[i].performer->set_sensitive(performerActive);
187 	page_[l].tracks[i].title = manage(new Gtk::Entry);
188 	page_[l].tracks[i].label = new Gtk::Label(buf);
189 	page_[l].tracks[i].hbox = manage(new Gtk::HBox);
190 
191 	page_[l].tracks[i].hbox->pack_end(*(page_[l].tracks[i].label),
192                                           Gtk::PACK_SHRINK);
193 
194 	page_[l].table->attach(*(page_[l].tracks[i].hbox),
195 			       0, 1, i + 3, i + 4, Gtk::FILL);
196 	page_[l].table->attach(*(page_[l].tracks[i].title),
197 			       2, 3, i + 3, i + 4);
198 	page_[l].table->attach(*(page_[l].tracks[i].performer),
199 			       1, 2, i + 3, i + 4);
200       }
201 
202       page_[l].table->show_all();
203     }
204   }
205 
206   trackEntries_ = n;
207 }
208 
update(unsigned long level,TocEdit * view)209 void CdTextDialog::update(unsigned long level, TocEdit *view)
210 {
211   if (view != tocEdit_) {
212     tocEdit_ = view;
213     level = UPD_ALL;
214   }
215 
216   std::string s(view->filename());
217   s += " - ";
218   s += APP_NAME;
219   if (view->tocDirty())
220     s += "(*)";
221   set_title(s);
222 
223   if (level & UPD_TOC_DATA) {
224     updateTabLabels();
225   }
226 
227   if ((level & UPD_TOC_DATA) ||
228       (level & UPD_TRACK_DATA)) {
229     importData();
230   }
231 
232   if (level & UPD_EDITABLE_STATE) {
233     applyButton_->set_sensitive(tocEdit_->editable() ? true : false);
234   }
235 }
236 
start(TocEdit * view)237 void CdTextDialog::start(TocEdit *view)
238 {
239   update(UPD_ALL, view);
240   present();
241   active_ = true;
242 }
243 
stop()244 void CdTextDialog::stop()
245 {
246   hide();
247   active_ = false;
248 }
249 
applyAction()250 void CdTextDialog::applyAction()
251 {
252   if (tocEdit_ == NULL || !tocEdit_->editable())
253     return;
254 
255   exportData();
256 
257   guiUpdate();
258 }
259 
fillPerformerAction()260 void CdTextDialog::fillPerformerAction()
261 {
262   int l = languages_->get_current_page();
263 
264   if (l >= 0 && l <= 7) {
265     int i;
266     const char *s = checkString(page_[l].performer->get_text());
267 
268     if (s == NULL)
269       return;
270 
271     char *performer = strdupCC(s);
272 
273     for (i = 0; i < trackEntries_; i++) {
274       if (checkString(page_[l].tracks[i].performer->get_text()) == NULL)
275 	page_[l].tracks[i].performer->set_text(performer);
276     }
277 
278     delete[] performer;
279   }
280 }
281 
activatePerformerAction(int l)282 void CdTextDialog::activatePerformerAction(int l)
283 {
284   int i;
285   int val = page_[l].performerButton->get_active();
286 
287   for (i = 0; i < trackEntries_; i++) {
288     page_[l].tracks[i].performer->set_sensitive(val);
289   }
290 }
291 
importData()292 void CdTextDialog::importData()
293 {
294   const CdTextItem *item;
295   const Toc *toc = tocEdit_->toc();
296   int i, l;
297   int n = toc->nofTracks();
298 
299   adjustTableEntries(n);
300 
301   for (l = 0; l < 8; l++) {
302     if ((item = toc->getCdTextItem(0, l, CdTextItem::CDTEXT_TITLE)) != NULL)
303       page_[l].title->set_text((const char*)item->data());
304     else
305       page_[l].title->set_text("");
306 
307     if ((item = toc->getCdTextItem(0, l, CdTextItem::CDTEXT_PERFORMER))
308 	!= NULL)
309       page_[l].performer->set_text((const char*)item->data());
310     else
311       page_[l].performer->set_text("");
312 
313     for (i = 0; i < n; i++) {
314       if ((item = toc->getCdTextItem(i + 1, l, CdTextItem::CDTEXT_TITLE))
315 	  != NULL)
316 	page_[l].tracks[i].title->set_text((const char*)item->data());
317       else
318 	page_[l].tracks[i].title->set_text("");
319 
320       if ((item = toc->getCdTextItem(i + 1, l, CdTextItem::CDTEXT_PERFORMER))
321 	  != NULL)
322 	page_[l].tracks[i].performer->set_text((const char*)item->data());
323       else
324 	page_[l].tracks[i].performer->set_text("");
325     }
326   }
327 }
328 
exportData()329 void CdTextDialog::exportData()
330 {
331   int i, l;
332 
333   for (l = 0; l < 8; l++) {
334     setCdTextItem(CdTextItem::CDTEXT_TITLE, 0, l,
335 		  checkString(page_[l].title->get_text()));
336     setCdTextItem(CdTextItem::CDTEXT_PERFORMER, 0, l,
337 		  checkString(page_[l].performer->get_text()));
338 
339     for (i = 0; i < trackEntries_; i++) {
340       setCdTextItem(CdTextItem::CDTEXT_TITLE, i + 1, l,
341 		    checkString(page_[l].tracks[i].title->get_text()));
342       setCdTextItem(CdTextItem::CDTEXT_PERFORMER, i + 1, l,
343 		    checkString(page_[l].tracks[i].performer->get_text()));
344     }
345   }
346 }
347 
setCdTextItem(CdTextItem::PackType type,int trackNr,int l,const char * s)348 void CdTextDialog::setCdTextItem(CdTextItem::PackType type, int trackNr,
349 				 int l, const char *s)
350 {
351   const CdTextItem *item;
352   TocEdit *tocEdit = tocEdit_;
353   const Toc *toc = tocEdit->toc();
354   CdTextItem *newItem;
355 
356   if (s != NULL)
357     newItem = new CdTextItem(type, l, s);
358   else
359     newItem = NULL;
360 
361   if ((item = toc->getCdTextItem(trackNr, l, type)) != NULL) {
362     if (newItem == NULL)
363       tocEdit->setCdTextItem(trackNr, type, l, NULL);
364     else if (*newItem != *item)
365       tocEdit->setCdTextItem(trackNr, type, l, s);
366   }
367   else if (newItem != NULL) {
368     tocEdit->setCdTextItem(trackNr, type, l, s);
369   }
370 
371   delete newItem;
372 }
373 
checkString(const std::string & str)374 const char *CdTextDialog::checkString(const std::string &str)
375 {
376   static char *buf = NULL;
377   static long bufLen = 0;
378   char *p, *s;
379   long len = strlen(str.c_str());
380 
381   if (len == 0)
382     return NULL;
383 
384   if (buf == NULL || len + 1 > bufLen) {
385     delete[] buf;
386     bufLen = len + 1;
387     buf = new char[bufLen];
388   }
389 
390   strcpy(buf, str.c_str());
391 
392   s = buf;
393   p = buf + len - 1;
394 
395   while (*s != 0 && isspace(*s))
396     s++;
397 
398   if (*s == 0)
399     return NULL;
400 
401   while (p > s && isspace(*p)) {
402     *p = 0;
403     p--;
404   }
405 
406   return s;
407 }
408 
409