//**************************************************************************
//*                     This file is part of the                           *
//*                MMC - Mpxplay Multimedia Commander                      *
//*                   The source code of MMC is                            *
//*        (C) copyright 1998-2014 by PDSoft (Attila Padar)                *
//*                http://mpxplay.sourceforge.net                          *
//*                  email: mpxplay@freemail.hu                            *
//**************************************************************************
//*  This program is distributed in the hope that it will be useful,       *
//*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *
//*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                  *
//*  Please contact with the author (with me) if you want to use           *
//*  or modify this source.                                                *
//**************************************************************************
//function: display playlist editor / dir browser

//#define MPXPLAY_USE_DEBUGF 1
#define DISPQT_DEBUG_OUTPUT stdout
#define DISPQT_DEBUGOUT_FUNC NULL
#define DISPQT_DEBUG_KEYE_OUTPUT NULL //stdout

#include <QtWidgets>
#include <QTabWidget>
#include "moc_mainwindow.h"
#include "disp_qt.h"
#include "moc_editor.h"
#include "moc_driveline.h"
#include "mpxplay.h"
#include "display/display.h"
#include "playlist/playlist.h"

extern "C" {
 extern struct mainvars mvps;
 extern unsigned int refdisp, desktopmode, preloadinfo;
 extern keyconfig kb[];
}

PlaylistEditorWidget::PlaylistEditorWidget(MainWindow *main_window, QWidget *parent) : QWidget(parent)
{
	struct mmc_dispqt_config_s *gcfg = main_window->gui_config;
	this->main_window = main_window;
	if((this->main_window->mainwin_is_translucent_enabled()) && (gcfg->editor_flags & DISPQT_CONFIG_EDITORFLAG_TRANSLUCENT_INWINDOW))
		funcbit_enable(gcfg->editor_flags, DISPQT_CONFIG_EDITORFLAG_TRANSPARENT_BACK);
	else
		funcbit_disable(gcfg->editor_flags, DISPQT_CONFIG_EDITORFLAG_TRANSPARENT_BACK);
	this->setFocusPolicy(Qt::NoFocus);
	this->action_tabs_refresh = new QAction(this);
	this->act_tabsrefresh_userdataid_tabrefreshcfg = this->action_tabs_refresh->registerUserData();
	connect(this->action_tabs_refresh, SIGNAL(triggered()), this, SLOT(tab_headers_refresh_apply()));
	this->editor_build_all(true);
}

void PlaylistEditorWidget::editor_build_all(bool initial)
{
	struct mmc_dispqt_config_s *gcfg = main_window->gui_config;
	this->last_desktopmode = desktopmode;
	this->last_editorflags = gcfg->editor_flags;

	this->mutex_editorwidget.tryLock(DISPQT_MUTEX_TIMEOUT);
	if(this->last_editorflags & DISPQT_CONFIG_EDITORFLAG_SHOWPANELS_ALL) {
		this->setUpdatesEnabled(false);
		if(this->last_desktopmode & DTM_EDIT_VERTICAL)
			this->PlaylistEditorLayout = new QHBoxLayout; // to make vertical panels
		else
			this->PlaylistEditorLayout = new QVBoxLayout;
		this->PlaylistEditorLayout->setMargin(1);
		this->PlaylistEditorLayout->setSpacing(1);
	} else
		this->PlaylistEditorLayout = NULL;

	for(int sidenum = 0; sidenum < PLAYLIST_MAX_SIDES; sidenum++) {
		if(this->last_editorflags & (1 << sidenum)) { // !!! DISPQT_CONFIG_EDITORFLAG_SHOWPANEL_
			struct dispqt_playlisteditor_model_config_s pmc;
			this->editor_side_layout[sidenum] = new QVBoxLayout; // to make horizontal fields on one panel
			if(this->last_editorflags & DISPQT_CONFIG_EDITORFLAG_SHOW_DRIVELINE) {
				this->editor_drive_line[sidenum] = new EditorDriveline(main_window, this, sidenum);
				this->editor_side_layout[sidenum]->addWidget(this->editor_drive_line[sidenum]);
			} else
				this->editor_drive_line[sidenum] = NULL;
			this->editor_tab_widget[sidenum] = new PlaylistEditorTabs(main_window, this, sidenum);
			this->editor_side_layout[sidenum]->addWidget(this->editor_tab_widget[sidenum]);
			this->PlaylistEditorLayout->addLayout(this->editor_side_layout[sidenum]);
			pds_memset(&pmc, 0, sizeof(pmc));
			this->editor_tab_widget[sidenum]->tab_create(&pmc);
		} else {
			this->editor_drive_line[sidenum] = NULL;
			this->editor_tab_widget[sidenum] = NULL;
		}
	}

	if(this->last_editorflags & DISPQT_CONFIG_EDITORFLAG_SHOWPANELS_ALL) {
		this->setLayout(this->PlaylistEditorLayout);
		this->setUpdatesEnabled(true);
		if(!initial && !(this->last_editorflags & (1 << mvps.editorside_selected))){
			editortabs_editlisteventcb_init(DISPQT_EDITOR_CBCMD_SET_SIDE, 0, -1, -1, -1);
		}
	}
	this->mutex_editorwidget.unlock();
	mpxplay_debugf(DISPQT_DEBUGOUT_FUNC, "build_all end");
}

void PlaylistEditorWidget::editor_delete_all(void)
{
	mpxplay_debugf(DISPQT_DEBUGOUT_FUNC, "delete_all begin");
	if(!this->PlaylistEditorLayout)
		return;
	this->mutex_editorwidget.tryLock(DISPQT_MUTEX_TIMEOUT);
	for(int sidenum = 0; sidenum < PLAYLIST_MAX_SIDES; sidenum++) {
		if(this->editor_drive_line[sidenum])
			this->editor_drive_line[sidenum]->hide();
		if(this->editor_tab_widget[sidenum])
			this->editor_tab_widget[sidenum]->hide();
	}
	delete this->PlaylistEditorLayout;
	this->PlaylistEditorLayout = NULL;
	for(int sidenum = 0; sidenum < PLAYLIST_MAX_SIDES; sidenum++) {
		this->editor_drive_line[sidenum] = NULL;
		this->editor_tab_widget[sidenum] = NULL;
	}
	this->mutex_editorwidget.unlock();
}

void PlaylistEditorWidget::editor_config_transparent_back(bool on_video)
{
	struct mmc_dispqt_config_s *gcfg = this->main_window->gui_config;
	if( this->main_window->mainwin_is_translucent_enabled() &&
	   (   (!on_video && (gcfg->editor_flags & DISPQT_CONFIG_EDITORFLAG_TRANSLUCENT_INWINDOW) && this->isActiveWindow())
	   ||  ( on_video && (gcfg->editor_flags & DISPQT_CONFIG_EDITORFLAG_TRANSLUCENT_ONVIDEO))
	   ||  (!on_video && (gcfg->editor_flags & DISPQT_CONFIG_EDITORFLAG_TRANSLUCENT_INACTIVE) && !this->isActiveWindow()) )
	)
		funcbit_enable(gcfg->editor_flags, DISPQT_CONFIG_EDITORFLAG_TRANSPARENT_BACK);
	else
		funcbit_disable(gcfg->editor_flags, DISPQT_CONFIG_EDITORFLAG_TRANSPARENT_BACK);
}

