868f1c209fef07e6e7df568d7fe19680066a27c3
[goodguy/history.git] / cinelerra-5.1 / cinelerra / binfolder.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 #include "awindowgui.h"
22 #include "bchash.h"
23 #include "binfolder.h"
24 #include "cstrdup.h"
25 #include "edl.h"
26 #include "filexml.h"
27 #include "guicast.h"
28 #include "indexable.h"
29 #include "language.h"
30 #include "mainerror.h"
31 #include "mainsession.h"
32 #include "mutex.h"
33 #include "mwindow.h"
34
35 #include <time.h>
36
37 const char *BinFolderEnabled::types[] = {
38         N_("Off"),
39         N_("And"),
40         N_("Or"),
41         N_("And Not"),
42         N_("Or Not"),
43 };
44
45 const char *BinFolderTarget::types[] = {
46         N_("Patterns"),
47         N_("Filesize"),
48         N_("Time"),
49         N_("Track type"),
50         N_("Width"),
51         N_("Height"),
52         N_("Framerate"),
53         N_("Samplerate"),
54         N_("Channels"),
55         N_("Duration"),
56 };
57
58 const char *BinFolderOp::types[] = {
59         N_("Around"),
60         N_("Eq"),
61         N_("Ge"),
62         N_("Gt"),
63         N_("Ne"),
64         N_("Le"),
65         N_("Lt"),
66         N_("Matches"),
67 };
68
69 static const struct {
70         const char *sfx, *sfxs;
71         double radix;
72 } scan_ranges[] = {
73         { N_("min"),   N_("mins"),   60, },
74         { N_("hour"),  N_("hours"),  60*60, },
75         { N_("day"),   N_("days"),   24*60*60, },
76         { N_("week"),  N_("weeks"),  24*60*60*7, },
77         { N_("month"), N_("months"), 24*60*60*31, },
78         { N_("year"),  N_("years"),  24*60*60*365.25, },
79 };
80 #define SCAN_RANGE_DAYS 2
81 #define DBL_INF 9007199254740991.
82
83 static int scan_inf(const char *cp, char *&bp)
84 {
85         bp = (char *)cp;
86         const char *inf = _("inf");
87         const int linf = strlen(inf);
88         if( strncasecmp(cp,inf,linf) ) return 0;
89         bp = (char *)(cp + linf);
90         return 1;
91 }
92
93 static double scan_no(const char *cp, char *&bp)
94 {
95         while( *cp == ' ' ) ++cp;
96         if( scan_inf(cp, bp) ) return DBL_INF;
97         if( *cp == '+' ) return 0;
98         double v = strtod(cp, &bp);
99         switch( *bp ) {
100         case 'T': v *= 1099511627776.;  break;
101         case 't': v *= 1e12;            break;
102         case 'G': v *= 1073741824.;     break;
103         case 'g': v *= 1e9;             break;
104         case 'M': v *= 1048576.;        break;
105         case 'm': v *= 1e6;             break;
106         case 'K': v *= 1024.;           break;
107         case 'k': v *= 1e3;             break;
108         default:  return v;
109         }
110         ++bp;
111         return v;
112 }
113
114 static void scan_around(const char *cp, char *&bp, double &v, double &a)
115 {
116         v = 0;  a = -1;
117         double sv = scan_no(cp, bp);
118         if( bp > cp ) v = sv;
119         if( *bp == '+' ) {
120                 double sa = scan_no(cp=bp+1, bp);
121                 if( bp > cp ) a = sa;
122         }
123 }
124
125 static void show_no(double v, char *&cp, char *ep, const char *fmt="%0.0f")
126 {
127         if( v == DBL_INF ) {
128                 cp += snprintf(cp, ep-cp, "%s", _("inf"));
129                 return;
130         }
131         const char *sfx = 0;
132         static const struct { double radix; const char *sfx; } sfxs[] = {
133                 { 1024.,          "K" }, { 1e3,  "k" },
134                 { 1048576.,       "M" }, { 1e6,  "m" },
135                 { 1073741824.,    "G" }, { 1e9,  "g" },
136                 { 1099511627776., "T" }, { 1e12, "t" },
137         };
138         for( int i=sizeof(sfxs)/sizeof(sfxs[0]); --i>=0; ) {
139                 if( v < sfxs[i].radix ) continue;
140                 if( fmod(v, sfxs[i].radix) == 0 ) {
141                         v /= sfxs[i].radix;
142                         sfx = sfxs[i].sfx;
143                         break;
144                 }
145         }
146         cp += snprintf(cp, ep-cp, fmt, v);
147         if( sfx ) cp += snprintf(cp, ep-cp, "%s", sfx);
148 }
149
150 static double scan_duration(const char *cp, char *&bp)
151 {
152         if( scan_inf(cp, bp) ) return DBL_INF;
153         double secs = 0;
154         while( *cp ) {
155                 double v = strtod(cp, &bp);
156                 if( cp >= bp ) break;
157                 int k = sizeof(scan_ranges)/sizeof(scan_ranges[0]);
158                 while( --k >= 0 ) {
159                         const char *tsfx  = _(scan_ranges[k].sfx);
160                         int lsfx  = strlen(tsfx), msfx  = strncasecmp(bp, tsfx,  lsfx);
161                         const char *tsfxs = _(scan_ranges[k].sfxs);
162                         int lsfxs = strlen(tsfxs), msfxs = strncasecmp(bp, tsfxs, lsfxs);
163                         int len = !msfx && !msfxs ? (lsfx > lsfxs ? lsfx : lsfxs) :
164                                 !msfx ? lsfx : !msfxs ? lsfxs : -1;
165                         if( len >= 0 ) {
166                                 secs += v * scan_ranges[k].radix;
167                                 bp += len;
168                                 break;
169                         }
170                 }
171                 if( k < 0 ) {
172                         int hour = 0, mins = 0;
173                         if( *bp == ':' && v == (int)v ) {
174                                 mins = v;
175                                 v = strtod(cp=bp+1, &bp);
176                                 if( *bp == ':' && v == (int)v ) {
177                                         hour = mins;  mins = v;
178                                         v = strtod(cp=bp+1, &bp);
179                                 }
180                         }
181                         secs += hour*3600 + mins*60 + v;
182                 }
183                 while( *bp && (*bp<'0' || *bp>'9') ) ++bp;
184                 cp = bp;
185         }
186         return secs;
187 }
188
189 static void show_duration(double v, char *&cp, char *ep)
190 {
191         if( v == DBL_INF ) {
192                 cp += snprintf(cp, ep-cp, "%s", _("inf"));
193                 return;
194         }
195         double secs = v;  char *bp = cp;
196         int k = sizeof(scan_ranges)/sizeof(scan_ranges[0]);
197         while( --k >= SCAN_RANGE_DAYS ) {
198                 if( secs >= scan_ranges[k].radix ) {
199                         int v = secs/scan_ranges[k].radix;
200                         secs -= v * scan_ranges[k].radix;
201                         cp += snprintf(cp, ep-cp,"%d%s", v,
202                                 v > 1 ? _(scan_ranges[k].sfxs) : _(scan_ranges[k].sfx));
203                 }
204         }
205         if( secs > 0 ) {
206                 if( cp > bp && cp < ep ) *cp++ = ' ';
207                 int64_t n = secs; int hour = n/3600, min = (n/60)%60, sec = n%60;
208                 if( hour > 0 ) cp += snprintf(cp, ep-cp, "%d:", hour);
209                 if( hour > 0 || min > 0 ) cp += snprintf(cp, ep-cp, "%02d:", min);
210                 cp += snprintf(cp, ep-cp, n>=10 ? "%02d" : "%d", sec);
211         }
212 }
213
214 static int64_t scan_date(const char *cp, char *&bp)
215 {
216         double year=0, mon=1, day=1;
217         double hour=0, min=0;
218         bp = (char *)cp;
219         while( *bp == ' ' ) ++bp;
220         if( *bp == '+' ) return 0;
221         double secs = strtod(cp=bp, &bp);
222         if( *bp == '/' && secs == (int)secs ) {
223                 year = secs;  secs = 0;
224                 mon = strtod(cp=bp+1, &bp);
225                 if( *bp == '/' && mon == (int)mon ) {
226                         day = strtod(cp=bp+1, &bp);
227                         while( *bp == ' ' ) ++bp;
228                         secs = *bp != '+' ? strtod(cp=bp, &bp) : 0;
229                 }
230         }
231         if( *bp == ':' && secs == (int)secs ) {
232                 hour = secs;  secs = 0;
233                 min = strtod(cp=bp+1, &bp);
234                 if( *bp == ':' && min == (int)min ) {
235                         secs = strtod(cp=bp+1, &bp);
236                 }
237         }
238         struct tm ttm;  memset(&ttm, 0, sizeof(ttm));
239         ttm.tm_year = year-1900;  ttm.tm_mon = mon-1;  ttm.tm_mday = day;
240         ttm.tm_hour = hour;       ttm.tm_min = min;    ttm.tm_sec = secs;
241         ttm.tm_wday = ttm.tm_yday = 0;  ttm.tm_isdst = daylight; /* tzset in main */
242         time_t t = mktime(&ttm);
243         return (int64_t)t;
244 }
245
246 static void show_date(time_t t, char *&cp, char *ep)
247 {
248         struct tm tm;  localtime_r(&t, &tm);
249         cp += snprintf(cp, ep-cp, "%04d/%02d/%02d %02d:%02d:%02d",
250                 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
251                 tm.tm_hour, tm.tm_min, tm.tm_sec);
252 }
253
254 double BinFolder::matches_indexable(Indexable *idxbl)
255 {
256         double result = -1;
257         for( int i=0; i<filters.size(); ++i ) {
258                 BinFolderFilter *filter = filters[i];
259                 double ret = filter->op->test(filter->target, idxbl);
260                 switch( filter->enabled->type ) {
261                 case FOLDER_ENABLED_OR: {
262                         if( result < 0 ) result = ret;
263                         break; }
264                 case FOLDER_ENABLED_AND: {
265                         if( ret < 0 ) result = -1;
266                         break; }
267                 case FOLDER_ENABLED_OR_NOT: {
268                         if( ret < 0 ) result = 1;
269                         break; }
270                 case FOLDER_ENABLED_AND_NOT: {
271                         if( ret >= 0 ) result = -1;
272                         break; }
273                 }
274         }
275         return result;
276 }
277
278
279 BinFolder::BinFolder(int awindow_folder, const char *title)
280 {
281         this->awindow_folder = awindow_folder;
282         char *bp = this->title;
283         int len = sizeof(this->title);
284         while( --len>0 && *title ) *bp++ = *title++;
285         *bp = 0;
286 }
287
288 BinFolder::BinFolder(BinFolder &that)
289 {
290         copy_from(&that);
291 }
292
293 void BinFolder::copy_from(BinFolder *that)
294 {
295         strcpy(title, that->title);
296         awindow_folder = that->awindow_folder;
297         filters.copy_from(&that->filters);
298 }
299
300 BinFolder::~BinFolder()
301 {
302 }
303
304 void BinFolder::save_xml(FileXML *file)
305 {
306         file->tag.set_title("FOLDER");
307         file->tag.set_property("TITLE", title);
308         file->tag.set_property("AWINDOW_FOLDER", awindow_folder);
309         file->append_tag();
310         file->append_newline();
311         for( int i=0; i<filters.size(); ++i )
312                 filters[i]->save_xml(file);
313         file->tag.set_title("/FOLDER");
314         file->append_tag();
315         file->append_newline();
316 }
317
318 int BinFolder::load_xml(FileXML *file)
319 {
320         title[0] = 0;
321         file->tag.get_property("TITLE", title);
322         awindow_folder = file->tag.get_property("AWINDOW_FOLDER", -1);
323         filters.remove_all_objects();
324
325         int ret = 0;
326         while( !(ret=file->read_tag()) ) {
327                 if( file->tag.title_is("/FOLDER") ) break;
328                 if( file->tag.title_is("FILTER") ) {
329                         BinFolderFilter *filter = new BinFolderFilter();
330                         filter->load_xml(file);
331                         filters.append(filter);
332                 }
333         }
334         return ret;
335 }
336
337 void BinFolder::add_patterns(ArrayList<Indexable*> *drag_assets)
338 {
339         int n = drag_assets->size();
340         if( n > 0 ) {
341                 int len = 1;
342                 for( int i=0; i<n; ++i )
343                         len += strlen(drag_assets->get(i)->path) + 1;
344                 char *pats = new char[len], *bp = pats;
345                 const char *cp = drag_assets->get(0)->path;
346                 while( *cp ) *bp++ = *cp++;
347                 for( int i=1; i<n; ++i ) {
348                         *bp++ = '\n';
349                         cp = drag_assets->get(i)->path;
350                         while( *cp ) *bp++ = *cp++;
351                 }
352                 *bp = 0;
353 // new pattern filter
354                 BinFolderFilter *filter = new BinFolderFilter();
355                 filter->update_enabled(FOLDER_ENABLED_OR);
356                 filter->update_target(FOLDER_TARGET_PATTERNS);
357                 filter->update_op(FOLDER_OP_MATCHES);
358                 BinFolderTargetPatterns *patterns = (BinFolderTargetPatterns *)(filter->target);
359                 patterns->update(pats);
360                 filters.append(filter);
361         }
362 }
363
364
365 double BinFolders::matches_indexable(int folder, Indexable *idxbl)
366 {
367         int k = size();
368         while( --k>=0 && get(k)->awindow_folder!=folder );
369         return k < 0 ? 0 : get(k)->matches_indexable(idxbl);
370 }
371
372 void BinFolders::save_xml(FileXML *file)
373 {
374         file->tag.set_title("FOLDERS");
375         file->append_tag();
376         file->append_newline();
377         for( int i=0; i<size(); ++i )
378                 get(i)->save_xml(file);
379         file->tag.set_title("/FOLDERS");
380         file->append_tag();
381         file->append_newline();
382 }
383
384 int BinFolders::load_xml(FileXML *file)
385 {
386         clear();
387         int ret = 0;
388         while( !(ret=file->read_tag()) ) {
389                 if( file->tag.title_is("/FOLDERS") ) break;
390                 if( file->tag.title_is("FOLDER") ) {
391                         BinFolder *folder = new BinFolder(-1, "folder");
392                         folder->load_xml(file);
393                         append(folder);
394                 }
395         }
396         return ret;
397 }
398
399 void BinFolders::copy_from(BinFolders *that)
400 {
401         clear();
402         for( int i=0; i<that->size(); ++i )
403                 append(new BinFolder(*that->get(i)));
404 }
405
406
407 BinFolderFilter::BinFolderFilter()
408 {
409         enabled = 0;
410         target = 0;
411         op = 0;
412         value = 0;
413 }
414 BinFolderFilter::~BinFolderFilter()
415 {
416         delete enabled;
417         delete target;
418         delete op;
419         delete value;
420 }
421
422 void BinFolderFilter::update_enabled(int type)
423 {
424         if( !enabled )
425                 enabled = new BinFolderEnabled(this, type);
426         else
427                 enabled->update(type);
428 }
429
430 void BinFolderFilter::update_target(int type)
431 {
432         if( target ) {
433                 if( target->type == type ) return;
434                 delete target;  target = 0;
435         }
436         switch( type ) {
437         case FOLDER_TARGET_PATTERNS:    target = new BinFolderTargetPatterns(this);    break;
438         case FOLDER_TARGET_FILE_SIZE:   target = new BinFolderTargetFileSize(this);    break;
439         case FOLDER_TARGET_MOD_TIME:    target = new BinFolderTargetTime(this);        break;
440         case FOLDER_TARGET_TRACK_TYPE:  target = new BinFolderTargetTrackType(this);   break;
441         case FOLDER_TARGET_WIDTH:       target = new BinFolderTargetWidth(this);       break;
442         case FOLDER_TARGET_HEIGHT:      target = new BinFolderTargetHeight(this);      break;
443         case FOLDER_TARGET_FRAMERATE:   target = new BinFolderTargetFramerate(this);   break;
444         case FOLDER_TARGET_SAMPLERATE:  target = new BinFolderTargetSamplerate(this);  break;
445         case FOLDER_TARGET_CHANNELS:    target = new BinFolderTargetChannels(this);    break;
446         case FOLDER_TARGET_DURATION:    target = new BinFolderTargetDuration(this);    break;
447         }
448 }
449
450 void BinFolderFilter::update_op(int type)
451 {
452         if( op ) {
453                 if( op->type == type ) return;
454                 delete op;  op = 0;
455         }
456         switch( type ) {
457         case FOLDER_OP_AROUND:  op = new BinFolderOpAround(this);  break;
458         case FOLDER_OP_EQ:      op = new BinFolderOpEQ(this);      break;
459         case FOLDER_OP_GE:      op = new BinFolderOpGE(this);      break;
460         case FOLDER_OP_GT:      op = new BinFolderOpGT(this);      break;
461         case FOLDER_OP_NE:      op = new BinFolderOpNE(this);      break;
462         case FOLDER_OP_LE:      op = new BinFolderOpLE(this);      break;
463         case FOLDER_OP_LT:      op = new BinFolderOpLT(this);      break;
464         case FOLDER_OP_MATCHES: op = new BinFolderOpMatches(this); break;
465         }
466 }
467
468 void BinFolderFilter::update_value(const char *text)
469 {
470         if( !value )
471                 value = new BinFolderValue(this, text);
472         else
473                 value->update(text);
474 }
475
476 void BinFolderFilter::save_xml(FileXML *file)
477 {
478         file->tag.set_title("FILTER");
479         file->tag.set_property("ENABLED", enabled->type);
480         file->tag.set_property("OP", op->type);
481         file->tag.set_property("TARGET", target->type);
482         target->save_xml(file);
483         file->append_tag();
484         if( target->type == FOLDER_TARGET_PATTERNS )
485                 file->append_text(((BinFolderTargetPatterns *)target)->text);
486         file->tag.set_title("/FILTER");
487         file->append_tag();
488         file->append_newline();
489 }
490
491 int BinFolderFilter::load_xml(FileXML *file)
492 {
493         int enabled_type = file->tag.get_property("ENABLED", FOLDER_ENABLED_AND);
494         int op_type = file->tag.get_property("OP", FOLDER_OP_MATCHES);
495         int target_type = file->tag.get_property("TARGET", FOLDER_TARGET_PATTERNS);
496         char data[0x40000];
497         file->read_text_until("/FILTER", data, sizeof(data), 0);
498         update_enabled(enabled_type);
499         update_target(target_type);
500         update_op(op_type);
501         target->load_xml(file);
502         if( target->type == FOLDER_TARGET_PATTERNS )
503                 ((BinFolderTargetPatterns *)target)->update(data);
504         return 0;
505 }
506
507 void BinFolderFilters::copy_from(BinFolderFilters *that)
508 {
509         clear();
510         for( int i=0; i<that->size(); ++i ) {
511                 BinFolderFilter *filter = new BinFolderFilter();
512                 BinFolderFilter *tp = that->get(i);
513                 filter->update_enabled(tp->enabled->type);
514                 filter->update_target(tp->target->type);
515                 filter->update_op(tp->op->type);
516                 filter->target->copy_from(tp->target);
517                 filter->op->copy_from(tp->op);
518                 append(filter);
519         }
520 }
521
522 double BinFolderOp::around(double v, double a)
523 {
524         if( type != FOLDER_OP_AROUND || a <= 0 ) return v;
525         if( (v=fabs(v)) > a ) return -1;
526         return v / a;
527 }
528
529 // string theory: Feynman, Einstein and Schrodinger string compare
530 //   Feynman: try all possible matches, weight the outcomes
531 //   Schrodinger: it may be there several ways at the same time
532 //   Einstein: the more matches there are, the heavier it is
533 double BinFolderOp::around(const char *ap, const char *bp)
534 {
535         int64_t v = 0, vmx = 0;
536         int alen = strlen(ap), blen = strlen(bp);
537         if( alen > blen ) {
538                 const char *cp = ap;  ap = bp;  bp = cp;
539                 int clen = alen;  alen = blen;  blen = clen;
540         }
541 // 4 level loop (with strncmp), don't try long strings
542         for( int n=0; ++n<=alen; ) {
543                 int64_t nn = n*n;
544                 int an = alen-n+1, bn = blen-n+1;
545                 for( int i=an; --i>=0; ) {
546                         for( int j=bn; --j>=0; ) {
547                                 if( !strncmp(ap+i, bp+j, n) ) v += nn;
548                         }
549                 }
550                 vmx += an*bn*nn;
551         }
552         return !vmx ? -1 : 1 - v / (double)vmx;
553 }
554
555
556 double BinFolderOp::compare(BinFolderTarget *target, Indexable *idxbl)
557 {
558         double v = -1;
559         switch( target->type ) {
560         case FOLDER_TARGET_PATTERNS: {
561                 BinFolderTargetPatterns *tgt = (BinFolderTargetPatterns *)target;
562                 switch( type ) {
563                 case FOLDER_OP_AROUND: {
564                         const char *cp = idxbl->path;
565                         const char *bp = strrchr(cp, '/');
566                         if( bp ) cp = bp + 1;
567                         v = around(cp, tgt->text);
568                         break; }
569                 case FOLDER_OP_EQ:  case FOLDER_OP_GT:  case FOLDER_OP_GE:
570                 case FOLDER_OP_NE:  case FOLDER_OP_LT:  case FOLDER_OP_LE: {
571                         const char *cp = idxbl->path;
572                         const char *bp = strrchr(cp, '/');
573                         if( bp ) cp = bp + 1;
574                         v = strcmp(cp, tgt->text);
575                         break; }
576                 case FOLDER_OP_MATCHES: {
577                         v = -1;
578                         char *cp = tgt->text;
579                         while( v < 0 && *cp ) {
580                                 char pattern[BCTEXTLEN], *bp = pattern, ch;
581                                 while( *cp && (ch=*cp++)!='\n' ) *bp++ = ch;
582                                 *bp = 0;
583                                 if( bp > pattern &&
584                                     !FileSystem::test_filter(idxbl->path, pattern) )
585                                         v = 1;
586                         }
587                         break; }
588                 }
589                 break; }
590         case FOLDER_TARGET_FILE_SIZE: {
591                 BinFolderTargetFileSize *tgt = (BinFolderTargetFileSize *)target;
592                 int64_t file_size = !idxbl->is_asset ? -1 :
593                         FileSystem::get_size(idxbl->path);
594                 v = around(file_size - tgt->file_size, tgt->around);
595                 break; }
596         case FOLDER_TARGET_MOD_TIME: {
597                 BinFolderTargetTime *tgt = (BinFolderTargetTime *)target;
598                 struct stat st;
599                 if( stat(idxbl->path, &st) ) break;
600                 v = around(st.st_mtime - tgt->mtime, tgt->around);
601                 break; }
602         case FOLDER_TARGET_TRACK_TYPE: {
603                 BinFolderTargetTrackType *tgt = (BinFolderTargetTrackType *)target;
604                 int want_audio = (tgt->data_types&(1<<TRACK_AUDIO)) ? 1 : 0;
605                 int has_audio = idxbl->have_audio();
606                 if( want_audio != has_audio ) break;
607                 int want_video = (tgt->data_types&(1<<TRACK_VIDEO)) ? 1 : 0;
608                 int has_video = idxbl->have_video();
609                 if( want_video != has_video ) break;
610                 v = 1;
611                 break; }
612         case FOLDER_TARGET_WIDTH: {
613                 BinFolderTargetWidth *tgt = (BinFolderTargetWidth *)target;
614                 int w = idxbl->get_w();
615                 v = around(w - tgt->width, tgt->around);
616                 break; }
617         case FOLDER_TARGET_HEIGHT: {
618                 BinFolderTargetHeight *tgt = (BinFolderTargetHeight *)target;
619                 int h = idxbl->get_h();
620                 v = around(h - tgt->height, tgt->around);
621                 break; }
622         case FOLDER_TARGET_FRAMERATE: {
623                 BinFolderTargetFramerate *tgt = (BinFolderTargetFramerate *)target;
624                 double rate = idxbl->get_frame_rate();
625                 v = around(rate - tgt->framerate, tgt->around);
626                 break; }
627         case FOLDER_TARGET_SAMPLERATE: {
628                 BinFolderTargetSamplerate *tgt = (BinFolderTargetSamplerate *)target;
629                 double rate = idxbl->get_sample_rate();
630                 v = around(rate - tgt->samplerate, tgt->around);
631                 break; }
632         case FOLDER_TARGET_CHANNELS: {
633                 BinFolderTargetChannels *tgt = (BinFolderTargetChannels *)target;
634                 double chs = idxbl->get_audio_channels();
635                 v = around(chs - tgt->channels, tgt->around);
636                 break; }
637         case FOLDER_TARGET_DURATION: {
638                 BinFolderTargetDuration *tgt = (BinFolderTargetDuration *)target;
639                 double len = 0;
640                 double video_rate = !idxbl->have_video() ? 0 : idxbl->get_frame_rate();
641                 if( video_rate > 0 ) {
642                         double video_length = idxbl->get_video_frames() / video_rate;
643                         if( video_length > len ) len = video_length;
644                 }
645                 double audio_rate = !idxbl->have_audio() ? 0 : idxbl->get_sample_rate();
646                 if( audio_rate > 0 ) {
647                         double audio_length = idxbl->get_audio_samples() / audio_rate;
648                         if( audio_length > len ) len = audio_length;
649                 }
650                 v = around(len - tgt->duration, tgt->around);
651                 break; }
652         }
653
654         return v;
655 }
656
657 BinFolderEnabled::BinFolderEnabled(BinFolderFilter *filter, int type)
658  : BC_ListBoxItem(_(types[type]))
659 {
660         this->filter = filter;
661         this->type = type;
662 }
663
664 BinFolderEnabled::~BinFolderEnabled()
665 {
666 }
667
668 void BinFolderEnabled::update(int type)
669 {
670         this->type = type;
671         set_text(_(types[type]));
672 }
673
674 BinFolderEnabledType::BinFolderEnabledType(int no)
675  : BC_MenuItem(_(BinFolderEnabled::types[no]))
676 {
677         this->no = no;
678 }
679 BinFolderEnabledType::~BinFolderEnabledType()
680 {
681 }
682
683 int BinFolderEnabledType::handle_event()
684 {
685         BinFolderEnabledPopup *enabled_popup = (BinFolderEnabledPopup *)get_popup_menu();
686         BinFolderList *folder_list = enabled_popup->folder_list;
687         int i = folder_list->get_selection_number(FOLDER_COLUMN_ENABLE, 0);
688         if( i >= 0 ) {
689                 BinFolder *folder = folder_list->folder;
690                 BinFolderFilter *filter = folder->filters[i];
691                 filter->update_enabled(no);
692                 folder_list->create_list();
693         }
694         return 1;
695 }
696
697 BinFolderEnabledPopup::BinFolderEnabledPopup(BinFolderList *folder_list)
698  : BC_PopupMenu(0, 0, 0, "", 0)
699 {
700         this->folder_list = folder_list;
701         enabled = 0;
702 }
703
704 void BinFolderEnabledPopup::create_objects()
705 {
706         add_item(new BinFolderEnabledType(FOLDER_ENABLED_OFF));
707         add_item(new BinFolderEnabledType(FOLDER_ENABLED_AND));
708         add_item(new BinFolderEnabledType(FOLDER_ENABLED_OR));
709         add_item(new BinFolderEnabledType(FOLDER_ENABLED_AND_NOT));
710         add_item(new BinFolderEnabledType(FOLDER_ENABLED_OR_NOT));
711 }
712
713 void BinFolderEnabledPopup::activate_menu(BC_ListBoxItem *item)
714 {
715         this->enabled = (BinFolderEnabled *)item;
716         BC_PopupMenu::activate_menu();
717 }
718
719 BinFolderTarget::BinFolderTarget(BinFolderFilter *filter, int type)
720  : BC_ListBoxItem(_(types[type]))
721 {
722         this->filter = filter;
723         this->type = type;
724         around = -1;
725 }
726
727 BinFolderTarget::~BinFolderTarget()
728 {
729 }
730
731 BC_Window *BinFolderTarget::new_gui(ModifyTargetThread *thread)
732 {
733         ModifyTargetGUI *window = new ModifyTargetGUI(thread);
734         window->create_objects();
735         return window;
736 }
737
738 BinFolderTargetType::BinFolderTargetType(int no)
739  : BC_MenuItem(_(BinFolderTarget::types[no]))
740 {
741         this->no = no;
742 }
743 BinFolderTargetType::~BinFolderTargetType()
744 {
745 }
746
747 int BinFolderTargetType::handle_event()
748 {
749         BinFolderTargetPopup *target_popup = (BinFolderTargetPopup *)get_popup_menu();
750         BinFolderList *folder_list = target_popup->folder_list;
751         int i = folder_list->get_selection_number(FOLDER_COLUMN_TARGET, 0);
752         if( i >= 0 ) {
753                 BinFolder *folder = folder_list->folder;
754                 BinFolderFilter *filter = folder->filters[i];
755                 filter->update_target(no);
756                 folder_list->create_list();
757         }
758         return 1;
759 }
760
761 BinFolderTargetPopup::BinFolderTargetPopup(BinFolderList *folder_list)
762  : BC_PopupMenu(0, 0, 0, "", 0)
763 {
764         this->folder_list = folder_list;
765         target = 0;
766 }
767
768 void BinFolderTargetPopup::create_objects()
769 {
770         add_item(new BinFolderTargetType(FOLDER_TARGET_PATTERNS));
771         add_item(new BinFolderTargetType(FOLDER_TARGET_FILE_SIZE));
772         add_item(new BinFolderTargetType(FOLDER_TARGET_MOD_TIME));
773         add_item(new BinFolderTargetType(FOLDER_TARGET_TRACK_TYPE));
774         add_item(new BinFolderTargetType(FOLDER_TARGET_WIDTH));
775         add_item(new BinFolderTargetType(FOLDER_TARGET_HEIGHT));
776         add_item(new BinFolderTargetType(FOLDER_TARGET_FRAMERATE));
777         add_item(new BinFolderTargetType(FOLDER_TARGET_SAMPLERATE));
778         add_item(new BinFolderTargetType(FOLDER_TARGET_CHANNELS));
779         add_item(new BinFolderTargetType(FOLDER_TARGET_DURATION));
780 }
781
782 void BinFolderTargetPopup::activate_menu(BC_ListBoxItem *item)
783 {
784         this->target = (BinFolderTarget *)item;
785         BC_PopupMenu::activate_menu();
786 }
787
788
789 BinFolderTargetPatterns::BinFolderTargetPatterns(BinFolderFilter *filter)
790  : BinFolderTarget(filter, FOLDER_TARGET_PATTERNS)
791 {
792         text = 0;
793         update("*");
794 }
795 BinFolderTargetPatterns::~BinFolderTargetPatterns()
796 {
797         delete [] text;
798 }
799  
800 void BinFolderTargetPatterns::save_xml(FileXML *file) {}
801 void BinFolderTargetPatterns::load_xml(FileXML *file) {}
802
803 void BinFolderTargetPatterns::copy_from(BinFolderTarget *that)
804 {
805         BinFolderTargetPatterns *tp = (BinFolderTargetPatterns*)that;
806         update(tp->text);
807 }
808
809 void BinFolderTargetPatterns::update(const char *text)
810 {
811         delete [] this->text;
812         this->text = cstrdup(text);
813         filter->update_value(text);
814 }
815
816 BC_Window *BinFolderTargetPatterns::new_gui(ModifyTargetThread *thread)
817 {
818         return new ModifyTargetPatternsGUI(thread);
819 }
820
821
822 BinFolderTargetFileSize::BinFolderTargetFileSize(BinFolderFilter *filter)
823  : BinFolderTarget(filter, FOLDER_TARGET_FILE_SIZE)
824 {
825         file_size = 0;
826         update(file_size, -1);
827 }
828 BinFolderTargetFileSize::~BinFolderTargetFileSize()
829 {
830 }
831
832 void BinFolderTargetFileSize::save_xml(FileXML *file)
833 {
834         file->tag.set_property("FILE_SIZE", file_size);
835         file->tag.set_property("AROUND", around);
836 }
837
838 void BinFolderTargetFileSize::load_xml(FileXML *file)
839 {
840         int64_t file_size = file->tag.get_property("FILE_SIZE", this->file_size);
841         double around = file->tag.get_property("AROUND", this->around);
842         update(file_size, around);
843 }
844
845 void BinFolderTargetFileSize::copy_from(BinFolderTarget *that)
846 {
847         BinFolderTargetFileSize *tp = (BinFolderTargetFileSize *)that;
848         update(tp->file_size, tp->around);
849 }
850
851 void BinFolderTargetFileSize::update(int64_t file_size, double around)
852 {
853         this->file_size = file_size;
854         this->around = around;
855         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
856         show_no(file_size, cp, ep);
857         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
858                 if( cp < ep ) *cp++ = '+';
859                 show_no(around, cp, ep);
860         }
861         *cp = 0;
862         filter->update_value(txt);
863 }
864
865 BC_Window *BinFolderTargetFileSize::new_gui(ModifyTargetThread *thread)
866 {
867         return new ModifyTargetFileSizeGUI(thread);
868 }
869
870
871 BinFolderTargetTime::BinFolderTargetTime(BinFolderFilter *filter)
872  : BinFolderTarget(filter, FOLDER_TARGET_MOD_TIME)
873 {
874         time_t t;  time(&t);
875         mtime = (int64_t)t;
876         update(mtime, -1);
877 }
878 BinFolderTargetTime::~BinFolderTargetTime()
879 {
880 }
881
882 void BinFolderTargetTime::save_xml(FileXML *file)
883 {
884         file->tag.set_property("MTIME", mtime);
885         file->tag.set_property("AROUND", around);
886 }
887
888 void BinFolderTargetTime::load_xml(FileXML *file)
889 {
890         int64_t mtime = file->tag.get_property("MTIME", this->mtime);
891         double around = file->tag.get_property("AROUND", this->around);
892         update(mtime, around);
893 }
894
895 void BinFolderTargetTime::copy_from(BinFolderTarget *that)
896 {
897         BinFolderTargetTime *tp = (BinFolderTargetTime *)that;
898         update(tp->mtime, tp->around);
899 }
900
901 void BinFolderTargetTime::update(int64_t mtime, double around)
902 {
903         this->mtime = mtime;
904         this->around = around;
905         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
906         show_date(mtime, cp, ep);
907         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
908                 if( cp < ep ) *cp++ = '+';
909                 show_duration(around, cp, ep);
910         }
911         *cp = 0;
912         filter->update_value(txt);
913 }
914
915 BC_Window *BinFolderTargetTime::new_gui(ModifyTargetThread *thread)
916 {
917         return new ModifyTargetTimeGUI(thread);
918 }
919
920
921 BinFolderTargetTrackType::BinFolderTargetTrackType(BinFolderFilter *filter)
922  : BinFolderTarget(filter, FOLDER_TARGET_TRACK_TYPE)
923 {
924         data_types = (1<<TRACK_AUDIO);
925         update(data_types);
926 }
927 BinFolderTargetTrackType::~BinFolderTargetTrackType()
928 {
929 }
930
931 void BinFolderTargetTrackType::save_xml(FileXML *file)
932 {
933         file->tag.set_property("DATA_TYPES", data_types);
934 }
935
936 void BinFolderTargetTrackType::load_xml(FileXML *file)
937 {
938         int data_types = file->tag.get_property("DATA_TYPES", this->data_types);
939         update(data_types);
940 }
941
942 void BinFolderTargetTrackType::copy_from(BinFolderTarget *that)
943 {
944         BinFolderTargetTrackType *tp = (BinFolderTargetTrackType *)that;
945         update(tp->data_types);
946 }
947
948 void BinFolderTargetTrackType::update(int data_types)
949 {
950         this->data_types = data_types;
951         this->around = -1;
952         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
953         if( data_types & (1<<TRACK_AUDIO) ) {
954                 if( cp > txt && cp < ep ) *cp++ = ' ';
955                 cp += snprintf(cp, ep-cp, "%s",_("audio"));
956         }
957         if( data_types & (1<<TRACK_VIDEO) ) {
958                 if( cp > txt && cp < ep ) *cp++ = ' ';
959                 cp += snprintf(cp, ep-cp, "%s",_("video"));
960         }
961         *cp = 0;
962         filter->update_value(txt);
963 }
964
965 BC_Window *BinFolderTargetTrackType::new_gui(ModifyTargetThread *thread)
966 {
967         return new ModifyTargetTrackTypeGUI(thread);
968 }
969
970
971 BinFolderTargetWidth::BinFolderTargetWidth(BinFolderFilter *filter)
972  : BinFolderTarget(filter, FOLDER_TARGET_WIDTH)
973 {
974         width = 0;
975         update(width, -1);
976 }
977 BinFolderTargetWidth::~BinFolderTargetWidth()
978 {
979 }
980
981 void BinFolderTargetWidth::save_xml(FileXML *file)
982 {
983         file->tag.set_property("WIDTH", width);
984         file->tag.set_property("AROUND", around);
985 }
986 void BinFolderTargetWidth::load_xml(FileXML *file)
987 {
988         int width = file->tag.get_property("WIDTH", this->width);
989         double around = file->tag.get_property("AROUND", this->around);
990         update(width, around);
991 }
992
993 void BinFolderTargetWidth::copy_from(BinFolderTarget *that)
994 {
995         BinFolderTargetWidth *tp = (BinFolderTargetWidth *)that;
996         update(tp->width, tp->around);
997 }
998
999 void BinFolderTargetWidth::update(int width, double around)
1000 {
1001         this->width = width;
1002         this->around = around;
1003         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
1004         show_no(width, cp, ep);
1005         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
1006                 if( cp < ep ) *cp++ = '+';
1007                 show_no(around, cp, ep);
1008         }
1009         *cp = 0;
1010         filter->update_value(txt);
1011 }
1012
1013 BC_Window *BinFolderTargetWidth::new_gui(ModifyTargetThread *thread)
1014 {
1015         return new ModifyTargetWidthGUI(thread);
1016 }
1017
1018
1019 BinFolderTargetHeight::BinFolderTargetHeight(BinFolderFilter *filter)
1020  : BinFolderTarget(filter, FOLDER_TARGET_HEIGHT)
1021 {
1022         height = 0;
1023         update(height, -1);
1024 }
1025 BinFolderTargetHeight::~BinFolderTargetHeight()
1026 {
1027 }
1028
1029 void BinFolderTargetHeight::save_xml(FileXML *file)
1030 {
1031         file->tag.set_property("HEIGHT", height);
1032         file->tag.set_property("AROUND", around);
1033 }
1034 void BinFolderTargetHeight::load_xml(FileXML *file)
1035 {
1036         int height = file->tag.get_property("HEIGHT", this->height);
1037         double around = file->tag.get_property("AROUND", this->around);
1038         update(height, around);
1039 }
1040
1041 void BinFolderTargetHeight::copy_from(BinFolderTarget *that)
1042 {
1043         BinFolderTargetHeight *tp = (BinFolderTargetHeight *)that;
1044         update(tp->height, tp->around);
1045 }
1046
1047 void BinFolderTargetHeight::update(int height, double around)
1048 {
1049         this->height = height;
1050         this->around = around;
1051         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
1052         show_no(height, cp, ep);
1053         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
1054                 if( cp < ep ) *cp++ = '+';
1055                 show_no(around, cp, ep);
1056         }
1057         *cp = 0;
1058         filter->update_value(txt);
1059 }
1060
1061 BC_Window *BinFolderTargetHeight::new_gui(ModifyTargetThread *thread)
1062 {
1063         return new ModifyTargetHeightGUI(thread);
1064 }
1065
1066
1067 BinFolderTargetFramerate::BinFolderTargetFramerate(BinFolderFilter *filter)
1068  : BinFolderTarget(filter, FOLDER_TARGET_FRAMERATE)
1069 {
1070         framerate = 0;
1071         update(framerate, -1);
1072 }
1073 BinFolderTargetFramerate::~BinFolderTargetFramerate()
1074 {
1075 }
1076
1077 void BinFolderTargetFramerate::save_xml(FileXML *file)
1078 {
1079         file->tag.set_property("FRAMERATE", framerate);
1080         file->tag.set_property("AROUND", around);
1081 }
1082
1083 void BinFolderTargetFramerate::load_xml(FileXML *file)
1084 {
1085         double framerate = file->tag.get_property("FRAMERATE", this->framerate);
1086         double around = file->tag.get_property("AROUND", this->around);
1087         update(framerate, around);
1088 }
1089
1090 void BinFolderTargetFramerate::copy_from(BinFolderTarget *that)
1091 {
1092         BinFolderTargetFramerate *tp = (BinFolderTargetFramerate *)that;
1093         update(tp->framerate, tp->around);
1094 }
1095
1096 void BinFolderTargetFramerate::update(double framerate, double around)
1097 {
1098         this->framerate = framerate;
1099         this->around = around;
1100         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
1101         show_no(framerate, cp, ep, "%0.3f");
1102         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
1103                 if( cp < ep ) *cp++ = '+';
1104                 show_no(around, cp, ep, "%0.3f");
1105         }
1106         *cp = 0;
1107         filter->update_value(txt);
1108 }
1109
1110 BC_Window *BinFolderTargetFramerate::new_gui(ModifyTargetThread *thread)
1111 {
1112         return new ModifyTargetFramerateGUI(thread);
1113 }
1114
1115
1116 BinFolderTargetSamplerate::BinFolderTargetSamplerate(BinFolderFilter *filter)
1117  : BinFolderTarget(filter, FOLDER_TARGET_SAMPLERATE)
1118 {
1119         samplerate = 0;
1120         update(samplerate, -1);
1121 }
1122
1123 BinFolderTargetSamplerate::~BinFolderTargetSamplerate()
1124 {
1125 }
1126
1127 void BinFolderTargetSamplerate::save_xml(FileXML *file)
1128 {
1129         file->tag.set_property("SAMPLERATE", samplerate);
1130         file->tag.set_property("AROUND", around);
1131 }
1132
1133 void BinFolderTargetSamplerate::load_xml(FileXML *file)
1134 {
1135         double samplerate = file->tag.get_property("SAMPLERATE", this->samplerate);
1136         double around = file->tag.get_property("AROUND", this->around);
1137         update(samplerate, around);
1138 }
1139
1140 void BinFolderTargetSamplerate::copy_from(BinFolderTarget *that)
1141 {
1142         BinFolderTargetSamplerate *tp = (BinFolderTargetSamplerate *)that;
1143         update(tp->samplerate, tp->around);
1144 }
1145
1146 void BinFolderTargetSamplerate::update(int samplerate, double around)
1147 {
1148         this->samplerate = samplerate;
1149         this->around = around;
1150         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
1151         show_no(samplerate, cp, ep);
1152         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
1153                 if( cp < ep ) *cp++ = '+';
1154                 show_no(around, cp, ep);
1155         }
1156         *cp = 0;
1157         filter->update_value(txt);
1158 }
1159
1160 BC_Window *BinFolderTargetSamplerate::new_gui(ModifyTargetThread *thread)
1161 {
1162         return new ModifyTargetSamplerateGUI(thread);
1163 }
1164
1165
1166 BinFolderTargetChannels::BinFolderTargetChannels(BinFolderFilter *filter)
1167  : BinFolderTarget(filter, FOLDER_TARGET_CHANNELS)
1168 {
1169         channels = 0;
1170         update(channels, -1);
1171 }
1172 BinFolderTargetChannels::~BinFolderTargetChannels()
1173 {
1174 }
1175
1176 void BinFolderTargetChannels::save_xml(FileXML *file)
1177 {
1178         file->tag.set_property("CHANNELS", channels);
1179         file->tag.set_property("AROUND", around);
1180 }
1181
1182 void BinFolderTargetChannels::load_xml(FileXML *file)
1183 {
1184         int channels = file->tag.get_property("CHANNELS", this->channels);
1185         double around = file->tag.get_property("AROUND", this->around);
1186         update(channels, around);
1187 }
1188
1189 void BinFolderTargetChannels::copy_from(BinFolderTarget *that)
1190 {
1191         BinFolderTargetChannels *tp = (BinFolderTargetChannels *)that;
1192         update(tp->channels, tp->around);
1193 }
1194
1195 void BinFolderTargetChannels::update(int channels, double around)
1196 {
1197         this->channels = channels;
1198         this->around = around;
1199         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
1200         show_no(channels, cp, ep);
1201         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
1202                 if( cp < ep ) *cp++ = '+';
1203                 show_no(around, cp, ep);
1204         }
1205         *cp = 0;
1206         filter->update_value(txt);
1207 }
1208
1209 BC_Window *BinFolderTargetChannels::new_gui(ModifyTargetThread *thread)
1210 {
1211         return new ModifyTargetChannelsGUI(thread);
1212 }
1213
1214
1215 BinFolderTargetDuration::BinFolderTargetDuration(BinFolderFilter *filter)
1216  : BinFolderTarget(filter, FOLDER_TARGET_DURATION)
1217 {
1218         duration = 0;
1219         update(duration, -1);
1220 }
1221 BinFolderTargetDuration::~BinFolderTargetDuration()
1222 {
1223 }
1224
1225 void BinFolderTargetDuration::save_xml(FileXML *file)
1226 {
1227         file->tag.set_property("DURATION", duration);
1228         file->tag.set_property("AROUND", around);
1229 }
1230
1231 void BinFolderTargetDuration::load_xml(FileXML *file)
1232 {
1233         int64_t duration = file->tag.get_property("DURATION", this->duration);
1234         double around = file->tag.get_property("AROUND", this->around);
1235         update(duration, around);
1236 }
1237
1238 void BinFolderTargetDuration::copy_from(BinFolderTarget *that)
1239 {
1240         BinFolderTargetDuration *tp = (BinFolderTargetDuration *)that;
1241         update(tp->duration, tp->around);
1242 }
1243
1244 void BinFolderTargetDuration::update(int64_t duration, double around)
1245 {
1246         this->duration = duration;
1247         this->around = around;
1248         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
1249         show_duration(duration, cp, ep);
1250         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
1251                 if( cp < ep ) *cp++ = '+';
1252                 show_duration(around, cp, ep);
1253         }
1254         *cp = 0;
1255         filter->update_value(txt);
1256 }
1257
1258 BC_Window *BinFolderTargetDuration::new_gui(ModifyTargetThread *thread)
1259 {
1260         return new ModifyTargetDurationGUI(thread);
1261 }
1262
1263
1264 BinFolderOp::BinFolderOp(BinFolderFilter *filter, int type)
1265  : BC_ListBoxItem(_(types[type]))
1266 {
1267         this->filter = filter;
1268         this->type = type;
1269 }
1270
1271 BinFolderOp::~BinFolderOp()
1272 {
1273 }
1274
1275 void BinFolderOp::copy_from(BinFolderOp *that)
1276 {
1277         type = that->type;
1278 }
1279
1280 BinFolderOpType::BinFolderOpType(int no)
1281  : BC_MenuItem(_(BinFolderOp::types[no]))
1282 {
1283         this->no = no;
1284 }
1285 BinFolderOpType::~BinFolderOpType()
1286 {
1287 }
1288
1289 int BinFolderOpType::handle_event()
1290 {
1291         BinFolderOpPopup *op_popup = (BinFolderOpPopup *)get_popup_menu();
1292         BinFolderList *folder_list = op_popup->folder_list;
1293         int i = folder_list->get_selection_number(FOLDER_COLUMN_OP, 0);
1294         if( i >= 0 ) {
1295                 BinFolder *folder = folder_list->folder;
1296                 BinFolderFilter *filter = folder->filters[i];
1297                 filter->update_op(no);
1298                 folder_list->create_list();
1299         }
1300         return 1;
1301 }
1302
1303 BinFolderOpPopup::BinFolderOpPopup(BinFolderList *folder_list)
1304  : BC_PopupMenu(0, 0, 0, "", 0)
1305 {
1306         this->folder_list = folder_list;
1307         op = 0;
1308 }
1309
1310 void BinFolderOpPopup::create_objects()
1311 {
1312         add_item(new BinFolderOpType(FOLDER_OP_AROUND));
1313         add_item(new BinFolderOpType(FOLDER_OP_EQ));
1314         add_item(new BinFolderOpType(FOLDER_OP_GE));
1315         add_item(new BinFolderOpType(FOLDER_OP_GT));
1316         add_item(new BinFolderOpType(FOLDER_OP_NE));
1317         add_item(new BinFolderOpType(FOLDER_OP_LE));
1318         add_item(new BinFolderOpType(FOLDER_OP_LT));
1319         add_item(new BinFolderOpType(FOLDER_OP_MATCHES));
1320 }
1321
1322 void BinFolderOpPopup::activate_menu(BC_ListBoxItem *item)
1323 {
1324         this->op = (BinFolderOp *)item;
1325         BC_PopupMenu::activate_menu();
1326 }
1327
1328 double BinFolderOp::test(BinFolderTarget *target, Indexable *idxbl)
1329 {
1330         return -1;
1331 }
1332
1333 double BinFolderOpEQ::test(BinFolderTarget *target, Indexable *idxbl)
1334 {
1335         double v = compare(target, idxbl);
1336         return v == 0 ? 1 : -1;
1337 }
1338
1339 double BinFolderOpGT::test(BinFolderTarget *target, Indexable *idxbl)
1340 {
1341         double v = compare(target, idxbl);
1342         return v > 0 ? 1 : -1;
1343 }
1344
1345 double BinFolderOpGE::test(BinFolderTarget *target, Indexable *idxbl)
1346 {
1347         double v = compare(target, idxbl);
1348         return v >= 0 ? 1 : -1;
1349 }
1350
1351 double BinFolderOpNE::test(BinFolderTarget *target, Indexable *idxbl)
1352 {
1353         double v = compare(target, idxbl);
1354         return v != 0 ? 1 : -1;
1355 }
1356
1357 double BinFolderOpLT::test(BinFolderTarget *target, Indexable *idxbl)
1358 {
1359         double v = compare(target, idxbl);
1360         return v < 0 ? 1 : -1;
1361 }
1362
1363 double BinFolderOpLE::test(BinFolderTarget *target, Indexable *idxbl)
1364 {
1365         double v = compare(target, idxbl);
1366         return v <= 0 ? 1 : -1;
1367 }
1368
1369 double BinFolderOpMatches::test(BinFolderTarget *target, Indexable *idxbl)
1370 {
1371         double v = compare(target, idxbl);
1372         return v;
1373 }
1374
1375 double BinFolderOpAround::test(BinFolderTarget *target, Indexable *idxbl)
1376 {
1377         double v = compare(target, idxbl);
1378         return v;
1379 }
1380
1381 BinFolderValue::BinFolderValue(BinFolderFilter *filter, const char *text)
1382  : BC_ListBoxItem()
1383 {
1384         this->filter = filter;
1385         update(text);
1386 }
1387
1388 BinFolderValue::~BinFolderValue()
1389 {
1390 }
1391
1392
1393 void BinFolderValue::update(const char *text)
1394 {
1395         const char *cp = text;
1396         char txt[BCSTRLEN], *tp = txt;
1397         for( int i=sizeof(txt); --i>0 && *cp!=0 && *cp!='\n'; ++tp,++cp ) *tp = *cp;
1398         *tp = 0;
1399         set_text(txt);
1400 }
1401
1402
1403 BinFolderList::BinFolderList(BinFolder *folder, MWindow *mwindow,
1404                 ModifyFolderGUI *window, int x, int y, int w, int h)
1405  : BC_ListBox(x, y, w, h, LISTBOX_TEXT, 0,
1406         0, 0, 1, 0, 0, LISTBOX_SINGLE, ICON_LEFT, 1)
1407 {
1408         this->folder = folder;
1409         this->mwindow = mwindow;
1410         this->window = window;
1411         dragging_item = 0;
1412         set_process_drag(1);
1413         enabled_popup = 0;
1414         op_popup = 0;
1415         target_popup = 0;
1416         modify_target = 0;
1417 }
1418
1419 BinFolderList::~BinFolderList()
1420 {
1421         save_defaults(mwindow->defaults);
1422         delete modify_target;
1423 }
1424
1425 void BinFolderList::create_objects()
1426 {
1427         list_titles[FOLDER_COLUMN_ENABLE] = _("Enable");
1428         list_titles[FOLDER_COLUMN_TARGET] = _("Target");
1429         list_titles[FOLDER_COLUMN_OP]     = _("Op");
1430         list_titles[FOLDER_COLUMN_VALUE]  = _("Value");
1431         list_width[FOLDER_COLUMN_ENABLE]  = 80;
1432         list_width[FOLDER_COLUMN_TARGET]  = 80;
1433         list_width[FOLDER_COLUMN_OP]      = 50;
1434         list_width[FOLDER_COLUMN_VALUE]   = 180;
1435         load_defaults(mwindow->defaults);
1436         create_list();
1437         add_subwindow(enabled_popup = new BinFolderEnabledPopup(this));
1438         enabled_popup->create_objects();
1439         add_subwindow(op_popup = new BinFolderOpPopup(this));
1440         op_popup->create_objects();
1441         add_subwindow(target_popup = new BinFolderTargetPopup(this));
1442         target_popup->create_objects();
1443
1444         modify_target = new ModifyTargetThread(this);
1445 }
1446
1447 void BinFolderList::create_list()
1448 {
1449         for( int i=0; i<FOLDER_COLUMNS; ++i )
1450                 list_items[i].remove_all();
1451         for( int i=0; i<folder->filters.size(); ++i ) {
1452                 BinFolderFilter *filter = folder->filters[i];
1453                 list_items[FOLDER_COLUMN_ENABLE].append(filter->enabled);
1454                 list_items[FOLDER_COLUMN_TARGET].append(filter->target);
1455                 list_items[FOLDER_COLUMN_OP].append(filter->op);
1456                 list_items[FOLDER_COLUMN_VALUE].append(filter->value);
1457         }
1458         update(list_items, list_titles, list_width, FOLDER_COLUMNS,
1459                 get_xposition(), get_yposition(), get_highlighted_item(),
1460                 1, 1);
1461 }
1462
1463 int BinFolderList::handle_event()
1464 {
1465         return 1;
1466 }
1467
1468 int BinFolderList::selection_changed()
1469 {
1470         if( !cursor_above() ) return 0;
1471         int no = get_selection_number(0, 0);
1472         if( no < 0 ) return 0;
1473         BinFolderFilter *filter = folder->filters[no];
1474         if( get_button_down() && get_buttonpress() == 3 ) {
1475                 int cx = get_cursor_x(), col = -1;
1476                 for( int i=0; col<0 && i<FOLDER_COLUMNS; ++i ) {
1477                         int ofs = get_column_offset(i);
1478                         if( cx >= ofs && cx < ofs+get_column_width(i) ) {
1479                                 col = i;  break;
1480                         }
1481                 }
1482                 BC_ListBoxItem *item = col >= 0 ? get_selection(col, 0) : 0;
1483                 if( item ) {
1484                         deactivate_selection();
1485                         switch( col ) {
1486                         case FOLDER_COLUMN_ENABLE:
1487                                 enabled_popup->activate_menu(item);
1488                                 break;
1489                         case FOLDER_COLUMN_TARGET:
1490                                 target_popup->activate_menu(item);
1491                                 break;
1492                         case FOLDER_COLUMN_OP:
1493                                 op_popup->activate_menu(item);
1494                                 break;
1495                         case FOLDER_COLUMN_VALUE: {
1496                                 modify_target->close_window();
1497                                 int cw = filter->target->type == FOLDER_TARGET_PATTERNS ? 400 : 320;
1498                                 int ch = filter->target->type == FOLDER_TARGET_PATTERNS ? 300 : 120;
1499                                 int cx, cy;  get_abs_cursor(cx, cy);
1500                                 if( (cx-=cw/2) < 50 ) cx = 50;
1501                                 if( (cy-=ch/2) < 50 ) cy = 50;
1502                                 modify_target->start(filter->target, cx, cy, cw, ch);
1503                                 break; }
1504                         }
1505                 }
1506         }
1507         return 1;
1508 }
1509
1510 int BinFolderList::column_resize_event()
1511 {
1512         for( int i = 0; i < FOLDER_COLUMNS; i++ ) {
1513                 list_width[i] = get_column_width(i);
1514         }
1515         return 1;
1516 }
1517
1518 int BinFolderList::drag_start_event()
1519 {
1520         if( BC_ListBox::drag_start_event() ) {
1521                 dragging_item = 1;
1522                 return 1;
1523         }
1524
1525         return 0;
1526 }
1527
1528 int BinFolderList::drag_motion_event()
1529 {
1530         if( BC_ListBox::drag_motion_event() ) {
1531                 return 1;
1532         }
1533         return 0;
1534 }
1535
1536 int BinFolderList::drag_stop_event()
1537 {
1538         if( dragging_item ) {
1539                 int src = get_selection_number(0, 0);
1540                 int dst = get_highlighted_item();
1541                 if( src != dst ) {
1542                         move_filter(src, dst);
1543                 }
1544                 BC_ListBox::drag_stop_event();
1545                 dragging_item = 0;
1546         }
1547         return 0;
1548 }
1549
1550 void BinFolderList::move_filter(int src, int dst)
1551 {
1552         BinFolderFilters &filters = folder->filters;
1553         BinFolderFilter *src_filter = filters[src];
1554         if( dst < 0 ) dst = filters.size()-1;
1555
1556         if( dst != src ) {
1557                 for( int i=src; i<filters.size()-1; ++i )
1558                         filters[i] = filters[i+1];
1559                 for( int i=filters.size(); --i>dst; )
1560                         filters[i] = filters[i-1];
1561                 filters[dst] = src_filter;
1562         }
1563 }
1564
1565 void BinFolderList::save_defaults(BC_Hash *defaults)
1566 {
1567         defaults->update("BIN_FOLDER_ENA", list_width[FOLDER_COLUMN_ENABLE]);
1568         defaults->update("BIN_FOLDER_TGT", list_width[FOLDER_COLUMN_TARGET]);
1569         defaults->update("BIN_FOLDER_OPR", list_width[FOLDER_COLUMN_OP]);
1570         defaults->update("BIN_FOLDER_VAL", list_width[FOLDER_COLUMN_VALUE]);
1571 }
1572 void BinFolderList::load_defaults(BC_Hash *defaults)
1573 {
1574         list_width[FOLDER_COLUMN_ENABLE] = defaults->get("BIN_FOLDER_ENA", list_width[FOLDER_COLUMN_ENABLE]);
1575         list_width[FOLDER_COLUMN_TARGET] = defaults->get("BIN_FOLDER_TGT", list_width[FOLDER_COLUMN_TARGET]);
1576         list_width[FOLDER_COLUMN_OP]     = defaults->get("BIN_FOLDER_OPR", list_width[FOLDER_COLUMN_OP]);
1577         list_width[FOLDER_COLUMN_VALUE]  = defaults->get("BIN_FOLDER_VAL", list_width[FOLDER_COLUMN_VALUE]);
1578 }
1579
1580 BinFolderAddFilter::BinFolderAddFilter(BinFolderList *folder_list, int x, int y)
1581  : BC_GenericButton(x, y, _("Add"))
1582 {
1583         this->folder_list = folder_list;
1584 }
1585 BinFolderAddFilter::~BinFolderAddFilter()
1586 {
1587 }
1588
1589 int BinFolderAddFilter::handle_event()
1590 {
1591         folder_list->modify_target->close_window();
1592 // default new filter
1593         BinFolderFilter *filter = new BinFolderFilter();
1594         filter->update_enabled(FOLDER_ENABLED_OR);
1595         filter->update_target(FOLDER_TARGET_PATTERNS);
1596         filter->update_op(FOLDER_OP_MATCHES);
1597         BinFolderTargetPatterns *patterns = (BinFolderTargetPatterns *)(filter->target);
1598         filter->update_value(patterns->text);
1599         folder_list->folder->filters.append(filter);
1600         folder_list->create_list();
1601         return 1;
1602 }
1603
1604 BinFolderDelFilter::BinFolderDelFilter(BinFolderList *folder_list, int x, int y)
1605  : BC_GenericButton(x, y, _("Del"))
1606 {
1607         this->folder_list = folder_list;
1608 }
1609 BinFolderDelFilter::~BinFolderDelFilter()
1610 {
1611 }
1612
1613 int BinFolderDelFilter::handle_event()
1614 {
1615         folder_list->modify_target->close_window();
1616         int no = folder_list->get_selection_number(0, 0);
1617         if( no >= 0 ) {
1618                 folder_list->folder->filters.remove_object_number(no);
1619                 folder_list->create_list();
1620         }
1621         return 1;
1622 }
1623
1624 BinFolderApplyFilter::BinFolderApplyFilter(BinFolderList *folder_list, int x, int y)
1625  : BC_GenericButton(x, y, _("Apply"))
1626 {
1627         this->folder_list = folder_list;
1628 }
1629 BinFolderApplyFilter::~BinFolderApplyFilter()
1630 {
1631 }
1632
1633 int BinFolderApplyFilter::handle_event()
1634 {
1635         ModifyFolderThread *thread = folder_list->window->thread;
1636         thread->original->copy_from(thread->folder);
1637         thread->agui->async_update_assets();
1638         return 1;
1639 }
1640
1641
1642 NewFolderGUI::NewFolderGUI(NewFolderThread *thread, int x, int y, int w, int h)
1643  : BC_Window(_(PROGRAM_NAME ": New folder"),
1644                 x, y, w, h, -1, -1, 0, 0, 1)
1645 {
1646         this->thread = thread;
1647 }
1648
1649 NewFolderGUI::~NewFolderGUI()
1650 {
1651 }
1652
1653 void NewFolderGUI::create_objects()
1654 {
1655         lock_window("NewFolderGUI::create_objects");
1656         int x = 10, y = 10;
1657         BC_Title *title;
1658         add_subwindow(title = new BC_Title(x, y, _("Enter the name of the folder:")));
1659         y += title->get_h() + 5;
1660         add_subwindow(text_box = new BC_TextBox(x, y, 300, 1, _("Untitled")));
1661         add_subwindow(new BC_OKButton(this));
1662         add_subwindow(new BC_CancelButton(this));
1663         show_window();
1664         unlock_window();
1665 }
1666
1667 const char* NewFolderGUI::get_text()
1668 {
1669         return text_box->get_text();
1670 }
1671
1672
1673 NewFolderThread::NewFolderThread(AWindowGUI *agui)
1674  : BC_DialogThread()
1675 {
1676         this->agui = agui;
1677 }
1678
1679 NewFolderThread::~NewFolderThread()
1680 {
1681         close_window();
1682 }
1683
1684 void NewFolderThread::start(int x, int y, int w, int h)
1685 {
1686         close_window();
1687         wx = x;  wy = y;
1688         ww = w;  wh = h;
1689         Thread::start();
1690 }
1691
1692 BC_Window *NewFolderThread::new_gui()
1693 {
1694         window = new NewFolderGUI(this, wx, wy, ww, wh);
1695         window->create_objects();
1696         return window;
1697 }
1698
1699 void NewFolderThread::handle_done_event(int result)
1700 {
1701         if( !result ) {
1702                 const char *text = window->get_text();
1703                 agui->mwindow->new_folder(text);
1704         }
1705 }
1706
1707 void NewFolderThread::handle_close_event(int result)
1708 {
1709 }
1710
1711 ModifyFolderGUI::ModifyFolderGUI(ModifyFolderThread *thread, int x, int y, int w, int h)
1712  : BC_Window(_(PROGRAM_NAME ": Modify folder"), x, y, w, h, 320, 200, 1, 0, 1)
1713 {
1714         this->thread = thread;
1715 }
1716
1717 ModifyFolderGUI::~ModifyFolderGUI()
1718 {
1719 }
1720
1721 int ModifyFolderGUI::receive_custom_xatoms(xatom_event *event)
1722 {
1723         if( event->message_type == modify_folder_xatom ) {
1724                 update_filters();
1725                 return 1;
1726         }
1727         return 0;
1728 }
1729
1730 void ModifyFolderGUI::async_update_filters()
1731 {
1732         xatom_event event;
1733         event.message_type = modify_folder_xatom;
1734         send_custom_xatom(&event);
1735 }
1736
1737
1738 void ModifyFolderGUI::create_objects()
1739 {
1740         lock_window("ModifyFolderGUI::create_objects");
1741         modify_folder_xatom = create_xatom("CWINDOWGUI_UPDATE_FILTERS");
1742         int x = 10, y = 10;
1743         add_tool(new BC_Title(x, y, _("Enter the name of the folder:")));
1744         y += 20;
1745         add_subwindow(text_box = new BC_TextBox(x, y, 300, 1, thread->folder->title));
1746         y += 30;
1747         int lh = get_h() - y - BC_OKButton::calculate_h() - 30;
1748         int lw = get_w() - x - 120;
1749         add_subwindow(folder_list =
1750                 new BinFolderList(thread->folder, thread->agui->mwindow, this, x, y, lw, lh));
1751         folder_list->create_objects();
1752         int x1 = x + folder_list->get_w() + 15, y1 = y;
1753         add_subwindow(add_filter = new BinFolderAddFilter(folder_list, x1, y1));
1754         y1 += add_filter->get_h() + 10;
1755         add_subwindow(del_filter = new BinFolderDelFilter(folder_list, x1, y1));
1756         y1 += del_filter->get_h() + 10;
1757         add_subwindow(apply_filter = new BinFolderApplyFilter(folder_list, x1, y1));
1758         add_subwindow(ok_button = new BC_OKButton(this));
1759         add_subwindow(cancel_button = new BC_CancelButton(this));
1760         show_window();
1761         unlock_window();
1762 }
1763
1764 int ModifyFolderGUI::resize_event(int w, int h)
1765 {
1766         MWindow *mwindow = thread->agui->mwindow;
1767         mwindow->session->bwindow_w = w;
1768         mwindow->session->bwindow_h = h;
1769         int lx = folder_list->get_x();
1770         int ly = folder_list->get_y();
1771         int lh = h - ly - BC_OKButton::calculate_h() - 30;
1772         int lw = w - lx - 120;
1773         folder_list->reposition_window(lx, ly, lw, lh);
1774         int x1 = lx + lw + 15;
1775         add_filter->reposition_window(x1, add_filter->get_y());
1776         del_filter->reposition_window(x1, del_filter->get_y());
1777         apply_filter->reposition_window(x1,apply_filter->get_y());
1778         ok_button->resize_event(w, h);
1779         cancel_button->resize_event(w, h);
1780         return 1;
1781 }
1782
1783 const char* ModifyFolderGUI::get_text()
1784 {
1785         return text_box->get_text();
1786 }
1787
1788 void ModifyFolderGUI::update_filters()
1789 {
1790         folder_list->create_list();
1791 }
1792
1793
1794 ModifyFolderThread::ModifyFolderThread(AWindowGUI *agui)
1795  : BC_DialogThread()
1796 {
1797         this->agui = agui;
1798         original = 0;
1799         folder = 0;
1800 }
1801
1802 ModifyFolderThread::~ModifyFolderThread()
1803 {
1804         close_window();
1805         delete folder;
1806 }
1807
1808 void ModifyFolderThread::start(BinFolder *folder, int x, int y, int w, int h)
1809 {
1810         close_window();
1811         this->original = folder;
1812         agui->mwindow->edl->add_user();
1813         this->folder = new BinFolder(*folder);
1814         wx = x;  wy = y;
1815         ww = w;  wh = h;
1816         Thread::start();
1817 }
1818
1819 BC_Window *ModifyFolderThread::new_gui()
1820 {
1821         window = new ModifyFolderGUI(this, wx, wy, ww, wh);
1822         window->create_objects();
1823         return window;
1824 }
1825
1826 void ModifyFolderThread::handle_done_event(int result)
1827 {
1828         if( !result ) {
1829                 const char *title = window->get_text();
1830                 if( strcmp(folder->title, title) ) {
1831                         if( agui->mwindow->edl->get_folder_number(title) >= 0 ) {
1832                                 eprintf("folder already exists: %s", title);
1833                                 result = 1;
1834                         }
1835                         else
1836                                 strncpy(folder->title, title,sizeof(folder->title));
1837                 }
1838         }
1839         if( !result ) {
1840                 original->copy_from(folder);
1841                 agui->async_update_assets();
1842         }
1843         delete folder;  folder = 0;
1844         original = 0;
1845         agui->mwindow->edl->remove_user();
1846 }
1847
1848 void ModifyFolderThread::handle_close_event(int result)
1849 {
1850 }
1851
1852
1853 ModifyTargetThread::ModifyTargetThread(BinFolderList *folder_list)
1854  : BC_DialogThread()
1855 {
1856         this->folder_list = folder_list;
1857         target = 0;
1858 }
1859
1860 ModifyTargetThread::~ModifyTargetThread()
1861 {
1862         close_window();
1863 }
1864
1865 void ModifyTargetThread::start(BinFolderTarget *target, int x, int y, int w, int h)
1866 {
1867         this->target = target;
1868         wx = x;  wy = y;
1869         ww = w;  wh = h;
1870         Thread::start();
1871 }
1872
1873 BC_Window *ModifyTargetThread::new_gui()
1874 {
1875         window = (ModifyTargetGUI *)target->new_gui(this);
1876         window->create_objects();
1877         return window;
1878 }
1879
1880 void ModifyTargetThread::handle_done_event(int result)
1881 {
1882         if( !result ) {
1883                 window->update();
1884                 folder_list->window->async_update_filters();
1885         }
1886 }
1887
1888 void ModifyTargetThread::handle_close_event(int result)
1889 {
1890         target = 0;
1891 }
1892
1893 ModifyTargetGUI::ModifyTargetGUI(ModifyTargetThread *thread)
1894  : BC_Window(_(PROGRAM_NAME ": Modify target"),
1895                 thread->wx, thread->wy, thread->ww, thread->wh,
1896                 -1, -1, 0, 0, 1)
1897 {
1898         this->thread = thread;
1899 }
1900
1901 ModifyTargetGUI::~ModifyTargetGUI()
1902 {
1903 }
1904
1905 void ModifyTargetGUI::create_objects(BC_TextBox *&text_box)
1906 {
1907         lock_window("ModifyTargetGUI::create_objects");
1908         int x = 10, y = 10;
1909         const char *text = thread->target->filter->value->get_text();
1910         add_subwindow(text_box = new BC_TextBox(x, y, get_w()-20, 1, text));
1911         add_subwindow(new BC_OKButton(this));
1912         add_subwindow(new BC_CancelButton(this));
1913         show_window();
1914         unlock_window();
1915 }
1916
1917 ModifyTargetPatternsGUI::ModifyTargetPatternsGUI(ModifyTargetThread *thread)
1918  : ModifyTargetGUI(thread)
1919 {
1920         this->thread = thread;
1921         scroll_text_box = 0;
1922 }
1923
1924 ModifyTargetPatternsGUI::~ModifyTargetPatternsGUI()
1925 {
1926         delete scroll_text_box;
1927 }
1928
1929 void ModifyTargetPatternsGUI::create_objects()
1930 {
1931         lock_window("ModifyTargetPatternsGUI::create_objects");
1932         BinFolderTargetPatterns *target = (BinFolderTargetPatterns *)thread->target;
1933         int x = 10, y = 10;
1934         int text_font = MEDIUMFONT;
1935         int text_rowsz = get_text_ascent(text_font)+1 + get_text_descent(text_font)+1;
1936         int th = get_h() - BC_OKButton::calculate_h() - y - 10;
1937         int rows = th / text_rowsz;
1938         scroll_text_box = new BC_ScrollTextBox(this, x, y, get_w()-20, rows, target->text);
1939         scroll_text_box->create_objects();
1940         add_subwindow(new BC_OKButton(this));
1941         add_subwindow(new BC_CancelButton(this));
1942         show_window();
1943         unlock_window();
1944 }
1945
1946 void ModifyTargetPatternsGUI::update()
1947 {
1948         BinFolderTargetPatterns *target = (BinFolderTargetPatterns *)thread->target;
1949         const char *cp = scroll_text_box->get_text();
1950         target->update(cp);
1951 }
1952
1953
1954 ModifyTargetFileSizeGUI::ModifyTargetFileSizeGUI(ModifyTargetThread *thread)
1955  : ModifyTargetGUI(thread)
1956 {
1957 }
1958
1959 ModifyTargetFileSizeGUI::~ModifyTargetFileSizeGUI()
1960 {
1961 }
1962
1963 void ModifyTargetFileSizeGUI::create_objects()
1964 {
1965         ModifyTargetGUI::create_objects(text_box);
1966 }
1967
1968 void ModifyTargetFileSizeGUI::update()
1969 {
1970         BinFolderTargetFileSize *target = (BinFolderTargetFileSize *)thread->target;
1971         double file_size = target->file_size, around = target->around;
1972         const char *cp = text_box->get_text();  char *bp = 0;
1973         scan_around(cp, bp, file_size, around);
1974         target->update(file_size, around);
1975 }
1976
1977
1978 ModifyTargetTimeGUI::ModifyTargetTimeGUI(ModifyTargetThread *thread)
1979  : ModifyTargetGUI(thread)
1980 {
1981 }
1982
1983 ModifyTargetTimeGUI::~ModifyTargetTimeGUI()
1984 {
1985 }
1986
1987 void ModifyTargetTimeGUI::create_objects()
1988 {
1989         ModifyTargetGUI::create_objects(text_box);
1990 }
1991
1992 void ModifyTargetTimeGUI::update()
1993 {
1994         BinFolderTargetTime *target = (BinFolderTargetTime *)thread->target;
1995         int64_t mtime = target->mtime;  double around = target->around;
1996         const char *cp = text_box->get_text(); char *bp = 0;
1997         int64_t v = scan_date(cp, bp);
1998         if( bp > cp ) {
1999                 mtime = v;
2000                 if( *bp == '+' ) {
2001                         v = scan_duration(cp=bp+1, bp);
2002                         if( bp > cp ) around = v;
2003                 }
2004         }
2005         target->update(mtime, around);
2006 }
2007
2008
2009 ModifyTargetTrackTypeGUI::ModifyTargetTrackTypeGUI(ModifyTargetThread *thread)
2010  : ModifyTargetGUI(thread)
2011 {
2012 }
2013
2014 ModifyTargetTrackTypeGUI::~ModifyTargetTrackTypeGUI()
2015 {
2016 }
2017
2018 void ModifyTargetTrackTypeGUI::create_objects()
2019 {
2020         ModifyTargetGUI::create_objects(text_box);
2021 }
2022
2023 void ModifyTargetTrackTypeGUI::update()
2024 {
2025         BinFolderTargetTrackType *target = (BinFolderTargetTrackType *)thread->target;
2026         const char *cp = text_box->get_text();
2027         int data_types = 0;
2028         if( bstrcasestr(cp, _("audio")) ) data_types |= (1<<TRACK_AUDIO);
2029         if( bstrcasestr(cp, _("video")) ) data_types |= (1<<TRACK_VIDEO);
2030         target->update(data_types);
2031 }
2032
2033
2034 ModifyTargetWidthGUI::ModifyTargetWidthGUI(ModifyTargetThread *thread)
2035  : ModifyTargetGUI(thread)
2036 {
2037 }
2038
2039 ModifyTargetWidthGUI::~ModifyTargetWidthGUI()
2040 {
2041 }
2042
2043 void ModifyTargetWidthGUI::create_objects()
2044 {
2045         ModifyTargetGUI::create_objects(text_box);
2046 }
2047
2048 void ModifyTargetWidthGUI::update()
2049 {
2050         BinFolderTargetWidth *target = (BinFolderTargetWidth *)thread->target;
2051         double width = target->width, around = target->around;
2052         const char *cp = text_box->get_text();  char *bp = 0;
2053         scan_around(cp, bp, width, around);
2054         target->update(width, around);
2055 }
2056
2057
2058 ModifyTargetHeightGUI::ModifyTargetHeightGUI(ModifyTargetThread *thread)
2059  : ModifyTargetGUI(thread)
2060 {
2061 }
2062
2063 ModifyTargetHeightGUI::~ModifyTargetHeightGUI()
2064 {
2065 }
2066
2067 void ModifyTargetHeightGUI::create_objects()
2068 {
2069         ModifyTargetGUI::create_objects(text_box);
2070 }
2071
2072 void ModifyTargetHeightGUI::update()
2073 {
2074         BinFolderTargetHeight *target = (BinFolderTargetHeight *)thread->target;
2075         double height = target->height, around = target->around;
2076         const char *cp = text_box->get_text();  char *bp = 0;
2077         scan_around(cp, bp, height, around);
2078         target->update(height, around);
2079 }
2080
2081
2082 ModifyTargetFramerateGUI::ModifyTargetFramerateGUI(ModifyTargetThread *thread)
2083  : ModifyTargetGUI(thread)
2084 {
2085 }
2086
2087 ModifyTargetFramerateGUI::~ModifyTargetFramerateGUI()
2088 {
2089 }
2090
2091 void ModifyTargetFramerateGUI::create_objects()
2092 {
2093         ModifyTargetGUI::create_objects(text_box);
2094 }
2095
2096 void ModifyTargetFramerateGUI::update()
2097 {
2098         BinFolderTargetFramerate *target = (BinFolderTargetFramerate *)thread->target;
2099         double framerate = target->framerate, around = target->around;
2100         const char *cp = text_box->get_text();  char *bp = 0;
2101         scan_around(cp, bp, framerate, around);
2102         target->update(framerate, around);
2103 }
2104
2105
2106 ModifyTargetSamplerateGUI::ModifyTargetSamplerateGUI(ModifyTargetThread *thread)
2107  : ModifyTargetGUI(thread)
2108 {
2109 }
2110
2111 ModifyTargetSamplerateGUI::~ModifyTargetSamplerateGUI()
2112 {
2113 }
2114
2115 void ModifyTargetSamplerateGUI::create_objects()
2116 {
2117         ModifyTargetGUI::create_objects(text_box);
2118 }
2119
2120 void ModifyTargetSamplerateGUI::update()
2121 {
2122         BinFolderTargetSamplerate *target = (BinFolderTargetSamplerate *)thread->target;
2123         double samplerate = target->samplerate, around = target->around;
2124         const char *cp = text_box->get_text();  char *bp = 0;
2125         scan_around(cp, bp, samplerate, around);
2126         target->update(samplerate, around);
2127 }
2128
2129
2130 ModifyTargetChannelsGUI::ModifyTargetChannelsGUI(ModifyTargetThread *thread)
2131  : ModifyTargetGUI(thread)
2132 {
2133 }
2134
2135 ModifyTargetChannelsGUI::~ModifyTargetChannelsGUI()
2136 {
2137 }
2138
2139 void ModifyTargetChannelsGUI::create_objects()
2140 {
2141         ModifyTargetGUI::create_objects(text_box);
2142 }
2143
2144 void ModifyTargetChannelsGUI::update()
2145 {
2146         BinFolderTargetChannels *target = (BinFolderTargetChannels *)thread->target;
2147         double channels = target->channels, around = target->around;
2148         const char *cp = text_box->get_text();  char *bp = 0;
2149         scan_around(cp, bp, channels, around);
2150         target->update(channels, around);
2151 }
2152
2153
2154 ModifyTargetDurationGUI::ModifyTargetDurationGUI(ModifyTargetThread *thread)
2155  : ModifyTargetGUI(thread)
2156 {
2157 }
2158
2159 ModifyTargetDurationGUI::~ModifyTargetDurationGUI()
2160 {
2161 }
2162
2163 void ModifyTargetDurationGUI::create_objects()
2164 {
2165         ModifyTargetGUI::create_objects(text_box);
2166 }
2167
2168 void ModifyTargetDurationGUI::update()
2169 {
2170         BinFolderTargetDuration *target = (BinFolderTargetDuration *)thread->target;
2171         int64_t duration = target->duration, around = target->around;
2172         const char *cp = text_box->get_text();  char *bp = 0;
2173         int64_t v = scan_duration(cp, bp);
2174         if( bp > cp ) {
2175                 duration = v;
2176                 if( *bp == '+' ) {
2177                         v = scan_duration(cp=bp+1, bp);
2178                         if( bp > cp ) around = v;
2179                 }
2180         }
2181         target->update(duration, around);
2182 }
2183