winamp/Src/Plugins/Library/ml_history/ml_history.cpp

289 lines
7.7 KiB
C++

#include "main.h"
#include "..\..\General\gen_ml/config.h"
#include "..\..\General\gen_ml/gaystring.h"
#include "..\..\General\gen_hotkeys/wa_hotkeys.h"
#include "..\..\General\gen_ml/MediaLibraryCOM.h"
#include "..\..\General\gen_ml/ml_ipc_0313.h"
#include <malloc.h>
int ml_history_tree = -1;
HWND m_curview_hwnd = NULL;
static WNDPROC wa_oldWndProc=0;
wchar_t *history_fn = 0;
int timer = -1;
static wchar_t *last_history_fn;
static int last_timer=-1;
static int last_play_pos=0;
int history_fn_mode = 0;
nde_database_t g_db = NULL;
nde_table_t g_table = NULL;
int g_table_dirty = 0;
C_Config *g_config;
CRITICAL_SECTION g_db_cs;
HWND onTreeViewSelectChange(HWND hwnd)
{
openDb();
if (m_curview_hwnd) DestroyWindow(m_curview_hwnd);
if (!g_table || nde_error)
{
m_curview_hwnd = WASABI_API_CREATEDIALOGPARAMW(IDD_VIEW_DB_ERROR, hwnd, view_errorinfoDialogProc, 0);
}
else
{
m_curview_hwnd = WASABI_API_CREATEDIALOGPARAMW(IDD_VIEW_RECENTITEMS, hwnd, view_historyDialogProc, 0);
}
return m_curview_hwnd;
}
static void history_cleanupifnecessary();
static LRESULT APIENTRY wa_newWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
int history_init()
{
if ( !g_config->ReadInt( L"showrecentitems", 1 ) )
return 1;
NAVINSERTSTRUCT nis = {0};
nis.item.cbSize = sizeof(NAVITEM);
nis.item.pszText = WASABI_API_LNGSTRINGW(IDS_HISTORY);
nis.item.pszInvariant = L"History";
nis.item.mask = NIMF_TEXT | NIMF_TEXTINVARIANT | NIMF_IMAGE | NIMF_IMAGESEL;
nis.item.iSelectedImage = nis.item.iImage = mediaLibrary.AddTreeImageBmp(IDB_TREEITEM_RECENT);
// map to item id (will probably have to change but is a quick port to support invariant item naming)
NAVITEM nvItem = {sizeof(NAVITEM),0,NIMF_ITEMID,};
nvItem.hItem = MLNavCtrl_InsertItem(plugin.hwndLibraryParent, &nis);
MLNavItem_GetInfo(plugin.hwndLibraryParent, &nvItem);
ml_history_tree = nvItem.id;
if (!wa_oldWndProc) // don't double dip (we call history_init() dynamically if the user fiddles with prefs
{
wa_oldWndProc = (WNDPROC)SetWindowLongPtrW(plugin.hwndWinampParent, GWLP_WNDPROC, (LONG_PTR)wa_newWndProc);
}
return 1;
}
void history_quit()
{
if (last_history_fn)
{
if ((last_timer <= 0) || (last_play_pos > last_timer))
{
if (last_play_pos) history_onFile(last_history_fn, last_play_pos);
}
}
free(last_history_fn);
last_history_fn = 0;
free(history_fn);
history_fn = 0;
closeDb();
mediaLibrary.RemoveTreeItem(ml_history_tree);
ml_history_tree=0;
}
static void RetypeFilename(nde_table_t table)
{
// TODO: UI
int totalRecords = NDE_Table_GetRecordsCount(g_table);
if (totalRecords == 0) // bail out early so we don't flash a dialog
return;
nde_scanner_t pruneScanner = NDE_Table_CreateScanner(table);
if (pruneScanner)
{
NDE_Scanner_First(pruneScanner);
while (!NDE_Scanner_EOF(pruneScanner))
{
nde_field_t f = NDE_Scanner_GetFieldByID(pruneScanner, HISTORYVIEW_COL_FILENAME);
if (f && NDE_Field_GetType(f) == FIELD_STRING)
{
wchar_t *s = NDE_StringField_GetString(f);
ndestring_retain(s);
NDE_Scanner_DeleteField(pruneScanner, f);
nde_field_t new_f = NDE_Scanner_NewFieldByID(pruneScanner, HISTORYVIEW_COL_FILENAME);
NDE_StringField_SetNDEString(new_f, s);
ndestring_release(s);
NDE_Scanner_Post(pruneScanner);
}
else if (f)
break;
NDE_Scanner_Next(pruneScanner);
}
NDE_Table_DestroyScanner(table, pruneScanner);
NDE_Table_Sync(table);
}
}
static void CreateFields(nde_table_t table)
{
// create defaults
NDE_Table_NewColumnW(g_table, HISTORYVIEW_COL_LASTPLAYED, L"lastplay", FIELD_DATETIME);
NDE_Table_NewColumnW(g_table, HISTORYVIEW_COL_PLAYCOUNT, L"playcount", FIELD_INTEGER);
NDE_Table_NewColumnW(g_table, HISTORYVIEW_COL_TITLE, L"title", FIELD_STRING);
NDE_Table_NewColumnW(g_table, HISTORYVIEW_COL_LENGTH, L"length", FIELD_INTEGER);
NDE_Table_NewColumnW(g_table, HISTORYVIEW_COL_FILENAME, L"filename", FIELD_FILENAME);
NDE_Table_NewColumnW(g_table, HISTORYVIEW_COL_OFFSET, L"offset", FIELD_INTEGER);
NDE_Table_PostColumns(g_table);
NDE_Table_AddIndexByIDW(g_table, 0, L"filename");}
int openDb()
{
if (g_table) return 1; // need to close first
EnterCriticalSection(&g_db_cs);
// benski> i know this looks redundant, but we might have sat and blocked at the above Critical Section for a while
if (g_table)
{
LeaveCriticalSection(&g_db_cs);
return 1;
}
if (!g_db)
{
__try
{
g_db = NDE_CreateDatabase(plugin.hDllInstance);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
g_db = NULL;
LeaveCriticalSection(&g_db_cs);
return 0;
}
}
wchar_t tableName[MAX_PATH] = {0}, indexName[MAX_PATH] = {0};
PathCombineW(tableName, g_tableDir, L"recent.dat");
PathCombineW(indexName, g_tableDir, L"recent.idx");
if (!g_db)
{
LeaveCriticalSection(&g_db_cs);
return 0;
}
g_table = NDE_Database_OpenTable(g_db, tableName, indexName, NDE_OPEN_ALWAYS, NDE_CACHE);
if (g_table)
{
CreateFields(g_table);
RetypeFilename(g_table);
}
LeaveCriticalSection(&g_db_cs);
return (g_table != NULL);
}
void closeDb(bool clear_dirty)
{
if (g_table_dirty && g_table)
{
history_bgQuery_Stop();
NDE_Table_Sync(g_table);
if (clear_dirty) g_table_dirty=0;
}
if (g_db)
{
__try
{
if (g_table)
NDE_Database_CloseTable(g_db, g_table);
NDE_DestroyDatabase(g_db);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
}
g_db = NULL;
g_table = NULL;
}
INT_PTR pluginHandleIpcMessage(int msg, INT_PTR param)
{
return (INT_PTR) SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, param, msg);
}
static LRESULT APIENTRY wa_newWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if ((uMsg == WM_SYSKEYDOWN || uMsg == WM_KEYDOWN) &&
wParam == 'H' &&
!(GetAsyncKeyState(VK_MENU)&0x8000) &&
!(GetAsyncKeyState(VK_SHIFT)&0x8000) &&
(GetAsyncKeyState(VK_CONTROL)&0x8000)
&& ml_history_tree > 0)
{
mediaLibrary.ShowMediaLibrary();
mediaLibrary.SelectTreeItem(ml_history_tree);
}
else if (history_fn && uMsg == WM_TIMER && wParam == 8082)
{
if (!history_fn_mode || SendMessage(hwndDlg, WM_WA_IPC, 0, IPC_GETOUTPUTTIME) > 350)
{
KillTimer(hwndDlg, 8082);
if (SendMessage(hwndDlg, WM_WA_IPC, 0, IPC_ISPLAYING) == 1)
{
history_onFile(history_fn, -1);
}
free(history_fn);
history_fn = 0;
}
return CallWindowProcW(wa_oldWndProc, hwndDlg, uMsg, wParam, lParam);
}
else if (last_history_fn && uMsg == WM_TIMER && wParam == 8083)
{
KillTimer(hwndDlg, 8083);
history_onFile(last_history_fn, last_play_pos);
return CallWindowProcW(wa_oldWndProc, hwndDlg, uMsg, wParam, lParam);
}
else if (uMsg == WM_WA_IPC)
{
if(lParam == IPC_STOPPLAYING && g_config->ReadInt(L"resumeplayback",0))
{
KillTimer(hwndDlg, 8082);
if (last_history_fn)
{
free(last_history_fn);
last_history_fn = 0;
}
if (history_fn) last_history_fn = _wcsdup(history_fn);
// copes with stopping after playback was tracked otherwise this aspect will fail!
else last_history_fn = _wcsdup((wchar_t*)SendMessage(hwndDlg,WM_WA_IPC,0,IPC_GET_PLAYING_FILENAME));
last_timer = timer;
stopPlayingInfoStruct *stopPlayingInfo = (stopPlayingInfoStruct *)wParam;
last_play_pos = stopPlayingInfo->last_time;
if (!stopPlayingInfo->g_fullstop)
{
if ((last_timer <= 0) || (last_play_pos > last_timer))
{
if (last_play_pos) SetTimer(hwndDlg, 8083, 150, NULL);
}
}
else // clean up play offset
{
if (last_history_fn) history_onFile(last_history_fn, 0);
}
}
else if(lParam == IPC_CB_MISC)
{
if (wParam == IPC_CB_MISC_PAUSE)
{
KillTimer(hwndDlg, 8082);
}
else if (wParam == IPC_CB_MISC_UNPAUSE)
{
if (history_fn) History_StartTracking(history_fn, true);
}
}
} // wm_wa_ipc
return CallWindowProcW(wa_oldWndProc, hwndDlg, uMsg, wParam, lParam);
}