void PlaylistEditorWidget::editor_config_apply(bool on_video)
{
	struct mmc_dispqt_config_s *gcfg = this->main_window->gui_config;

	this->editor_config_transparent_back(on_video);

	if(  ((desktopmode & DISPQT_CONFIG_DESKTOPMODE_FULLREDRAW) != (this->last_desktopmode & DISPQT_CONFIG_DESKTOPMODE_FULLREDRAW))
	  || ((gcfg->editor_flags & DISPQT_CONFIG_EDITORFLAGS_FULLREDRAW) != (this->last_editorflags & DISPQT_CONFIG_EDITORFLAGS_FULLREDRAW))
	){
		funcbit_smp_disable(refdisp, RDT_EDITOR);
		this->editor_delete_all();
		this->editor_build_all(false);
		funcbit_enable(refdisp, (RDT_EDITOR | RDT_RESET_EDIT));
	} else {
		funcbit_smp_disable(refdisp, RDT_EDITOR);
		this->mutex_editorwidget.tryLock(DISPQT_MUTEX_TIMEOUT);
		for(int sidenum = 0; sidenum < PLAYLIST_MAX_SIDES; sidenum++) {
			if(this->editor_tab_widget[sidenum]) {
				this->editor_tab_widget[sidenum]->editortabs_config_apply();
				this->editor_tab_widget[sidenum]->editortabs_config_style_apply();
			}
		}
		this->last_editorflags = gcfg->editor_flags;
		this->mutex_editorwidget.unlock();
		funcbit_enable(refdisp, RDT_EDITOR);
	}
}

void PlaylistEditorWidget::editor_config_style_apply(bool lucent_enable)
{
	funcbit_smp_disable(refdisp, RDT_EDITOR);
	this->mutex_editorwidget.tryLock(DISPQT_MUTEX_TIMEOUT);
	this->editor_config_transparent_back(this->main_window->mainwin_is_on_video());
	for(int sidenum = 0; sidenum < PLAYLIST_MAX_SIDES; sidenum++) {
		if(this->editor_drive_line[sidenum])
			this->editor_drive_line[sidenum]->driveline_config_style_apply(lucent_enable);
		if(this->editor_tab_widget[sidenum])
			this->editor_tab_widget[sidenum]->editortabs_config_style_apply();
	}
	this->mutex_editorwidget.unlock();
	funcbit_enable(refdisp, RDT_EDITOR);
}

void PlaylistEditorWidget::editor_config_style_onvideo_switch(bool on_video)
{
	struct mmc_dispqt_config_s *gcfg = this->main_window->gui_config;

	this->editor_config_transparent_back(on_video);

	if((gcfg->editor_flags & DISPQT_CONFIG_EDITORFLAG_TRANSPARENT_BACK) != (this->last_editorflags & DISPQT_CONFIG_EDITORFLAG_TRANSPARENT_BACK)) {
		funcbit_smp_disable(refdisp, RDT_EDITOR);
		this->mutex_editorwidget.tryLock(DISPQT_MUTEX_TIMEOUT);
		for(int sidenum = 0; sidenum < PLAYLIST_MAX_SIDES; sidenum++)
			if(this->editor_tab_widget[sidenum])
				this->editor_tab_widget[sidenum]->editortabs_config_style_apply();
		funcbit_copy(this->last_editorflags, gcfg->editor_flags, DISPQT_CONFIG_EDITORFLAG_TRANSPARENT_BACK);
		this->mutex_editorwidget.unlock();
		funcbit_enable(refdisp, RDT_EDITOR);
	}
}

void PlaylistEditorWidget::set_default_focus(struct playlist_side_info *psi)
{
	if(!psi)
		return;
	unsigned int sidenum = psi->sidenum;
	if(sidenum >= PLAYLIST_MAX_SIDES)
		return;
	PlaylistEditorTabs *peb = this->editor_tab_widget[sidenum];
	if(!peb)
		return;
	QWidget *curwd = peb->currentWidget();
	if(curwd)
		curwd->setFocus();
	else
		peb->setFocus();
}

void PlaylistEditorWidget::keyPressEvent(QKeyEvent *event)
{
	mpxplay_debugf(DISPQT_DEBUG_KEYE_OUTPUT, "KEY event  PlaylistEditorWidget");
	this->main_window->handle_keypressevent(event);
}

struct dispqt_playlisteditor_model_config_s *PlaylistEditorWidget::tab_get_pmc(PlaylistEditorTabs **pet_ptr, int sidenum, int tabnum)
{
	struct dispqt_playlisteditor_model_config_s *pmc = NULL;
	PlaylistEditorTabs *pet = NULL;
	if((sidenum >= 0) && (sidenum < PLAYLIST_MAX_SIDES)){
		pet = this->editor_tab_widget[sidenum];
		if(pet){
			PlaylistEditorTable *table = pet->tabs_get_table(tabnum);
			if(table)
				pmc = table->editortable_get_pmc();
		}
	}
	if(pet_ptr)
		*pet_ptr = pet;
	return pmc;
}

