Example #1
0
TagEditor::TagEditor(QWidget *parent, const QList<Song> &songs,
                     const QSet<QString> &existingArtists, const QSet<QString> &existingAlbumArtists, const QSet<QString> &existingComposers,
                     const QSet<QString> &existingAlbums, const QSet<QString> &existingGenres, const QString &udi)
    : Dialog(parent, "TagEditor", QSize(500, 200))
    #ifdef ENABLE_DEVICES_SUPPORT
    , deviceUdi(udi)
    #endif
    , currentSongIndex(-1)
    , updating(false)
    , haveArtists(false)
    , haveAlbumArtists(false)
    , haveComposers(false)
    , haveAlbums(false)
    , haveGenres(false)
    , saving(false)
{
    iCount++;
    foreach (const Song &s, songs) {
        if (CueFile::isCue(s.file)) {
            continue;
        }
        if (s.guessed) {
            Song song(s);
            song.revertGuessedTags();
            original.append(song);
        } else {
            original.append(s);
        }
    }

    if (original.isEmpty()) {
        deleteLater();
        return;
    }

    #ifdef ENABLE_DEVICES_SUPPORT
    if (deviceUdi.isEmpty()) {
        baseDir=MPDConnection::self()->getDetails().dir;
    } else {
        Device *dev=getDevice(udi, parentWidget());

        if (!dev) {
            deleteLater();
            return;
        }

        baseDir=dev->path();
    }
    #else
    Q_UNUSED(udi)
    baseDir=MPDConnection::self()->getDetails().dir;
    #endif
    qSort(original);

    QWidget *mainWidet = new QWidget(this);
    setupUi(mainWidet);
    track->setAllowEmpty();
    disc->setAllowEmpty();
    year->setAllowEmpty();
    setMainWidget(mainWidet);
    ButtonCodes buttons=Ok|Cancel|Reset|User3;
    if (songs.count()>1) {
        buttons|=User2|User1;
    }
    setButtons(buttons);
    setCaption(i18n("Tags"));
    progress->setVisible(false);
    if (songs.count()>1) {
        setButtonGuiItem(User2, StdGuiItem::back(true));
        setButtonGuiItem(User1,StdGuiItem::forward(true));
        enableButton(User1, false);
        enableButton(User2, false);
    }
    setButtonGuiItem(Ok, StdGuiItem::save());
    setButtonGuiItem(User3, GuiItem(i18n("Tools"), "tools-wizard"));
    QMenu *toolsMenu=new QMenu(this);
    toolsMenu->addAction(i18n("Apply \"Various Artists\" Workaround"), this, SLOT(applyVa()));
    toolsMenu->addAction(i18n("Revert \"Various Artists\" Workaround"), this, SLOT(revertVa()));
    toolsMenu->addAction(i18n("Set 'Album Artist' from 'Artist'"), this, SLOT(setAlbumArtistFromArtist()));
    toolsMenu->addAction(i18n("Capitalize"), this, SLOT(capitalise()));
    toolsMenu->addAction(i18n("Adjust Track Numbers"), this, SLOT(adjustTrackNumbers()));
    setButtonMenu(User3, toolsMenu, InstantPopup);
    enableButton(Ok, false);
    enableButton(Reset, false);

    setAttribute(Qt::WA_DeleteOnClose);

    QStringList strings=existingArtists.toList();
    strings.sort();
    artist->clear();
    artist->insertItems(0, strings);

    strings=existingAlbumArtists.toList();
    strings.sort();
    albumArtist->clear();
    albumArtist->insertItems(0, strings);

    strings=existingComposers.toList();
    strings.sort();
    composer->clear();
    composer->insertItems(0, strings);

    strings=existingAlbums.toList();
    strings.sort();
    album->clear();
    album->insertItems(0, strings);

    strings=existingGenres.toList();
    strings.sort();
    genre->clear();
    genre->insertItems(0, strings);

    trackName->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
    trackName->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
    trackName->view()->setTextElideMode(Qt::ElideLeft);

    if (original.count()>1) {
        QSet<QString> songArtists;
        QSet<QString> songAlbumArtists;
        QSet<QString> songAlbums;
        QSet<QString> songGenres;
        QSet<QString> songComposers;
        QSet<int> songYears;
        QSet<int> songDiscs;

        foreach (const Song &s, original) {
            if (!s.artist.isEmpty()) {
                songArtists.insert(s.artist);
            }
            if (!s.albumartist.isEmpty()) {
                songAlbumArtists.insert(s.albumartist);
            }
            if (!s.album.isEmpty()) {
                songAlbums.insert(s.album);
            }
            if (!s.genre.isEmpty()) {
                songGenres.insert(s.genre);
            }
            if (!s.composer.isEmpty()) {
                songComposers.insert(s.composer);
            }
            songYears.insert(s.year);
            songDiscs.insert(s.disc);
            if (songArtists.count()>1 && songAlbumArtists.count()>1 && songAlbums.count()>1 &&
                songGenres.count()>1 && songYears.count()>1 && songDiscs.count()>1 && songComposers.count()>=1) {
                break;
            }
        }
        Song all;
        all.file.clear();
        all.title.clear();
        all.track=0;
        all.artist=1==songArtists.count() ? *(songArtists.begin()) : QString();
        all.composer=1==songComposers.count() ? *(songComposers.begin()) : QString();
        all.albumartist=1==songAlbumArtists.count() ? *(songAlbumArtists.begin()) : QString();
        all.album=1==songAlbums.count() ? *(songAlbums.begin()) : QString();
        all.genre=1==songGenres.count() ? *(songGenres.begin()) : QString();
        all.year=1==songYears.count() ? *(songYears.begin()) : 0;
        all.disc=1==songDiscs.count() ? *(songDiscs.begin()) : 0;
        original.prepend(all);
        artist->setFocus();
        haveArtists=!songArtists.isEmpty();
        haveAlbumArtists=!songAlbumArtists.isEmpty();
        haveAlbums=!songAlbums.isEmpty();
        haveGenres=!songGenres.isEmpty();
        haveComposers=!songComposers.isEmpty();
    } else {
Example #2
0
function main(in mode, in select, in nfilters, dim& filters) {

	if (false && mode && select && nfilters && filters(0,0)){};

	var filename = SENTENCE.field(" ", 2);
	var file;
	if (not(file.open(filename))) {
		return fsmsg();
	}

	var sentencex = SENTENCE;
	sentencex.converter(" ", VM);
	if (sentencex.locate("SELECT", temp, 1)) {
		selectx = SENTENCE.field(" ", temp + 1, 9999);
		sentencex = SENTENCE.field(" ", 1, temp - 1);
	}else{
		sentencex = SENTENCE;
		selectx = "";
	}

	var normalise = sentencex.index(" NORMALISE", 1);
	if (normalise) {
		sentencex.swapper(" NORMALISE", "");
	}

	var raw = sentencex.index(" RAW", 1);
	if (raw) {
		sentencex.swapper(" RAW", "");
	}
	var mvgroupno = "";

	var colheaderrow = not sentencex.index(" NOCOLHEADER", 1);
	if (not colheaderrow) {
		sentencex.swapper(" NOCOLHEADER", "");
	}

	if (filename.substr(1,4) == "DICT") {
		tt = "VOC";
	}else{
		tt = filename;
	}
	if (not(DICT.open("dict_"^tt))) {
		return fsmsg();
	}

//	var converter = "";
//	if (not((tt!!!).read(DEFINITIONS, "CONVERTER*" ^ filename))) {
//		tt!!! = "";
//	}
//	if (tt!!!.a(1)) {
//		converter = "CONVERTER." ^ tt!!!.a(1);
//	}

	var xx;
	if (xx.read(DICT, "AUTHORISED")) {
		dicthasauthorised = 1;
	}else{
		dicthasauthorised = 0;
	}

	var notexportable = "";
	var exportable = sentencex.field(" ", 3, 9999);
	if (exportable) {
		exportable.converter(" ", FM);
		if (exportable.a(1) == "EXCEPT") {
			notexportable = exportable.field(FM, 2, 9999);
			exportable = "";
		}
	}

	//expand any group fields in notexportable
	if (notexportable) {
		for (var ii = 1; ii <= notexportable.count(FM) + 1; ++ii) {
			var dictrec;
			if (dictrec.read(DICT, notexportable.a(ii))) {
				if (dictrec.a(1) == "G") {
					temp = dictrec.a(3);
					temp.converter(VM ^ " ", FM ^ FM);
					notexportable.r(ii, temp);
				}
			}
		};//ii;
	}

	var listkey = var(1000000).rnd();

	if (not exportable) {

		if (exportable.read(DICT, "exportable")) {
			if (exportable.a(1) == "G") {
				exportable = exportable.a(3);
				exportable.converter(VM ^ " ", FM ^ FM);
			}
			keyx = exportable.substr(1,exportable.index(FM ^ FM, 1) - 1);
			nkeys = keyx.count(FM) + 1;
			if (nkeys > 2) {
				//call msg('Key field(s) should be followed by a blank line or space in EXPORTABLE')
				//stop
				nkeys = 0;
			}
		}else{
			exportable = "";
			keyx = "";
		}

	}

	var exportable2 = exportable;

//nextmvgroup:

	if (mvgroupno) {
		tt = keyx ^ FM ^ "LINE_NO" ^ FM;
	}else{
		tt = "";
	}

	exportable = tt ^ exportable2.field("%", 1);
	exportable2 = exportable2.field("%", 2, 9999);

	outfilename = SYSTEM.a(2);
	//zzz if mvgroupno then outfilename[8,1]=mvgroupno
	if (outfilename.lcase().substr(-4, 4) == ".htm") {
		outfilename.splicer(-3, 3, "xls");
		SYSTEM.r(2, outfilename);
	}

	var excel = outfilename.lcase().substr(-3, 3) == "xls";

//retry:
	outfilename.osdelete();
	if (outfilename.osfile()) {
		return exit2("CANNOT EXPORT BECAUSE " ^ outfilename ^ " IS ALREADY|OPEN IN ANOTHER PROGRAM, OR CANNOT BE ACCESSED");
	}

	//call note2("Exporting " ^ outfilename ^ "||Please wait ...", "UB", buffer, "");

	files.redim(255);
	filenames.redim(255);
	oconvxs.redim(255);
	fmtxs.redim(255);
	dictrecs.redim(255);
	filenames="";
	oconvxs="";
	fmtxs="";
	var nfields = 0;
	
	var selectlist = LISTACTIVE;
	if (selectlist) {
		savelistactive=LISTACTIVE;
	}

	if (exportable) {
		//call makelist("", exportable, "", "");
		//write exportable on lists,listkey
		//perform 'GET-LIST ':listkey:' (S)'
		//delete lists,listkey
		var tt="select dict_" ^ filename ^ " " ^ exportable.swap(FM, "\" \"").quote();
		DICT.select(tt);

	}else{
		if (filename.substr(1,4).lcase() == "dict") {
			dict = "";
		}else{
			dict = "dict_";
		}
		DICT.select("select " ^ dict ^ filename ^ " BY FMC WITH FMC BETWEEN 1 AND 999999 AND WITH @ID NOT STARTING \'%\' AND WITH MASTER.FLAG (S)");
		if (not LISTACTIVE) {
			return exit2(dict ^ filename ^ " has no exportable columns");
		}
	}

	dictids.redim(255);
	colgroups.redim(255);

	dictids = "";
	colgroups = "";
	var headingx = "";
	var coln = 0;

	var dictid;
	while (DICT.readnext(dictid, MV)) {

		if (notexportable.locateusing(dictid, FM, xx)) {
			continue;
		}

		if (dictid[1] == "%") {
			continue;
		}

		if (dictid == "LINE_NO") {
			coln += 1;
			dictids(coln) = dictid;
			headingx.r(coln, dictid);
			fmtxs(coln) = "R";
			dictrecs(coln) = "";
		}else{
			if (dict.read(DICT, dictid)) {
//				call dicti2a(dict);
				coln += 1;
				//if dict<2> matches '0N' then
				var fn = dict.a(2);
				if (fn > nfields) {
					nfields = fn;
				}

				fmtxs(coln) = dict.a(9)[1];

				if (raw) {
					headingx.r(coln, dictid);
				}else{

					//extract title
					var title = dict.a(3).trim();
					title.swapper("<WBR/>", "");
					title.swapper("<wbr/>", " ");
					title.converter(UPPERCASE ^ "|_" _VM_ "", LOWERCASE ^ "   ");

					//t=title[1,1]
					//convert @lower.case to @upper.case in t
					//title[1,1]=t
					title = capitalise(title);

					title.swapper("(Base)", "(" ^ gen.company.a(3) ^ ")");

					//swap ' code' with '' in title

					headingx.r(coln, title.trim());
				}

				//extract file
				if (dict.a(11)[1] == "<") {
					temp = dict.a(11).substr(2,9999).field(">", 1);
					filenames(coln) = temp;
					if (not(files(coln).open(temp, ""))) {
						return exit2(DQ ^ (temp ^ DQ) ^ " file cannot be found in dict " ^ (DQ ^ (dictid ^ DQ)));
					}
					var title = headingx.a(coln);
					if (title.ucase().substr(-5,5) == " CODE") {
						title.splicer(-5, 5, "");
						headingx.r(coln, title);
					}
				}

				//extract conversion
				if (dict.a(7)) {
					var oconvx = dict.a(7);

					//force long date format
					if (oconvx.index("DATE", 1) or oconvx[1] == "D") {
						//if raw then
						// oconvx='D4/J'
						//end else
						if (oconvx == "[SCH.DATES]") {
							oconvx = "";
						}else{
							oconvx = "D4/E";
						}
						//end
					}

					oconvxs(coln) = oconvx;
				}

				colgroups(coln) = dict.a(4)[1] == "M";
				dictids(coln) = dictid;
				dictrecs(coln) = dict;

			}
			//end
		}
	}//nextdict
	var ncols = coln;

	//if @username='******' then oswrite matunparse(dictids) on 'csv'

	if (selectlist) {
		LISTACTIVE=savelistactive;
	}

	call oswrite("", outfilename);
	if (not outfile.osopen(outfilename)) {
		return exit2(outfilename.quote()^" file cannot be created");
	}
	var ptr = 0;

	//suppress headerrow if not required
	if (not colheaderrow) {
		headingx = "";
	}

	if (selectx) {
	//selectx:=' AND WITH PERSON_CODE "HARRIS"'
		//perform 'SELECT ':filename:' ':selectx
		tt = "SELECT " ^ filename ^ " " ^ selectx;
		//call xselect(tt);
		file.select(tt);
/*		if (not LISTACTIVE) {
			outfile.osclose();
			outfilename.osdelete();
			return exit2("No records found");
		}
*/
	}else{
		if (not LISTACTIVE) {
			file.select();
		}
	}

	var recn = 0;

	rec.redim(ncols);
	mvrec.redim(ncols);

/////
//nextrecord:
/////

	//get the next key and mv
	var mvx;
	while (file.readnext(ID, mvx)) {

		//user interrupt
		if (esctoexit()) {
			outfile.osclose();
			//osdelete outfilename
			return exit2("Interrupted by User");
		}

		//skip "" key
		if (ID == "") {
			continue;
		}

		recn += 1;

		//cout << AW.a(30)<< var().cursor(0)<< var().cursor(-4);
		//cout << var().cursor(39, _CRTHIGH / 2)<< recn<< ". ";

		//get the record
		if (not(RECORD.read(file, ID))) {
			continue;
		}

		//skip record if not authorised
		if (dicthasauthorised and not calculate("AUTHORISED")) {
			continue;
		}

		//skip zero hours in timesheets
		//TODO get this hack into a special dictionary item like LIMIT
		if (filename == "TIMESHEETS" and mvx and not RECORD.a(2, mvx)) {
			continue;
		}
		
		//get the data and work out maximum vn
		mvrec = "";
		var maxvn=0;
		for (var coln = 1; coln <= ncols; ++coln) {

			dictid = dictids(coln);
			if (dictid eq "LINE_NO")
				continue;

			MV = mvx;
			var cell = calculate(dictid);
			if (not cell.length())
				continue;
				
			if (oconvxs(coln)) {
				cell = cell.oconv(oconvxs(coln));
			}

			mvrec(coln) = cell;

			var temp = cell.dcount(VM);
			if (temp > maxvn)
				maxvn = temp;
				
		}

		//skip if no data
		if (not maxvn)
			continue;

		//normalise the data and output to csv file
		
		//output the lines
		for (var vn=1; vn <= maxvn; ++vn) {

			rec="";
					
			//conversions
			for (var coln = 1; coln <= ncols; ++coln) {

				var cell;
				
				if (dictids(coln) == "LINE_NO") {
					cell = vn;

				//select right multivalue if multivalued field/column
				//non-multivalued fields/columns are repeated on every line
				}else if (colgroups(coln)) {
						cell=mvrec(coln).a(1,vn);
						
				//not multivalued so repeat on every line
				} else {
						cell = mvrec(coln);
				}
								
				//skip empty cells
				if (not cell.length())
					continue;

				//conversions
				if (mvx or vn == 1) {

					//convert codes to names
					if (filenames(coln) and not raw) {
						var rec2;
						if (rec2.read(files(coln), cell)) {
							if (filenames(coln) == "BRANDS") {
								cell = rec2.a(2, 1);
							}else{
								cell = rec2.a(1);
							}
						}
					}

				}

				//remove any initial + sign - on numbers only
				if (cell[1] == "+") {
					if ((cell.substr(2,9999)).isnum()) {
						cell.splicer(1, 1, "");
					}
				}
				
				//a single double quote gets changed to ''
				if (cell == DQ) {
					cell = "\'\'";
				}
				
				//swap double quotes for '' unless already double quoted
				if (cell[1] ne DQ or cell[-1] ne DQ) {
					cell.swapper(DQ, "\'\'");
				}
				
				//WARNING prevent cell length more than 255
				if (cell.length() > 255) {
					cell = cell.substr(1,250) ^ " ...";
				}
				
				//double quote non-numerics
				if (fmtxs(coln) ne "R") {

					//make sure "1-12" is not interpreted as a formula (by prefixing a space?)
					if (1 or excel) {
						if (var(".-+0123456789").index(cell[1])) {
							if (not cell.isnum()) {
								cell.splicer(1, 0, " ");
							}
						}
					}

					//convert any existing double quotes to '' for T columns which are not already double quoted
					if (cell.index(DQ, 1)) {
						if (fmtxs(coln) == "T") {
							if (cell[1] ne DQ or cell[-1] ne DQ) {
								cell.swapper(DQ, "\'\'");
								cell = DQ ^ (cell ^ DQ);
							}
						}
					//otherwise just double quote stuff
					}else{
						cell = DQ ^ (cell ^ DQ);
					}

				}

				rec(coln) = cell;

			};//coln;

			var line = rec.unparse();
			
			//remove trailing or all tab chars
			line.trimmerb(FM);

			//suppress output of empty amv rows
			if (mvgroupno and nkeys) {
				if (line.field(FM, nkeys + 2, 9999) == "") {
					line = "";
				}
			}

			//output one line
			if (not line.length())
				continue;

			//remove leading equal signs in order not to confuse Excel
			line.swapper(FM ^ "=", FM);

			//output header row if first line and not suppressed

			if (headingx) {

//				if (converter) {
//					//headingx will come back converted and maybe as multiple lines
//					//converterparams initially contains first line so heading can put some columns into heading if required
//					//converterparams comes back with info to speed convertion of lines
//					converterparams = line;
//					call onverter("HEAD", headingx, converterparams, filename);
//				}else{
					headingx.converter(FM, var().chr(9));
					headingx ^= "\r\n";
//				}

				osbwrite(headingx, outfile, ptr);

				headingx = "";
			}

			//output line

//			if (converter) {
//				call @converter("LINE", line, converterparams, filename);
//			}else{
				line.swapper(FM, var().chr(9));
				line ^= "\r\n";
//			}

			osbwrite(line, outfile, ptr);

		}//next vn

	}//goto nextrecord
	
/////
//exit:
/////
	outfile.osclose();
//	call uconvfile(outfile, "CODEPAGE", "UTF16", result, errors);
	//general result code
	SYSTEM.r(34, 1);
	
//exit3:
//	if (raw and exportable2) {
//		mvgroupno += 1;
//		if (mvgroupno == 1) {
//			mvgroupno = 2;
//		}
//		goto nextmvgroup;
//	}
	return 1;
}