//----------------------------------------------------------------------------------
void mpxplay_dispqt_editor_tab_header_create_info(struct playlist_side_info *psi, struct dispqt_playlisteditor_model_config_s *pmc, bool full)
{
	int namepos = 0;
	struct mainvars *mvp;
	char *fullnamep, strtmp[MAX_PATHNAMELEN], path[MAX_PATHNAMELEN];

	if(!psi || !pmc)
		return;

	pmc->sidenum = psi->sidenum;
	pmc->tabnum = psi->tabnum;
	pmc->editloadtype = psi->editloadtype;
	pmc->editsidetype = psi->editsidetype;
	if(psi->sublistlevel)
		funcbit_disable(pmc->editsidetype, PLT_DIRECTORY);
	pmc->id3ordernum_primary = psi->id3ordernum_primary;
	pmc->filenum_displayed = (psi->editloadtype&PLL_FILTERED)? psi->filtered_files : (psi->lastentry - psi->firstentry + 1);
	pmc->filenum_entry_diff = playlist_editlist_entry_diff(psi, psi->firstentry, psi->editor_from);
	pmc->editorhighline_row = playlist_editlist_entry_diff(psi, psi->editor_from, psi->editorhighline);
	mvp = psi->mvp;
	if(psi == mvp->psie)
		funcbit_enable(pmc->flags, DISPQT_EDITOR_MODELCONFIGFLAG_EDITSIDE);
	if(psi->tabnum == mvp->editorsides_selected_tab[psi->sidenum])
		funcbit_enable(pmc->flags, DISPQT_EDITOR_MODELCONFIGFLAG_EDITTAB);
	if(psi == mvp->psip)
		funcbit_enable(pmc->flags, DISPQT_EDITOR_MODELCONFIGFLAG_PLAYTAB);

	strtmp[0]=0;
	fullnamep = NULL;
	if(pmc->editsidetype & PLT_DIRECTORY){
		char *updir = pds_getfilename_from_fullname(psi->currdir);
		if(updir && *updir)
			pds_strcpy(strtmp, updir);
		else
			pds_strcpy(strtmp, psi->currdir);
		fullnamep = &psi->currdir[0];
	}else if(psi->editloadtype & PLL_JUKEBOX) {
		sprintf(strtmp, "JukeBox%d", (psi->tabnum + 1));
	}else if(psi->savelist_filename[0] || ((psi->savelist_filename[0] || !(psi->editloadtype&PLL_RESTORED)) && psi->sublistnames[psi->sublistlevel][0])){
		char *p = (psi->savelist_filename[0])? &psi->savelist_filename[0]:(&psi->sublistnames[psi->sublistlevel][0]);
		fullnamep = p;
		if(pds_filename_wildcard_chk(p)){
			pds_getpath_nowildcard_from_filename(path, p);
			p = &path[0];
		}
		pds_strcpy(strtmp, pds_getfilename_from_fullname(p));
	}
	if(!strtmp[0])
		sprintf(strtmp, "LIST%d", (psi->tabnum + 1));
	if(!fullnamep)
		fullnamep = &strtmp[0];

	if(psi->editloadtype & PLL_LOCKTAB)
		pmc->head_filename[namepos++] = '#';
	if((psi->editloadtype & PLL_CHG_MANUAL) && !(pmc->editsidetype&PLT_DIRECTORY))
		pmc->head_filename[namepos++] = '*';

	pds_strncpy(&pmc->head_filename[namepos], strtmp, sizeof(pmc->head_filename) - namepos);
	pds_strncpy(pmc->head_fullname, fullnamep, sizeof(pmc->head_fullname));
	pmc->head_filename[sizeof(pmc->head_filename) - 1] = 0;
	pmc->head_fullname[sizeof(pmc->head_fullname) - 1] = 0;

	if(full && funcbit_test(pmc->flags, DISPQT_EDITOR_MODELCONFIGFLAG_EDITTAB) && (psi->editsidetype & PLT_DIRECTORY)){
		int i;
		struct playlist_entry_info *pei;
		struct playlist_side_info psi_drvlist;
		char astr_drv[sizeof(PDS_DIRECTORY_ROOTDIR_STR)];

		memset((void *)&psi_drvlist, 0, sizeof(psi_drvlist));
		psi_drvlist.editsidetype=PLT_DIRECTORY;
		psi_drvlist.mvp = &mvps;

		playlist_loaddir_browser_get_drives(&psi_drvlist, psi->currdrive, psi->currdrive);  // !!! loads only the current drive infos
		if(!psi_drvlist.firstentry)
			return;  // !!!
		pmc->nb_drives = (psi_drvlist.lastentry - psi_drvlist.firstentry + 1);
		pmc->drivenames = (char **)pds_calloc(pmc->nb_drives, sizeof(char *));
		if(pmc->drivenames){
			for(pei = psi_drvlist.firstentry, i = 0; pei <= psi_drvlist.lastentry; pei++, i++) {
				int len1 = pds_strlen(pei->filename), len2 = len1;
				if(len1 <= 2)
					len2 += pds_strlen(pei->id3info[I3I_DFT_STORE]) + 1; // +1 space
				pmc->drivenames[i] = (char *)pds_malloc(len2 + 1);
				if(pmc->drivenames[i]){
					pds_strcpy(pmc->drivenames[i], pei->filename);
					if(len1 <= 2){
						pds_strcpy(&pmc->drivenames[i][len1], (char *)" ");
						pds_strcpy(&pmc->drivenames[i][len1 + 1], pei->id3info[I3I_DFT_STORE]);
					}
				}
			}
		}
		playlist_editlist_tab_clear(&psi_drvlist);

		pds_strncpy(astr_drv, psi->currdir, sizeof(astr_drv));
		astr_drv[sizeof(PDS_DIRECTORY_ROOTDIR_STR) - 1] = 0;
		if(astr_drv[sizeof(PDS_DIRECTORY_ROOTDIR_STR) - 2] != PDS_DIRECTORY_SEPARATOR_CHAR)
			astr_drv[sizeof(PDS_DIRECTORY_ROOTDIR_STR) - 2] = PDS_DIRECTORY_SEPARATOR_CHAR;
		pmc->drive_free_space = 0; pmc->drive_total_space = 0;
		pds_drive_getspace(astr_drv, &pmc->drive_free_space, &pmc->drive_total_space);
	}
}

int mpxplay_dispqt_editor_tab_headers_refresh_create(struct mainvars *mvp, PlaylistEditorWidget *pew)
{
	if(!pew)
		return DISPQT_ERROR_EDITORTABLE_MISSING;
	if(pew->action_tabs_refresh->userData(pew->act_tabsrefresh_userdataid_tabrefreshcfg))
		return DISPQT_ERROR_EDITORTABLE_BUSY;
	struct dispqt_playlisteditor_tabrefresh_config_s *trc = (struct dispqt_playlisteditor_tabrefresh_config_s *)pds_malloc(sizeof(struct dispqt_playlisteditor_tabrefresh_config_s));
	pds_memset(trc, 0 , sizeof(*trc));
	for(int sidenum = 0; sidenum < PLAYLIST_MAX_SIDES; sidenum++)
	{
		trc->nb_tabs_on_side[sidenum] = mvp->editorsides_num_tabs[sidenum];
		for(int tabnum = 0; tabnum < PLAYLIST_MAX_TABS_PER_SIDE; tabnum++)
		{
			struct playlist_side_info *psi = playlist_editlist_tabpsi_get(mvp, sidenum, tabnum);
			mpxplay_dispqt_editor_tab_header_create_info(psi, &trc->tab_infos[sidenum][tabnum], true);
		}
	}

	pew->action_tabs_refresh->setUserData(pew->act_tabsrefresh_userdataid_tabrefreshcfg, (QObjectUserData *)trc);
	pew->action_tabs_refresh->activate(QAction::Trigger);
	return DISPQT_ERROR_OK;
}

void PlaylistEditorWidget::tab_headers_refresh_apply(void)
{
	struct dispqt_playlisteditor_tabrefresh_config_s *trc = (struct dispqt_playlisteditor_tabrefresh_config_s *)this->action_tabs_refresh->userData(this->act_tabsrefresh_userdataid_tabrefreshcfg);
	if(!trc)
		return;
	this->mutex_editorwidget.tryLock(DISPQT_MUTEX_TIMEOUT);
	this->setUpdatesEnabled(false);

	for(int sidenum = 0; sidenum < PLAYLIST_MAX_SIDES; sidenum++)
	{
		PlaylistEditorTabs *tabs = this->editor_tab_widget[sidenum];
		struct dispqt_playlisteditor_model_config_s *pmc;
		int tabnum;
		if(!tabs) // side is not displayed
			continue;
		pmc = &trc->tab_infos[sidenum][0];
		for(tabnum = 0; tabnum < trc->nb_tabs_on_side[sidenum]; tabnum++, pmc++)
		{
			tabs->tab_create(pmc);
			if(pmc->flags & DISPQT_EDITOR_MODELCONFIGFLAG_EDITTAB){
				tabs->tab_select(tabnum);
				this->tab_changed_handler(pmc);
			}
		}
		for(; tabnum < PLAYLIST_MAX_TABS_PER_SIDE; tabnum++, pmc++)
		{
			pmc->tabnum = tabnum;
			tabs->tab_delete(pmc);
		}
	}

	this->action_tabs_refresh->setUserData(this->act_tabsrefresh_userdataid_tabrefreshcfg, NULL);
	pds_free(trc);
	this->setUpdatesEnabled(true);
	this->mutex_editorwidget.unlock();
}

void PlaylistEditorWidget::tab_changed_handler(struct dispqt_playlisteditor_model_config_s *pmc)
{
	EditorDriveline *edl = this->editor_drive_line[pmc->sidenum];
	if(edl && edl->drive_combobox)
		edl->drive_combobox->drive_list_select_by_tabpath(pmc, QString::fromUtf8(pmc->head_fullname));
}

int PlaylistEditorWidget::table_refresh_create(struct playlist_side_info *psi)
{
	int retcode = DISPQT_ERROR_EDITORTABLE_ARGS;
	if(!psi)
		return retcode;
	unsigned int sidenum = psi->sidenum;
	if(sidenum >= PLAYLIST_MAX_SIDES)
		return retcode;
	this->mutex_editorwidget.tryLock(DISPQT_MUTEX_TIMEOUT);
	PlaylistEditorTabs *tabs = this->editor_tab_widget[sidenum];
	if(tabs)
		retcode = tabs->table_refresh_create(psi);
	this->mutex_editorwidget.unlock();
	return retcode;
}

void PlaylistEditorWidget::line_select_request(struct playlist_side_info *psi, struct playlist_entry_info *pei)
{
	if(!psi || !pei)
		return;
	unsigned int sidenum = psi->sidenum;
	if(sidenum >= PLAYLIST_MAX_SIDES)
		return;
	this->mutex_editorwidget.tryLock(DISPQT_MUTEX_TIMEOUT);
	PlaylistEditorTabs *tabs = this->editor_tab_widget[sidenum];
	if(tabs)
		tabs->line_select_request(psi, pei);
	this->mutex_editorwidget.unlock();
}

int PlaylistEditorWidget::editortable_line_count(struct playlist_side_info *psi)
{
	int line_count = 0;
	PlaylistEditorTable *table = NULL;
	if(!psi)
		return line_count;
	unsigned int sidenum = psi->sidenum, tabnum = psi->tabnum;
	if(sidenum >= PLAYLIST_MAX_SIDES)
		return line_count;
	this->mutex_editorwidget.tryLock(DISPQT_MUTEX_TIMEOUT);
	PlaylistEditorTabs *tabs = this->editor_tab_widget[sidenum];
	if(tabs){
		table = tabs->tabs_get_table(tabnum);
		if(table)
			line_count = table->line_count();
	}
	this->mutex_editorwidget.unlock();
	return line_count;
}

void mpxplay_dispqt_editor_event_callback(void *passdata) // called from Mpxplay's main thread timer
{
	struct dispqt_editor_callbackdata_s *deci = (struct dispqt_editor_callbackdata_s *)passdata;
	struct playlist_side_info *psi;
	struct mainvars *mvp = &mvps;

	if(!deci)
		return;

	switch(deci->cbcmd)
	{
		case DISPQT_EDITOR_CBCMD_SET_SIDE:
			playlist_editlist_tab_select(mvp, deci->sidenum, deci->tabnum);
			goto err_out_event;
		case DISPQT_EDITOR_CBCMD_TAB_ADD:
			playlist_editlist_tab_add(mvp, deci->mode, deci->sidenum, deci->tabnum, deci->dest_sidenum);
			goto err_out_event;
		case DISPQT_EDITOR_CBCMD_TAB_DEL:
			playlist_editlist_tab_del(mvp, deci->sidenum, deci->tabnum);
			goto err_out_event;
	}

	psi = playlist_editlist_tabpsi_get(mvp, deci->sidenum, deci->tabnum);
	if(!psi)
		goto err_out_event;

	deci->sidenum = psi->sidenum; // for -1 arguments
	deci->tabnum = psi->tabnum;   //

	funcbit_enable(deci->flags,DISPQT_EDITOR_FLAG_CONTENTREFRESH);

	switch(deci->cbcmd)
	{
		case DISPQT_EDITOR_CBCMD_TAB_LOCK:
			funcbit_inverse(psi->editloadtype, PLL_LOCKTAB);
			break;
		case DISPQT_EDITOR_CBCMD_SAVELISTAS:
			playlist_savelist_manual_save(psi);
			break;
		case DISPQT_EDITOR_CBCMD_RELOAD:
			playlist_reload_side(mvp, psi);
			break;
		case DISPQT_EDITOR_CBCMD_DIRSWITCH:
			if(psi->editsidetype & PLT_DIRECTORY)
				playlist_loaddir_switch_to_playlist(psi);
			else {
				char *dir = (psi->currdir[0])? (&psi->currdir[0]) : NULL;
				if(!dir) {
					struct playlist_side_info *pss = playlist_editlist_tabpsi_get(mvp, deci->sidenum, 0);
					unsigned int i, num_tabs = mvps.editorsides_num_tabs[deci->sidenum];
					for(i = 0; i < num_tabs; i++, pss++) {
						if(pss->currdir[0]){
							dir = &pss->currdir[0];
							break;
						}
					}
				}
				if(!dir)
					dir = mpxplay_playlist_startdir();
				//loaddir_selectdrive_playlist_to_sublist(psi->psio);
				psi->editsidetype = PLT_DIRECTORY;
				psi->editloadtype = 0;
				playlist_loaddir_initbrowser_tab(psi, dir);
				playlist_loaddir_buildbrowser(psi);
				playlist_id3list_load(psi->mvp, psi);
				playlist_chkfile_start_norm(psi, NULL);
			}
			break;
		case DISPQT_EDITOR_CBCMD_RANDOMIZE:
			playlist_randlist_randomize_side(psi);
			if(preloadinfo & PLI_DISPLOAD)
				display_editorside_reset(psi);
			break;
		case DISPQT_EDITOR_CBCMD_CLEARLIST:
			mpxplay_playlist_sideclear_entries(psi);
			playlist_disable_side_full(psi);
			mpxplay_playlist_sideclear_sidetype(psi);
			psi->currdir[0]=0;
			break;
		case DISPQT_EDITOR_CBCMD_SORT:
			playlist_sortlist_do_sort_col_n(psi, deci->mode, -1);
			mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "DISPQT_EDITOR_CBCMD_SORT s:%d t:%d m:%d psi:%8.8X", deci->sidenum, deci->tabnum, deci->mode, (unsigned long)psi);
			break;
		default:
			funcbit_disable(deci->flags,DISPQT_EDITOR_FLAG_CONTENTREFRESH);
			break;
	}

	if(deci->flags & DISPQT_EDITOR_FLAG_CONTENTREFRESH){
		if(deci->tabnum != mvp->editorsides_selected_tab[deci->sidenum])
			funcbit_enable(refdisp, RDT_TABINFOS);
//		else									// FIXME: unneccessary editor refresh (pmc fill rowflags)
			funcbit_enable(refdisp, RDT_EDITOR);
		if(psi && (psi == mvp->psip))
			funcbit_enable(refdisp, RDT_BROWSER);
	}

err_out_event:
	pds_free(deci);
}

void PlaylistEditorWidget::editortabs_editlisteventcb_init(unsigned int cmd, unsigned int mode, int sidenum, int tabnum, int dest_sidenum)
{
	//this->mutex_editorwidget.tryLock(DISPQT_MUTEX_TIMEOUT);
	struct dispqt_editor_callbackdata_s *deci = (struct dispqt_editor_callbackdata_s *)pds_malloc(sizeof(struct dispqt_editor_callbackdata_s));
	deci->cbcmd = cmd;
	deci->flags = 0;
	deci->mode = mode;
	deci->sidenum = sidenum;
	deci->tabnum = tabnum;
	deci->dest_sidenum = dest_sidenum;
	deci->linenum = -1; // don't change linenum
	mpxplay_dispqt_mainthread_callback_init((void *)mpxplay_dispqt_editor_event_callback, (void *)deci, DISPQT_CB_FLAG_MULTYCALL);
	//this->mutex_editorwidget.unlock();
}

//------------------------------------------------------------------------------------------------
// PlaylistEditorTabBar class

PlaylistEditorTabBar::PlaylistEditorTabBar(MainWindow *main_window, QWidget *parent, unsigned int sidenum) : QTabBar(parent)
{
	this->main_window = main_window;
	this->parent_widget = parent;
	this->side_num = sidenum;
	if(main_window->gui_config->editor_flags & DISPQT_CONFIG_EDITORFLAG_TRANSPARENT_BACK)
		tabbar_config_style_apply();
	this->setFocusPolicy(Qt::NoFocus);
	setUsesScrollButtons(true);
}

void PlaylistEditorTabBar::tabbar_config_style_apply(void)
{
	if(main_window->gui_config->editor_flags & DISPQT_CONFIG_EDITORFLAG_TRANSPARENT_BACK) {
		setDocumentMode(true);
        setAttribute(Qt::WA_TranslucentBackground, true);
        setAttribute(Qt::WA_NoSystemBackground, true);
	} else {
		setDocumentMode(false);
		setAttribute(Qt::WA_TranslucentBackground, false);
		setAttribute(Qt::WA_NoSystemBackground, false);
	}
}

void PlaylistEditorTabBar::mousePressEvent (QMouseEvent *event)
{
	if (event->button() == Qt::LeftButton) {
		int tabCount = count();
		for( int i=0; i< tabCount; i++ ) {
			if (tabRect(i).contains(event->pos())) {
				this->main_window->PlaylistEditor->editortabs_editlisteventcb_init(DISPQT_EDITOR_CBCMD_SET_SIDE, 0, this->side_num, i, -1);
				event->accept();
				break;
			}
		}
	} else
		QTabBar::mousePressEvent(event);
	// emit this->main_window->signal_video_mainwin_wakeup(false, false); // FIXME: ???
}

void PlaylistEditorTabBar::keyPressEvent(QKeyEvent *event)
{
    mpxplay_debugf(DISPQT_DEBUG_KEYE_OUTPUT, "KEY event  PlaylistEditorTabBar");
    this->main_window->handle_keypressevent(event);
}

void PlaylistEditorTabBar::wheelEvent(QWheelEvent* event)
{
	emit this->main_window->signal_video_mainwin_wakeup(true, false);
	event->accept();
}

//------------------------------------------------------------------------------------------------
// PlaylistEditorTabs class

PlaylistEditorTabs::PlaylistEditorTabs(MainWindow *main_window, QWidget *parent, unsigned int sidenum) : QTabWidget(parent)
{
	this->main_window = main_window;
	this->parent_widget = parent;
	this->side_num = sidenum;
	this->selected_tab_num = 0;
	this->sort_last_prikey_col = DISPQT_EDITOR_TABLE_COL_MAX;
	this->setFocusPolicy(Qt::NoFocus);
	//this->releaseKeyboard();

	for(int tabnum = 0; tabnum < PLAYLIST_MAX_TABS_PER_SIDE; tabnum++) {
		this->editor_tab_tables[tabnum] = NULL;
		this->editor_tab_indexes[tabnum] = -1;
	}

	this->action_line_select = new QAction(this);
	this->act_lineselect_userdataid_reqinfo = this->action_line_select->registerUserData();
	connect(this->action_line_select, SIGNAL(triggered()), this, SLOT(line_select_apply()));

	this->tab_head_contextmenu = new QMenu("Tab Menu");
	this->tab_head_contextmenu->setStyleSheet("QMenu { font-size:13px; border: 1px solid transparent;}");
	//this->tab_head_contextmenu->setFixedWidth(190);
	this->tab_head_menuact_tabname = this->tab_head_contextmenu->addAction("");
	this->tab_head_menuact_tabname->setFont(QFont("", -1, QFont::DemiBold, false));
	this->tab_head_contextmenu->addSeparator();
	this->tab_head_menuact_duplicate = this->tab_head_contextmenu->addAction(QIcon(":/images/page_copy.png"), "Duplicate tab     (Ctrl-T)");
	this->tab_head_menuact_copyToOtherSide = this->tab_head_contextmenu->addAction( "Copy tab to other side");
	this->tab_head_menuact_locktab = this->tab_head_contextmenu->addAction("Lock tab");
	this->tab_head_menuact_newEmptyTab = this->tab_head_contextmenu->addAction(QIcon(":/images/list-add.png"), "New empty tab");
	this->tab_head_menuact_remove = this->tab_head_contextmenu->addAction(QIcon(":/images/fileclose.png"), "Remove tab       (Ctrl-W)");
	this->tab_head_contextmenu->addSeparator();
	this->tab_head_menuact_loadfiles = this->tab_head_contextmenu->addAction(QIcon(":/images/open.png"), "Add files");
	this->tab_head_menuact_loaddir = this->tab_head_contextmenu->addAction(QIcon(":/images/open.png"), "Add directory");
	this->tab_head_menuact_loadurl = this->tab_head_contextmenu->addAction(QIcon(":/images/open.png"), "Add url");
	this->tab_head_menuact_savelistas = this->tab_head_contextmenu->addAction(QIcon(":/images/save.png"), "Save list As        (F2)");
	this->tab_head_contextmenu->addSeparator();
	this->tab_head_menuact_reload = this->tab_head_contextmenu->addAction(QIcon(":/images/arrow_refresh.png"), "Reload dir/list     (Ctrl-R)");
	this->tab_head_menuact_randomize = this->tab_head_contextmenu->addAction(QIcon(":/images/arrow_switch.png"), "Randomize list    (Ctrl-N)");
	this->tab_head_menuact_dirswitch = this->tab_head_contextmenu->addAction("Dir/List type select");
	this->tab_head_menuact_clearlist = this->tab_head_contextmenu->addAction(QIcon(":/images/new.png"), "Clear list          (Ctrl-Del)");
	this->tab_head_contextmenu->addSeparator();
	this->tab_head_menuact_sort[0] = this->tab_head_contextmenu->addAction("");
	this->tab_head_menuact_sort[1] = this->tab_head_contextmenu->addAction("");
	this->tab_head_menuact_sort[2] = this->tab_head_contextmenu->addAction("");
	this->tab_head_menuact_sort[3] = this->tab_head_contextmenu->addAction("");
	this->tab_head_contextmenu_add_vary_texts();

	connect(this->tab_head_menuact_duplicate, SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_duplicate()));
	connect(this->tab_head_menuact_copyToOtherSide, SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_copyToOtherSide()));
	connect(this->tab_head_menuact_locktab, SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_locktab()));
	connect(this->tab_head_menuact_newEmptyTab, SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_newEmptyTab()));
	connect(this->tab_head_menuact_remove, SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_remove()));
	connect(this->tab_head_menuact_loadfiles, SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_loadfiles()));
	connect(this->tab_head_menuact_loaddir, SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_loaddir()));
	connect(this->tab_head_menuact_loadurl, SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_loadurl()));
	connect(this->tab_head_menuact_savelistas, SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_savelistas()));
	connect(this->tab_head_menuact_reload, SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_reload()));
	connect(this->tab_head_menuact_dirswitch, SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_dirswitch()));
	connect(this->tab_head_menuact_randomize, SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_randomize()));
	connect(this->tab_head_menuact_clearlist, SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_clearlist()));
	connect(this->tab_head_menuact_sort[0], SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_sort_col_0()));
	connect(this->tab_head_menuact_sort[1], SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_sort_col_1()));
	connect(this->tab_head_menuact_sort[2], SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_sort_col_2()));
	connect(this->tab_head_menuact_sort[3], SIGNAL(triggered()),this,SLOT(tab_head_contextmenuaction_sort_col_3()));

	PlaylistEditorTabBar *petb = new PlaylistEditorTabBar(main_window, this, sidenum);
	this->editor_tab_bar = petb;
	this->setTabBar(petb);
	connect(petb, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(showContextMenu(const QPoint &)));
	petb->setContextMenuPolicy(Qt::CustomContextMenu);
	connect(this , SIGNAL(signal_tab_head_lockedfuncmsg()),this,SLOT(tab_head_contexmenu_lockedfunc_msg()));

	this->action_table_refresh = new QAction(this);
	this->act_tablerefresh_userdataid_model = this->action_table_refresh->registerUserData();
	this->act_tablerefresh_userdataid_pmc = this->action_table_refresh->registerUserData();
	connect(this->action_table_refresh, SIGNAL(triggered()), this, SLOT(table_refresh_apply()));
}

void PlaylistEditorTabs::editortabs_config_apply(void)
{
	this->mutex_editortabs.tryLock(DISPQT_MUTEX_TIMEOUT);
	for(int tabnum = 0; tabnum < PLAYLIST_MAX_TABS_PER_SIDE; tabnum++) {
		if(this->editor_tab_tables[tabnum])
			this->editor_tab_tables[tabnum]->table_config_apply();
	}
	this->mutex_editortabs.unlock();
}

void PlaylistEditorTabs::editortabs_config_style_apply(void)
{
	this->mutex_editortabs.tryLock(DISPQT_MUTEX_TIMEOUT);
	this->editor_tab_bar->tabbar_config_style_apply();
	for(int tabnum = 0; tabnum < PLAYLIST_MAX_TABS_PER_SIDE; tabnum++) {
		if(this->editor_tab_tables[tabnum])
			this->editor_tab_tables[tabnum]->table_config_color(false);
	}
	this->mutex_editortabs.unlock();
}

void PlaylistEditorTabs::keyPressEvent(QKeyEvent *event)
{
    mpxplay_debugf(DISPQT_DEBUG_KEYE_OUTPUT, "KEY event PlaylistEditorTabs");
    this->main_window->handle_keypressevent(event);
}

//------------------------------------------------------------------------------------------
// tab right click menu actions
void PlaylistEditorTabs::tab_head_contextmenu_add_vary_texts(void)
{
	unsigned int prikey_col = DISPQT_EDITOR_TABLE_COL_MAX;
	struct playlist_side_info *psi = playlist_editlist_tabpsi_get(&mvps, this->side_num, this->selected_tab_num); // FIXME:
	if(psi) {
		if(psi->editloadtype & PLL_LOCKTAB) {
			this->tab_head_menuact_locktab->setText("Unlock tab");
			this->tab_head_menuact_locktab->setIcon(QIcon(":/images/lock_open.png"));
			this->tab_head_menuact_remove->setEnabled(false);
			this->tab_head_menuact_loadfiles->setEnabled(false);
			this->tab_head_menuact_loaddir->setEnabled(false);
			this->tab_head_menuact_loadurl->setEnabled(false);
			this->tab_head_menuact_dirswitch->setEnabled(false);
			this->tab_head_menuact_clearlist->setEnabled(false);
		} else {
			this->tab_head_menuact_locktab->setText("Lock tab");
			this->tab_head_menuact_locktab->setIcon(QIcon(":/images/lock.png"));
			this->tab_head_menuact_remove->setEnabled(true);
			this->tab_head_menuact_loadfiles->setEnabled(true);
			this->tab_head_menuact_loaddir->setEnabled(true);
			this->tab_head_menuact_loadurl->setEnabled(true);
			this->tab_head_menuact_dirswitch->setEnabled(true);
			this->tab_head_menuact_clearlist->setEnabled(true);
		}
		prikey_col = playlist_sortlist_get_editorcolumn_from_priordernum(psi);
	}
	if(this->sort_last_prikey_col < DISPQT_EDITOR_TABLE_COL_MAX) {
		this->tab_head_menuact_sort[this->sort_last_prikey_col]->setIcon(QIcon(""));
		this->sort_last_prikey_col = DISPQT_EDITOR_TABLE_COL_MAX;
	}
	if( prikey_col < DISPQT_EDITOR_TABLE_COL_MAX) {
		this->tab_head_menuact_sort[prikey_col]->setIcon(QIcon(":/images/tick.png"));
		this->sort_last_prikey_col = prikey_col;
	}
	this->tab_head_menuact_tabname->setText(this->tabText(this->selected_tab_num));
	if((desktopmode&DTM_MASK_COMMANDER)==DTM_MASK_COMMANDER) {
		this->tab_head_menuact_sort[0]->setText("Sort by filename (Ctrl-F1)");
		this->tab_head_menuact_sort[1]->setText("Sort by ext        (Ctrl-F2)");
		this->tab_head_menuact_sort[2]->setText("Sort by filesize  (Ctrl-F3)");
		this->tab_head_menuact_sort[3]->setText("Sort by filedate (Ctrl-F4)");
	} else {
		this->tab_head_menuact_sort[0]->setText("Sort by filename (Ctrl-F1)");
		this->tab_head_menuact_sort[1]->setText("Sort by artist      (Ctrl-F2)");
		this->tab_head_menuact_sort[2]->setText("Sort by title        (Ctrl-F3)");
		this->tab_head_menuact_sort[3]->setText("Sort by duration (Ctrl-F4)");
	}
}

void PlaylistEditorTabs::tab_head_contexmenu_lockedfunc_msg(void)
{
	QMessageBox* msg = new QMessageBox(this->parent_widget);
	msg->setWindowTitle("Warning");
	msg->setText("Tab is locked!\n(unlock it)");
	msg->setIconPixmap(QPixmap(":/images/lock.png"));
	msg->show();

	PlaylistEditorTabs *pet;
	struct dispqt_playlisteditor_model_config_s *pmc = this->main_window->PlaylistEditor->tab_get_pmc(&pet, this->side_num, -1);
	if(pmc && pet && pet->editor_tab_tables[pmc->tabnum])
		pet->editor_tab_tables[pmc->tabnum]->setFocus();
}

void PlaylistEditorTabs::tab_head_contextmenuaction_duplicate(void)
{
	this->main_window->PlaylistEditor->editortabs_editlisteventcb_init(DISPQT_EDITOR_CBCMD_TAB_ADD, 0, this->side_num, this->selected_tab_num, -1);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_copyToOtherSide(void)
{
	this->main_window->PlaylistEditor->editortabs_editlisteventcb_init(DISPQT_EDITOR_CBCMD_TAB_ADD, EDITLIST_ADDTABMODE_TOEND, this->side_num, this->selected_tab_num, !this->side_num);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_locktab(void)
{
	this->main_window->PlaylistEditor->editortabs_editlisteventcb_init(DISPQT_EDITOR_CBCMD_TAB_LOCK, 0, this->side_num, this->selected_tab_num, -1);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_newEmptyTab(void)
{
	this->main_window->PlaylistEditor->editortabs_editlisteventcb_init(DISPQT_EDITOR_CBCMD_TAB_ADD, (EDITLIST_ADDTABMODE_BLANK | EDITLIST_ADDTABMODE_TOEND), this->side_num, -1, -1);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_remove(void)
{
	struct dispqt_playlisteditor_model_config_s *pmc = this->main_window->PlaylistEditor->tab_get_pmc(NULL, this->side_num, this->selected_tab_num);
	if(!pmc)
		return;
	if(funcbit_test(pmc->editloadtype, PLL_LOCKTAB)) {
		this->tab_head_contexmenu_lockedfunc_msg();
		return;
	}
	this->main_window->PlaylistEditor->editortabs_editlisteventcb_init(DISPQT_EDITOR_CBCMD_TAB_DEL, 0, this->side_num, this->selected_tab_num, -1);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_loadfiles(void)
{
	this->main_window->mainwin_load_files_or_dir(this->side_num, this->selected_tab_num, Mainwindow_SelectLoadFiles);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_loaddir(void)
{
	this->main_window->mainwin_load_files_or_dir(this->side_num, this->selected_tab_num, Mainwindow_SelectLoadDir);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_loadurl(void)
{
	this->main_window->mainwin_load_files_or_dir(this->side_num, this->selected_tab_num, Mainwindow_SelectLoadUrl);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_savelistas(void)
{
	this->main_window->PlaylistEditor->editortabs_editlisteventcb_init(DISPQT_EDITOR_CBCMD_SAVELISTAS, 0, this->side_num, this->selected_tab_num, -1);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_reload(void)
{
	this->main_window->PlaylistEditor->editortabs_editlisteventcb_init(DISPQT_EDITOR_CBCMD_RELOAD, 0, this->side_num, this->selected_tab_num, -1);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_dirswitch(void)
{
	struct dispqt_playlisteditor_model_config_s *pmc = this->main_window->PlaylistEditor->tab_get_pmc(NULL, this->side_num, this->selected_tab_num);
	if(!pmc)
		return;
	if(funcbit_test(pmc->editloadtype, PLL_LOCKTAB)) {
		this->tab_head_contexmenu_lockedfunc_msg();
		return;
	}
	this->main_window->PlaylistEditor->editortabs_editlisteventcb_init(DISPQT_EDITOR_CBCMD_DIRSWITCH, 0, this->side_num, this->selected_tab_num, -1);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_randomize(void)
{
	this->main_window->PlaylistEditor->editortabs_editlisteventcb_init(DISPQT_EDITOR_CBCMD_RANDOMIZE, 0, this->side_num, this->selected_tab_num, -1);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_clearlist(void)
{
	struct dispqt_playlisteditor_model_config_s *pmc = this->main_window->PlaylistEditor->tab_get_pmc(NULL, this->side_num, this->selected_tab_num);
	if(!pmc)
		return;
	if(funcbit_test(pmc->editloadtype, PLL_LOCKTAB)) {
		this->tab_head_contexmenu_lockedfunc_msg();
		return;
	}
	this->main_window->PlaylistEditor->editortabs_editlisteventcb_init(DISPQT_EDITOR_CBCMD_CLEARLIST, 0, this->side_num, this->selected_tab_num, -1);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_sort_col_n(unsigned int col)
{
	this->main_window->PlaylistEditor->editortabs_editlisteventcb_init(DISPQT_EDITOR_CBCMD_SORT, col, this->side_num, this->selected_tab_num, -1);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_sort_col_0(void)
{
	tab_head_contextmenuaction_sort_col_n(0);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_sort_col_1(void)
{
	tab_head_contextmenuaction_sort_col_n(1);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_sort_col_2(void)
{
	tab_head_contextmenuaction_sort_col_n(2);
}

void PlaylistEditorTabs::tab_head_contextmenuaction_sort_col_3(void)
{
	tab_head_contextmenuaction_sort_col_n(3);
}

void PlaylistEditorTabs::showContextMenu(const QPoint &point)
{
	if (point.isNull())
		return;
	int tabIndex = this->tabBar()->tabAt(point);
	if(tabIndex < 0)
		return;
	if(!this->tabs_get_table(tabIndex))
		return;
	this->main_window->signal_video_mainwin_opacity_disable(true);
	this->selected_tab_num = tabIndex;
	this->tab_head_contextmenu_add_vary_texts();
	this->tab_head_contextmenu->exec(this->tabBar()->mapToGlobal(point));
	this->main_window->signal_video_mainwin_opacity_disable(false);
}

//-----------------------------------------------------------------------------------------
void PlaylistEditorTabs::tab_create(struct dispqt_playlisteditor_model_config_s *pmc)
{
	PlaylistEditorTable *pet;
	int tabnum;

	this->mutex_editortabs.tryLock(DISPQT_MUTEX_TIMEOUT);
	tabnum = pmc->tabnum;
	if(tabnum >= PLAYLIST_MAX_TABS_PER_SIDE)
		goto err_out_create;
	pet = this->editor_tab_tables[tabnum];
	if(pet)
		goto err_out_exists;

	pet = new PlaylistEditorTable(this->main_window, this, this->side_num);
	if(!pet)
		goto err_out_create;
	this->editor_tab_tables[tabnum] = pet;

	this->editor_tab_indexes[tabnum] = this->addTab(pet, tr(" "));
	if(this->editor_tab_indexes[tabnum] < 0) {
		delete pet;
		goto err_out_create;
	}

	if(this->main_window->gui_config->editor_flags & DISPQT_CONFIG_EDITORFLAG_TRANSPARENT_BACK)
		pet->table_config_color(false);

err_out_exists:
	pet->pmcdata_update(pmc, false);
	this->tab_header_apply_info(pmc);

err_out_create:
	this->mutex_editortabs.unlock();
}

void PlaylistEditorTabs::tab_delete(struct dispqt_playlisteditor_model_config_s *pmc)
{
	int tabnum = pmc->tabnum;
	if(tabnum >= PLAYLIST_MAX_TABS_PER_SIDE)
		return;
	this->mutex_editortabs.tryLock(DISPQT_MUTEX_TIMEOUT);
	if(this->editor_tab_indexes[tabnum] >= 0) {
		this->removeTab(this->editor_tab_indexes[tabnum]);
		this->editor_tab_indexes[tabnum] = -1;
	}
	if(this->editor_tab_tables[tabnum]) {
		delete this->editor_tab_tables[tabnum];
		this->editor_tab_tables[tabnum] = NULL;
	}
	this->mutex_editortabs.unlock();
}

bool PlaylistEditorTabs::tab_select(unsigned int tabnum)
{
	if((tabnum >= PLAYLIST_MAX_TABS_PER_SIDE) || (this->editor_tab_indexes[tabnum] < 0))
		return false;
	if(this->currentIndex() != this->editor_tab_indexes[tabnum])
		this->setCurrentIndex(this->editor_tab_indexes[tabnum]);
	return true;
}

void PlaylistEditorTabs::tab_header_apply_info(struct dispqt_playlisteditor_model_config_s *pmc)
{
	if(!pmc || (this->editor_tab_indexes[pmc->tabnum] < 0))
		return;
	this->setTabText(this->editor_tab_indexes[pmc->tabnum], QString::fromUtf8(pmc->head_filename));
	this->setTabToolTip(this->editor_tab_indexes[pmc->tabnum], QString::fromUtf8(pmc->head_fullname));
	if(funcbit_test(pmc->flags, DISPQT_EDITOR_MODELCONFIGFLAG_PLAYTAB)) {
		this->setTabIcon(this->editor_tab_indexes[pmc->tabnum], QIcon(":/images/player_play.png"));
	} //else if(psi->editloadtype & PLL_LOCKTAB)
		//this->setTabIcon(this->editor_tab_indexes[psi->tabnum], QIcon(":/images/lock.png"));
	else
		this->setTabIcon(this->editor_tab_indexes[pmc->tabnum], QIcon(""));
}

int PlaylistEditorTabs::table_refresh_create(struct playlist_side_info *psi)
{
	int retcode = DISPQT_ERROR_EDITORTABLE_ARGS;
	PlaylistEditorTable *table;
	void *table_data_ptr, *pmc_data_ptr;

	if(!psi)
		return retcode;
	unsigned int tabnum = psi->tabnum;
	if(tabnum >= PLAYLIST_MAX_TABS_PER_SIDE)
		return retcode;

	this->mutex_editortabs.tryLock(DISPQT_MUTEX_TIMEOUT);
	if(this->action_table_refresh->userData(this->act_tablerefresh_userdataid_model) || this->action_table_refresh->userData(this->act_tablerefresh_userdataid_pmc)){
		retcode = DISPQT_ERROR_EDITORTABLE_BUSY;
		goto err_out_ttrc;
	}
	table = this->editor_tab_tables[tabnum];
	if(!table){
		retcode = DISPQT_ERROR_EDITORTABLE_MISSING;
		goto err_out_ttrc;
	}
	retcode = table->table_refresh_create(psi, &table_data_ptr, &pmc_data_ptr);
	if(retcode == DISPQT_ERROR_OK){
		this->action_table_refresh->setUserData(this->act_tablerefresh_userdataid_model, (QObjectUserData *)(table_data_ptr));
		this->action_table_refresh->setUserData(this->act_tablerefresh_userdataid_pmc, (QObjectUserData *)(pmc_data_ptr));
	}

err_out_ttrc:
	this->mutex_editortabs.unlock();
	if(retcode == DISPQT_ERROR_OK){
		mpxplay_debugf(DISPQT_DEBUGOUT_FUNC,"table_refresh_create trigger END t:%3.2f", (float)pds_gettimeh() / 100.0f);
		this->action_table_refresh->activate(QAction::Trigger);
	}
	return retcode;
}

void PlaylistEditorTabs::table_refresh_apply()
{
	PlaylistEditorModel *model_new = (PlaylistEditorModel *)this->action_table_refresh->userData(this->act_tablerefresh_userdataid_model);
	struct dispqt_playlisteditor_model_config_s *pmc = (struct dispqt_playlisteditor_model_config_s *)this->action_table_refresh->userData(this->act_tablerefresh_userdataid_pmc);
	mpxplay_debugf(DISPQT_DEBUGOUT_FUNC,"table_refresh_apply BEGIN t:%3.2f", (float)pds_gettimeh() / 100.0f);
	if(!model_new || !pmc)
		return;
	this->mutex_editortabs.tryLock(DISPQT_MUTEX_TIMEOUT);
	PlaylistEditorTable *table = this->editor_tab_tables[pmc->tabnum];
	if(!table)
		goto err_out_tra;
	table->table_refresh_apply(model_new, pmc);
	this->tab_header_apply_info(pmc);

err_out_tra:
	this->action_table_refresh->setUserData(this->act_tablerefresh_userdataid_model, NULL);
	this->action_table_refresh->setUserData(this->act_tablerefresh_userdataid_pmc, NULL);
	mpxplay_debugf(DISPQT_DEBUGOUT_FUNC,"table_refresh_apply END");
	this->mutex_editortabs.unlock();
}

void PlaylistEditorTabs::line_select_request(struct playlist_side_info *psi, struct playlist_entry_info *pei)
{
	if(!psi)
		return;
	unsigned int tabnum = psi->tabnum;
	if(tabnum >= PLAYLIST_MAX_TABS_PER_SIDE)
		return;
	if(this->action_line_select->userData(this->act_lineselect_userdataid_reqinfo))
		return;
	struct dispqt_editor_lineselect_request_s *lsrq = (struct dispqt_editor_lineselect_request_s *)pds_malloc(sizeof(struct dispqt_editor_lineselect_request_s));
	if(!lsrq)
		return;
	this->mutex_editortabs.tryLock(DISPQT_MUTEX_TIMEOUT);
	lsrq->flags = 0;
	if(psi == psi->mvp->psie)
		lsrq->flags |= DISPQT_EDITOR_FLAG_SETFOCUS;
	lsrq->sidenum = psi->sidenum;
	lsrq->tabnum = tabnum;
	lsrq->linenum = playlist_editlist_entry_diff(psi, psi->editor_from, pei);

	this->action_line_select->setUserData(this->act_lineselect_userdataid_reqinfo, (QObjectUserData *)(lsrq));
	this->mutex_editortabs.unlock();
	this->action_line_select->activate(QAction::Trigger);
	//mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "LSR s:%d t:%d i:%2d ef:%8.8X ", psi->sidenum, tabnum, lsrq->linenum, (unsigned long)(psi->editor_from - psi->firstentry));
}

void PlaylistEditorTabs::line_select_apply(void)
{
	struct dispqt_editor_lineselect_request_s *lsrq = (struct dispqt_editor_lineselect_request_s *)this->action_line_select->userData(this->act_lineselect_userdataid_reqinfo);
	PlaylistEditorTable *pet;

	if(!lsrq)
		return;

	this->mutex_editortabs.tryLock(DISPQT_MUTEX_TIMEOUT);

	if(!this->tab_select(lsrq->tabnum))
		goto err_out_apply;

	pet = this->editor_tab_tables[lsrq->tabnum];
	if(!pet)
		goto err_out_apply;

	if(lsrq->flags & DISPQT_EDITOR_FLAG_SETFOCUS)
		pet->setFocus();

	pet->table_line_select(lsrq->linenum);

err_out_apply:
	this->action_line_select->setUserData(this->act_lineselect_userdataid_reqinfo, NULL);
	pds_free(lsrq);
	this->mutex_editortabs.unlock();
}

PlaylistEditorTable *PlaylistEditorTabs::tabs_get_table(int tabnum)
{
	PlaylistEditorTable *table;
	if(tabnum < 0)
		tabnum = this->selected_tab_num;
	if(tabnum >= PLAYLIST_MAX_TABS_PER_SIDE)
		return NULL;
	this->mutex_editortabs.tryLock(DISPQT_MUTEX_TIMEOUT);
	table = this->editor_tab_tables[tabnum];
	this->mutex_editortabs.unlock();
	return table;
}
