// // Database.cpp // // (c)Copyright 2000 The Caney Group, LLC. All Rights Reserved. // // Programmed by Steven J. Eschweiler // // Compiled with Microsoft Visual C++ 6.0 Professional // #include <windows.h> #include <windowsx.h> #include <commctrl.h> #include <direct.h> #include <ctype.h> #include <winver.h> #include "VideoPlayer.h" #include "IndotekBackgroundTechnology.h" #include "Database.h" #include "comcthlp.h" #include "resource.h" BOOL gbConstructingResultList,gbConstructingPlaylist; int GetAppVersion(void); #define WFW_DELETE(p) { if(p) { delete (p); (p)=NULL; } } char *DatabaseCSV=NULL; // Allocated as needed. int DatabaseCSVFileSize; int DatabaseCSVRowCount; int DatabaseCSVColCount; #define DATABASECSV_MAX_ROWS 16384 #define DATABASECSV_MAX_COLUMNS 26 // DatabaseCSVLine contains pointers into DatabaseCSV for a // particular row and column. Each field in DatabaseCSV // is converted into a NULL terminated string. char *DatabaseCSVLine[DATABASECSV_MAX_ROWS][DATABASECSV_MAX_COLUMNS]; #define CONFIGTXT_PROJECT_NAME 0 #define CONFIGTXT_VIDEOINFORMATION 1 #define CONFIGTXT_TABS 2 #define CONFIGTXT_TEXT_FORMAT 3 #define CONFIGTXT_AUTHORIZATION 4 char *ConfigTXT=NULL; // Allocated as needed. int ConfigTXTFileSize; int ConfigTXTNumLines; #define CONFIGTXT_MAX_LINES 16 char *ConfigTXTLine[CONFIGTXT_MAX_LINES]; typedef struct __FILTERTAB__ { char *pName; int DatabaseCSVColIndex; char *pUniqueEntryName[DATABASECSV_MAX_ROWS]; int UniqueEntryNameCount; BOOL bUniqueEntryFiltered[DATABASECSV_MAX_ROWS]; BOOL bAllFiltered; // This is true whether all are checked or none are checked. } FILTERTAB; FILTERTAB *FilterTab=NULL; int FilterTabCount; BOOL gbTempUniqueEntryFiltered[DATABASECSV_MAX_ROWS]; // This array contains TRUE for each row that is included in the // selections list box. This is basically used as an intermediary // for constructing the ResultList[] array below. BOOL gbFilterResults[DATABASECSV_MAX_ROWS]; // This is the Result List... It contains indexes into the // database... int ResultList[DATABASECSV_MAX_ROWS]; int ResultListCount; BOOL bResultListCheckState[DATABASECSV_MAX_ROWS]; // This is the playlist... It contains indexes into the // database... int Playlist[DATABASECSV_MAX_ROWS]; int PlaylistCount; BOOL bPlaylistCheckState[DATABASECSV_MAX_ROWS]; // This contains notes, one whole page for each entry typedef struct __NOTES__ { char *Note; // Allocated as needed. Size is strlen(*Note)+1 int NoteSize; // Number of elements in Note[], including terminating NULL. We must save this because strlen and sizeof won't work on dynamically allocated arrays using the new keyword } NOTES; NOTES Notes[DATABASECSV_MAX_ROWS]; int CurrentMovieIndex=0; // Assume none // The current video clip info is stored here #define MAX_EDIT_BOX_LENGTH 32768 char TempNotes[MAX_EDIT_BOX_LENGTH]; char CurrentVideoClipInfoString[MAX_EDIT_BOX_LENGTH]; int db_InternalGetMovieIndexResultList(void) { HTREEITEM hItem; // The tree view control's highlighted item // is going to give us the CurrentMovieIndex hItem = TreeView_GetSelection(GetDlgItem(hwndDialog,IDC_TREERESULTLIST)); if (hItem==NULL) return 0; return ResultList[TreeView_GetSelectionIndex(GetDlgItem(hwndDialog,IDC_TREERESULTLIST),hItem)]; } int db_InternalGetMovieIndexPlaylist(void) { HTREEITEM hItem; // The tree view control's highlighted item // is going to give us the CurrentMovieIndex hItem = TreeView_GetSelection(GetDlgItem(hwndDialog,IDC_TREEPLAYLIST)); if (hItem==NULL) return 0; return Playlist[TreeView_GetSelectionIndex(GetDlgItem(hwndDialog,IDC_TREEPLAYLIST),hItem)]; } BOOL db_Open(char *CDROM_Path) { HANDLE hDatabaseCSVFile,hConfigTXTFile; char db_pathname[_MAX_PATH],cfg_pathname[_MAX_PATH]; int LoopVar,LoopVar2,DatabaseCSVRowIndex; BOOL bFieldIsQuoted; float fDatabaseCSVAuthorizationCode; // Open Database.CSV file or exit with error. strcpy(db_pathname,CDROM_Path); strcat(db_pathname,"\\database.csv"); if ( (hDatabaseCSVFile = r3d_FileOpen( db_pathname, R3D_READ)) == INVALID_HANDLE_VALUE) { return FALSE; } // We generate an authorization code for comparison to // the value in the config.txt file. THEY MUST MATCH! fDatabaseCSVAuthorizationCode = (float)r3d_FileSize(hDatabaseCSVFile); fDatabaseCSVAuthorizationCode *= 314.0F; // Open config.txt file or exit with error. strcpy(cfg_pathname,CDROM_Path); strcat(cfg_pathname,"\\config.txt"); if ( (hConfigTXTFile = r3d_FileOpen( cfg_pathname, R3D_READ)) == INVALID_HANDLE_VALUE) { // Close DatabaseCSV file. r3d_FileClose(hDatabaseCSVFile); return FALSE; } // Read the ConfigTXT file into memory and close file. ConfigTXTFileSize = (int)r3d_FileSize(hConfigTXTFile); ConfigTXT = new char[ConfigTXTFileSize+1]; if ( NULL == ConfigTXT ) { r3d_FileClose(hConfigTXTFile); r3d_FileClose(hDatabaseCSVFile); MessageBox(hwndMain,"Can not allocate memory for ConfigTXT","Error",MB_OK); return FALSE; } r3d_FileRead(hConfigTXTFile,ConfigTXT,ConfigTXTFileSize); r3d_FileClose(hConfigTXTFile); ConfigTXTFileSize+=1; ConfigTXT[ConfigTXTFileSize-1]=0x00; // Read the DatabaseCSV file into memory and close file. DatabaseCSVFileSize = (int)r3d_FileSize(hDatabaseCSVFile); DatabaseCSV = new char[DatabaseCSVFileSize+1]; if ( NULL == DatabaseCSV ) { WFW_DELETE(ConfigTXT); r3d_FileClose(hConfigTXTFile); r3d_FileClose(hDatabaseCSVFile); MessageBox(hwndMain,"Can not allocate memory for DatabaseCSV","Error",MB_OK); return FALSE; } r3d_FileRead(hDatabaseCSVFile,DatabaseCSV,DatabaseCSVFileSize); r3d_FileClose(hDatabaseCSVFile); DatabaseCSVFileSize+=1; DatabaseCSV[DatabaseCSVFileSize-1]=0x00; // If a field starts with a quotes, it means that there is // either quation marks inside the field or that there are // comma's in the field. // // A qoutation followed immediatley by a quotation means that // there is a single quotation mark. If there is a quotation // mark at the beginning and end of the field, it means that // there is a comma in there. // DatabaseCSVRowCount = 0; DatabaseCSVColCount = 0; if (DatabaseCSV[0] == '\"') { bFieldIsQuoted = TRUE; LoopVar=1; DatabaseCSVLine[DatabaseCSVRowCount][DatabaseCSVColCount] = &DatabaseCSV[1]; } else { bFieldIsQuoted = FALSE; LoopVar=0; DatabaseCSVLine[DatabaseCSVRowCount][DatabaseCSVColCount] = &DatabaseCSV[0]; } for (; LoopVar<DatabaseCSVFileSize; LoopVar++) { // If the current field is quoted, then there is either // a " or a comma in the field. A quote is represented // as "" in the field. A comma is simply a comma. if (bFieldIsQuoted) { // If we are here, we increase LoopVar until we // find the field closing mark ", OR "\r\n // // At the same time we convert "" to '' and we // treat comma's as literal // for (LoopVar2=LoopVar; LoopVar2<DatabaseCSVFileSize; LoopVar2++) { if (DatabaseCSV[LoopVar2]=='\"' && DatabaseCSV[LoopVar2+1]=='\"' ) { // Double quotes found. DatabaseCSV[LoopVar2]='\''; LoopVar2++; DatabaseCSV[LoopVar2]='\''; } else if (DatabaseCSV[LoopVar2]=='\"' && (DatabaseCSV[LoopVar2+1]==',' || DatabaseCSV[LoopVar2+1]=='\r' ) ) { // End of field found. DatabaseCSV[LoopVar2]=0x00; // Let the remainder of the LoopVar loop // handle the comma or end of line case. LoopVar2++; LoopVar=LoopVar2; break; } } } // Now we increase LoopVar until we find the next field. // At the same time, we convert comma's and \r and \n into // a value of 0x00 to get NULL terminated strings. // if (DatabaseCSV[LoopVar]=='\r') { DatabaseCSV[LoopVar]=0x00; } if (DatabaseCSV[LoopVar]=='\n') { DatabaseCSVRowCount++; // We may have reached the end of file. if (LoopVar+1==DatabaseCSVFileSize) { DatabaseCSVColCount++; // Make it accurate if (DatabaseCSVColCount>26) MessageBox(hwndMain,"The database contains more than 26 columns - This application will not function correctly!","Error",MB_OK); break; } DatabaseCSVColCount=0; DatabaseCSV[LoopVar]=0x00; DatabaseCSVLine[DatabaseCSVRowCount][DatabaseCSVColCount] = &DatabaseCSV[LoopVar+1]; if (DatabaseCSV[LoopVar+1] == '\"') { bFieldIsQuoted = TRUE; LoopVar++; DatabaseCSVLine[DatabaseCSVRowCount][DatabaseCSVColCount] = &DatabaseCSV[LoopVar+1]; } else { bFieldIsQuoted = FALSE; DatabaseCSVLine[DatabaseCSVRowCount][DatabaseCSVColCount] = &DatabaseCSV[LoopVar+1]; } } if (DatabaseCSV[LoopVar]==',') { DatabaseCSVColCount++; if (DatabaseCSVColCount>26) MessageBox(hwndMain,"The database contains more than 26 columns - This application will not function correctly!","Error",MB_OK); DatabaseCSV[LoopVar]=0x00; if (DatabaseCSV[LoopVar+1] == '\"') { bFieldIsQuoted = TRUE; LoopVar++; DatabaseCSVLine[DatabaseCSVRowCount][DatabaseCSVColCount] = &DatabaseCSV[LoopVar+1]; } else { bFieldIsQuoted = FALSE; DatabaseCSVLine[DatabaseCSVRowCount][DatabaseCSVColCount] = &DatabaseCSV[LoopVar+1]; } } } // At this point, the database could contain an empty line // or lines at the end of the database file... This is very // possible. We need to go backwards through each line and // if we find no data, we reduce the DatabaseCSVRowCount // variable for each one we find until no black lines are // found. // for (DatabaseCSVRowIndex=DatabaseCSVRowCount-1; DatabaseCSVRowIndex>=0; DatabaseCSVRowIndex--) { // Determine if this line is blank. Since the database // should be set up with NO BLANK FIELDS then we // simply need to check the first field in every line // to establish whether that line is blank or not. // // if (strcmp(DatabaseCSVLine[DatabaseCSVRowIndex][0],"")==0) if (strlen(DatabaseCSVLine[DatabaseCSVRowIndex][0])==0) { DatabaseCSVRowCount--; } } // Now we need to parse the contents of the Config.txt file. ConfigTXTNumLines=1; ConfigTXTLine[0]=&ConfigTXT[0]; for (LoopVar=0; LoopVar<ConfigTXTFileSize; LoopVar++) { if (ConfigTXT[LoopVar]=='\r') { ConfigTXT[LoopVar]=0x00; } if (ConfigTXT[LoopVar]=='\n' || LoopVar+1==ConfigTXTFileSize) { ConfigTXT[LoopVar]=0x00; if (LoopVar+1!=ConfigTXTFileSize) { ConfigTXTLine[ConfigTXTNumLines] = &ConfigTXT[LoopVar+1]; ConfigTXTNumLines++; } } } // At this point, we authorize the file. This helps to avoid // theft of the software for use with other databases. // // To accomplish authorization, we use the // fDatabaseCSVAuthorizationCode value which was calculated // above and compare it to the authorization code in // the config.txt file. // // THEY MUST MATCH! // // // NOW, in order to avoid problems between future versions of // the Word for Word and older databases (of which // do not contain the Authorization Line in config.txt), // we must look at the file version number. It must be greater // than version 1.1 which is coded as 110. // if (GetAppVersion()>110) { if (atof(ConfigTXTLine[CONFIGTXT_AUTHORIZATION]) != fDatabaseCSVAuthorizationCode ) { WFW_DELETE(DatabaseCSV); WFW_DELETE(ConfigTXT); MessageBox(hwndMain,"The database has not been authorized. This application will now exit.","Error",MB_OK|MB_ICONSTOP); return FALSE; } } PlaylistCount=0; return TRUE; } void db_SetupInterface(void) { HWND hwndTabControl; TCITEM tie; int LoopVar; RECT rcMainClient; int FilterTabIndex,RowIndex,UniqueEntryIndex; BOOL bInList; // If there is no Config.txt, DatabaseCSV or dialog box, // there is an error and we return immediately. if (ConfigTXT==NULL || DatabaseCSV==NULL || hwndDialog==NULL) { MessageBox(hwndMain,"ConfigTXT=NULL or DatabaseCSV=NULL or hwndDialog==NULL","Error",MB_OK); return; } // Get the handle of the Filtering TAB Control. hwndTabControl = GetDlgItem(hwndDialog, IDC_TABFILTER); // Add the appropriate filter options based on the settings // in Config.txt, Line 3 (index 2). Remeber, only A-Z // are allowed. Something like AB,AC would be illegal and // would not work. // strlwr(ConfigTXTLine[CONFIGTXT_TABS]); FilterTabCount=(int)strlen(ConfigTXTLine[CONFIGTXT_TABS]); // MUST BE LOWER CASE! strlwr(ConfigTXTLine[CONFIGTXT_VIDEOINFORMATION]); // Make sure this line is lower case!!! // Allocate space for FilterTab WFW_DELETE(FilterTab); FilterTab = new FILTERTAB[FilterTabCount]; if ( NULL == FilterTab ) { MessageBox(hwndMain,"Can not allocate FilterTab","Error",MB_OK); return; } // Get tab info for FilterTab for (LoopVar=0; LoopVar<FilterTabCount; LoopVar++) { FilterTab[LoopVar].DatabaseCSVColIndex = (int)(ConfigTXTLine[CONFIGTXT_TABS][LoopVar]-'a'); tie.mask = TCIF_TEXT | TCIF_IMAGE; tie.iImage = 0; FilterTab[LoopVar].pName = DatabaseCSVLine[0][FilterTab[LoopVar].DatabaseCSVColIndex]; tie.pszText = FilterTab[LoopVar].pName; TabCtrl_InsertItem(hwndTabControl, LoopVar, &tie); } // Now we need to resize the "client" of the tab control. GetClientRect(hwndMain, &rcMainClient); SendMessage(hwndMain,WM_SIZE,(WPARAM)SIZE_RESTORED,MAKELPARAM(rcMainClient.right,rcMainClient.bottom)); // Now we construct an internal list of what to display // in the treeview control for each filtering option. // We maintain a database of checked/unchecked options. // for (FilterTabIndex=0; FilterTabIndex<FilterTabCount; FilterTabIndex++) { // We know that the first entry (db row 1) is unique... FilterTab[FilterTabIndex].pUniqueEntryName[0] = DatabaseCSVLine[1][FilterTab[FilterTabIndex].DatabaseCSVColIndex]; FilterTab[FilterTabIndex].UniqueEntryNameCount = 1; FilterTab[FilterTabIndex].bUniqueEntryFiltered[0] = FALSE; FilterTab[FilterTabIndex].bAllFiltered = TRUE; // Now, we search through entire column for any that // are not already in the list for (RowIndex=2; RowIndex<DatabaseCSVRowCount; RowIndex++) { // Is the name at RowIndex in our list? bInList = FALSE; // Assume FALSE for (UniqueEntryIndex=0; UniqueEntryIndex<FilterTab[FilterTabIndex].UniqueEntryNameCount; UniqueEntryIndex++) { if ( strcmp(FilterTab[FilterTabIndex].pUniqueEntryName[UniqueEntryIndex], DatabaseCSVLine[RowIndex][FilterTab[FilterTabIndex].DatabaseCSVColIndex]) == 0) { // Yes, the name is in our list, move along to // check next entry at RowIndex bInList = TRUE; break; } } if (bInList==FALSE) { // No, the name is NOT in our list, add it FilterTab[FilterTabIndex].pUniqueEntryName[FilterTab[FilterTabIndex].UniqueEntryNameCount] = DatabaseCSVLine[RowIndex][FilterTab[FilterTabIndex].DatabaseCSVColIndex]; // For Testing: FilterTab[FilterTabIndex].bUniqueEntryFiltered[FilterTab[FilterTabIndex].UniqueEntryNameCount] = (BOOL)(FilterTab[FilterTabIndex].UniqueEntryNameCount%2); FilterTab[FilterTabIndex].bUniqueEntryFiltered[FilterTab[FilterTabIndex].UniqueEntryNameCount] = FALSE; FilterTab[FilterTabIndex].UniqueEntryNameCount++; } } } // Set All Selections Available in selection list box gbFilterResults[0] = FALSE; // Never available for (RowIndex=1; RowIndex<DatabaseCSVRowCount; RowIndex++) gbFilterResults[RowIndex] = TRUE; // Lastly, initialize the TreeView control db_ConstructFilterTree(TabCtrl_GetCurSel(hwndTabControl)); // Put proper icons on TABS db_UpdateTABIcons(); db_UpdateSelections(); } void db_ConstructFilterTree(int FilterTabIndex) { int UniqueEntryIndex;//,MaxStrlen,TheStrlen; HWND hwndTreeControl;//,hwndTreeControl; TVINSERTSTRUCT tvis; // Change mouse cursor to hourglass // First delete all tree items, if any hwndTreeControl = GetDlgItem(hwndDialog, IDC_TREEFILTER); TreeView_DeleteAllItems(hwndTreeControl); // Initialize list view item structure ZeroMemory(&tvis, sizeof(TVINSERTSTRUCT)); tvis.hParent = NULL; tvis.hInsertAfter = TVI_LAST; tvis.item.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE; tvis.item.iImage = 0; tvis.item.iSelectedImage = 0; tvis.item.cchTextMax = 256; // Now based on what tab's selected, we display treeview... // // Find what FILTER TAB is active, and construct tree. // Cycle through possible checked selections and display them // for (UniqueEntryIndex=0; UniqueEntryIndex<FilterTab[FilterTabIndex].UniqueEntryNameCount; UniqueEntryIndex++) { tvis.item.pszText = FilterTab[FilterTabIndex].pUniqueEntryName[UniqueEntryIndex]; TreeView_InsertItem(hwndTreeControl, &tvis); } // Now set the check states to reflect our internal array TreeView_SetCheckStateAll(hwndTreeControl,FilterTab[FilterTabIndex].bUniqueEntryFiltered); } BOOL db_DetermineTreeChecked(HWND hwndTreeControl, int FilterTabIndex) { int UniqueEntryIndex; BOOL bNewStateFound; bNewStateFound = FALSE; if (FilterTab==NULL || FilterTabCount==0) return FALSE; // Get potential new check states into temporary array TreeView_GetCheckStateAll(hwndTreeControl,gbTempUniqueEntryFiltered); // Compare old check states with new check states for (UniqueEntryIndex=0; UniqueEntryIndex<FilterTab[FilterTabIndex].UniqueEntryNameCount; UniqueEntryIndex++) { if (gbTempUniqueEntryFiltered[UniqueEntryIndex] != FilterTab[FilterTabIndex].bUniqueEntryFiltered[UniqueEntryIndex] ) { bNewStateFound = TRUE; } } // Ok, now save new check states TreeView_GetCheckStateAll(hwndTreeControl,FilterTab[FilterTabIndex].bUniqueEntryFiltered); return bNewStateFound; } void db_UpdateTABIcons(void) { HWND hwndTabControl; int FilterTabIndex,UniqueEntryIndex; BOOL bFiltering; TCITEM tie; int UniqueEntryFilteredCount; // Now we determine whether the TAB should incdicate filtering // with a checked box icon. hwndTabControl = GetDlgItem(hwndDialog, IDC_TABFILTER); for (FilterTabIndex=0; FilterTabIndex<FilterTabCount; FilterTabIndex++) { FilterTab[FilterTabIndex].bAllFiltered = FALSE; // Assume FALSE UniqueEntryFilteredCount=0; bFiltering = FALSE; for (UniqueEntryIndex=0; UniqueEntryIndex<FilterTab[FilterTabIndex].UniqueEntryNameCount; UniqueEntryIndex++) { if ( TRUE == FilterTab[FilterTabIndex].bUniqueEntryFiltered[UniqueEntryIndex] ) { UniqueEntryFilteredCount++; bFiltering=TRUE; } } if (bFiltering==TRUE) { if (UniqueEntryFilteredCount==FilterTab[FilterTabIndex].UniqueEntryNameCount) FilterTab[FilterTabIndex].bAllFiltered = TRUE; // Set Checked Icon On TAB tie.mask = TCIF_IMAGE; tie.iImage = 1; TabCtrl_SetItem(hwndTabControl, FilterTabIndex, &tie); } else { FilterTab[FilterTabIndex].bAllFiltered = TRUE; // Set Non Checked Icon On TAB tie.mask = TCIF_IMAGE; tie.iImage = 0; TabCtrl_SetItem(hwndTabControl, FilterTabIndex, &tie); } } } void db_UpdateSelections(void) { int FilterTabIndex,UniqueEntryIndex,RowIndex; char buffer[4096]; // Assume TRUE for all videos found for (RowIndex=1; RowIndex<DatabaseCSVRowCount; RowIndex++) { gbFilterResults[RowIndex] = TRUE; } // Based on what TAB selections are filtered, // we determine what to display. for (FilterTabIndex=0; FilterTabIndex<FilterTabCount; FilterTabIndex++) { if (FilterTab[FilterTabIndex].bAllFiltered==FALSE) { for (UniqueEntryIndex=0; UniqueEntryIndex<FilterTab[FilterTabIndex].UniqueEntryNameCount; UniqueEntryIndex++) { if ( FALSE == FilterTab[FilterTabIndex].bUniqueEntryFiltered[UniqueEntryIndex] ) { // Find all rows containing the entry name // at the column and mark // gbFilterResults[RowIndex] as FALSE for (RowIndex=1; RowIndex<DatabaseCSVRowCount; RowIndex++) { if (gbFilterResults[RowIndex]==FALSE) continue; // Already marked as not available. if ( strcmp( DatabaseCSVLine[RowIndex][FilterTab[FilterTabIndex].DatabaseCSVColIndex], FilterTab[FilterTabIndex].pUniqueEntryName[UniqueEntryIndex]) == 0) { gbFilterResults[RowIndex] = FALSE; } } } } } } // Construct ResultList[] ResultListCount=0; for (RowIndex=1; RowIndex<DatabaseCSVRowCount; RowIndex++) { if (gbFilterResults[RowIndex] == TRUE) { ResultList[ResultListCount] = RowIndex; ResultListCount++; } } wsprintf(buffer,"Filter Results (%d of %d Found):", ResultListCount,DatabaseCSVRowCount-1); SetDlgItemText(hwndDialog,IDC_TEXT_SELECTIONS,buffer); // Construct ResultList Control db_ConstructResultListControl(); db_ConstructPlaylistControl(0); } void db_AddToPlaylist(void) { HWND hwndTreeSelections,hwndTreePlaylist; int PlaylistIndex; BOOL bAlreadyInPlayList; int ResultListIndex; hwndTreeSelections = GetDlgItem(hwndDialog, IDC_TREERESULTLIST); hwndTreePlaylist = GetDlgItem(hwndDialog, IDC_TREEPLAYLIST); // Find out which items are checked in the gbFilterResults // TreeView TreeView_GetCheckStateAll(hwndTreeSelections,bResultListCheckState); // Cycle through Result List, find what's checked and add // it to the Playlist provided that it does not already // exist in the Platlist. for (ResultListIndex=0; ResultListIndex<ResultListCount; ResultListIndex++) { if (bResultListCheckState[ResultListIndex]==TRUE) { // Potentially add this to Playlist bAlreadyInPlayList = FALSE; for (PlaylistIndex=0; PlaylistIndex<PlaylistCount; PlaylistIndex++) { if (ResultList[ResultListIndex]==Playlist[PlaylistIndex]) bAlreadyInPlayList = TRUE; } if (bAlreadyInPlayList == FALSE) { Playlist[PlaylistCount] = ResultList[ResultListIndex]; PlaylistCount++; } } } // Now we update the playlist tree view control based // on new settings of Playlist[] and PlaylistCount. db_ConstructPlaylistControl(0); db_ConstructResultListControl(); // Update icons in ResultList } void db_ConstructResultListControl(void) { HWND hwndTreeControl; TVINSERTSTRUCT tvis; int ResultListIndex,PlaylistIndex; char buffer[512]; BOOL bAlreadyInPlayList; HTREEITEM hItem; gbConstructingResultList = TRUE; hwndTreeControl = GetDlgItem(hwndDialog, IDC_TREERESULTLIST); TreeView_DeleteAllItems(hwndTreeControl); ZeroMemory(&tvis, sizeof(TVINSERTSTRUCT)); tvis.hParent = NULL; tvis.hInsertAfter = TVI_LAST; tvis.item.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_PARAM|TVIF_SELECTEDIMAGE; tvis.item.cchTextMax = 256; for (ResultListIndex=0; ResultListIndex<ResultListCount; ResultListIndex++) { // Put up an apropriate icon based on whether the // video clip is already in the Playlist bAlreadyInPlayList = FALSE; for (PlaylistIndex=0; PlaylistIndex<PlaylistCount; PlaylistIndex++) { if (ResultList[ResultListIndex]==Playlist[PlaylistIndex]) bAlreadyInPlayList = TRUE; } if (bAlreadyInPlayList) { tvis.item.iImage = 0; tvis.item.iSelectedImage = 0; } else { tvis.item.iImage = 1; tvis.item.iSelectedImage = 1; } tvis.item.lParam = (LPARAM)ResultListIndex; wsprintf(buffer,"%s, Disk %s", DatabaseCSVLine[ResultList[ResultListIndex]][(int)(ConfigTXTLine[CONFIGTXT_VIDEOINFORMATION][0]-'a')], DatabaseCSVLine[ResultList[ResultListIndex]][(int)(ConfigTXTLine[CONFIGTXT_VIDEOINFORMATION][2]-'a')] ); tvis.item.pszText = buffer; TreeView_InsertItem(hwndTreeControl, &tvis); } // Select first item hItem = TreeView_GetRoot(hwndTreeControl); TreeView_SelectItem(hwndTreeControl, hItem); gbConstructingResultList = FALSE; } void db_ConstructPlaylistControl(int SelectionIndex) { HWND hwndTreeControl,hwndControl; TVINSERTSTRUCT tvis; int ResultListIndex,PlaylistIndex; char buffer[512]; BOOL bPartOfResultList; gbConstructingPlaylist = TRUE; hwndTreeControl = GetDlgItem(hwndDialog, IDC_TREEPLAYLIST); TreeView_DeleteAllItems(hwndTreeControl); ZeroMemory(&tvis, sizeof(TVINSERTSTRUCT)); tvis.hParent = NULL; tvis.hInsertAfter = TVI_LAST; tvis.item.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_PARAM|TVIF_SELECTEDIMAGE; tvis.item.cchTextMax = 256; for (PlaylistIndex=0; PlaylistIndex<PlaylistCount; PlaylistIndex++) { // Put up an apropriate icon based on whether the // video clip is part of the ResultList bPartOfResultList = FALSE; for (ResultListIndex=0; ResultListIndex<ResultListCount; ResultListIndex++) { if (ResultList[ResultListIndex]==Playlist[PlaylistIndex]) bPartOfResultList = TRUE; } if (bPartOfResultList) { tvis.item.iImage = 0; tvis.item.iSelectedImage = 0; } else { tvis.item.iImage = 1; tvis.item.iSelectedImage = 1; } tvis.item.lParam = (LPARAM)PlaylistIndex; wsprintf(buffer,"%s, Disk %s", DatabaseCSVLine[Playlist[PlaylistIndex]][(int)(ConfigTXTLine[CONFIGTXT_VIDEOINFORMATION][0]-'a')], DatabaseCSVLine[Playlist[PlaylistIndex]][(int)(ConfigTXTLine[CONFIGTXT_VIDEOINFORMATION][2]-'a')] ); tvis.item.pszText = buffer; TreeView_InsertItem(hwndTreeControl, &tvis); } // Now disable or enable irrelevant controls if (PlaylistCount==0) { hwndControl = GetDlgItem( hwndDialog, IDC_PRESENT ); EnableWindow(hwndControl, FALSE); hwndControl = GetDlgItem( hwndDialog, IDC_MOVEUP ); EnableWindow(hwndControl, FALSE); hwndControl = GetDlgItem( hwndDialog, IDC_MOVEDOWN ); EnableWindow(hwndControl, FALSE); hwndControl = GetDlgItem( hwndDialog, IDC_DELETE ); EnableWindow(hwndControl, FALSE); } else { hwndControl = GetDlgItem( hwndDialog, IDC_PRESENT ); EnableWindow(hwndControl, TRUE); hwndControl = GetDlgItem( hwndDialog, IDC_MOVEUP ); EnableWindow(hwndControl, TRUE); hwndControl = GetDlgItem( hwndDialog, IDC_MOVEDOWN ); EnableWindow(hwndControl, TRUE); hwndControl = GetDlgItem( hwndDialog, IDC_DELETE ); EnableWindow(hwndControl, TRUE); } // Select item TreeView_SelectItem( hwndTreeControl, TreeView_SetSelectionIndex(hwndTreeControl,SelectionIndex) ); gbConstructingPlaylist = FALSE; } void db_DeleteFromPlaylist(void) { HWND hwndTreeSelections,hwndTreePlaylist; int PlaylistIndex,PlaylistIndex2; hwndTreeSelections = GetDlgItem(hwndDialog, IDC_TREERESULTLIST); hwndTreePlaylist = GetDlgItem(hwndDialog, IDC_TREEPLAYLIST); // Find out which items are checked in the gbFilterResults // TreeView TreeView_GetCheckStateAll(hwndTreePlaylist,bPlaylistCheckState); // Cycle through Playist, find what's checked and add // delete it from the list for (PlaylistIndex=PlaylistCount-1; PlaylistIndex>=0; PlaylistIndex--) { if (bPlaylistCheckState[PlaylistIndex]==TRUE) { // Shrink the array by this one for (PlaylistIndex2=PlaylistIndex+1; PlaylistIndex2<PlaylistCount; PlaylistIndex2++) { Playlist[PlaylistIndex2-1] = Playlist[PlaylistIndex2]; } PlaylistCount--; } } // Now we update the playlist tree view control based // on new settings of Playlist[] and PlaylistCount. db_ConstructPlaylistControl(0); db_ConstructResultListControl(); // Update icons in ResultList } void db_UpdateEditControl(void) { HWND hwndTabControl,hwndEditControl; int LoopVar; char TmpBuffer[2]; // Get a handle on the relevant windows hwndTabControl = GetDlgItem(hwndDialog, IDC_TABTEXT); hwndEditControl = GetDlgItem(hwndDialog, IDC_EDIT); // Disable the Edit Box if no video is selected and return if (CurrentMovieIndex==0) { SetDlgItemText(hwndDialog,IDC_EDIT,""); // Change control to read only (disabled) EnableWindow(hwndEditControl,FALSE); return; } else { EnableWindow(hwndEditControl,TRUE); } // Display Edit Box contents based upon the TAB control if (TabCtrl_GetCurSel(hwndTabControl)==0) { // Video Clip Information TAB is selected // Change control to read only Edit_SetReadOnly(hwndEditControl,TRUE); // Construct the Video Clip Information string strcpy(CurrentVideoClipInfoString,""); for (LoopVar=0; LoopVar<(int)strlen(ConfigTXTLine[CONFIGTXT_TEXT_FORMAT]); LoopVar++) { if (isalpha(ConfigTXTLine[CONFIGTXT_TEXT_FORMAT][LoopVar])) { // Add a string if (islower(ConfigTXTLine[CONFIGTXT_TEXT_FORMAT][LoopVar])) { // Convert letter to index strcat(CurrentVideoClipInfoString, DatabaseCSVLine[ CurrentMovieIndex ][(int)(ConfigTXTLine[CONFIGTXT_TEXT_FORMAT][LoopVar]-'a')]); } else { // Convert letter to index strcat(CurrentVideoClipInfoString, DatabaseCSVLine[0][(int)(ConfigTXTLine[CONFIGTXT_TEXT_FORMAT][LoopVar]-'A')]); } } else if ( ConfigTXTLine[CONFIGTXT_TEXT_FORMAT][LoopVar] =='\\' || ConfigTXTLine[CONFIGTXT_TEXT_FORMAT][LoopVar] =='/' ) { // Add a new line strcat(CurrentVideoClipInfoString, "\r\n"); } else { // Add literal translation TmpBuffer[0] = ConfigTXTLine[CONFIGTXT_TEXT_FORMAT][LoopVar]; TmpBuffer[1] = 0x00; strcat(CurrentVideoClipInfoString, TmpBuffer); } } // Display the Video Clip Information string SetDlgItemText(hwndDialog,IDC_EDIT,CurrentVideoClipInfoString); } else { // Video Clip Notes TAB is selected // Change control to read and write Edit_SetReadOnly(hwndEditControl,FALSE); // Display notes, if any, in edit bos if (Notes[CurrentMovieIndex].Note != NULL) SetDlgItemText(hwndDialog,IDC_EDIT,Notes[CurrentMovieIndex].Note); else SetDlgItemText(hwndDialog,IDC_EDIT,""); } } void db_SaveCurrentNotes(void) { if (TabCtrl_GetCurSel(GetDlgItem(hwndDialog, IDC_TABTEXT))==0) return; // Kill curent note item in array if (Notes[CurrentMovieIndex].Note != NULL) { WFW_DELETE(Notes[CurrentMovieIndex].Note); Notes[CurrentMovieIndex].NoteSize = 0; } // Get data from edit box. Add one for NULL. Notes[CurrentMovieIndex].NoteSize = Edit_GetTextLength(GetDlgItem(hwndDialog,IDC_EDIT))+1; Notes[CurrentMovieIndex].Note = new char[Notes[CurrentMovieIndex].NoteSize]; if ( NULL == Notes[CurrentMovieIndex].Note ) { MessageBox(hwndMain,"Error:\n\nCan not allocate memory for Video Clip Notes!","Error",MB_OK); } GetDlgItemText(hwndDialog,IDC_EDIT,Notes[CurrentMovieIndex].Note,Notes[CurrentMovieIndex].NoteSize); } void db_MoveClipUp(void) { HTREEITEM hItem; int TempIndex,CurrentPlaylistIndex; hItem = TreeView_GetSelection(GetDlgItem(hwndDialog,IDC_TREEPLAYLIST)); CurrentPlaylistIndex = TreeView_GetSelectionIndex(GetDlgItem(hwndDialog,IDC_TREEPLAYLIST),hItem); if (CurrentPlaylistIndex==0) return; // Simply swap Playlist[CurrentPlaylistIndex-1] with // Playlist[CurrentPlaylistIndex] and reconstruct // playlist with newly moved item selected. TempIndex = Playlist[CurrentPlaylistIndex]; Playlist[CurrentPlaylistIndex] = Playlist[CurrentPlaylistIndex-1]; Playlist[CurrentPlaylistIndex-1] = TempIndex; CurrentPlaylistIndex-=1; db_ConstructPlaylistControl(CurrentPlaylistIndex); } void db_MoveClipDown(void) { HTREEITEM hItem; int TempIndex,CurrentPlaylistIndex; hItem = TreeView_GetSelection(GetDlgItem(hwndDialog,IDC_TREEPLAYLIST)); CurrentPlaylistIndex = TreeView_GetSelectionIndex(GetDlgItem(hwndDialog,IDC_TREEPLAYLIST),hItem); if (CurrentPlaylistIndex==PlaylistCount-1) return; // Simply swap Playlist[CurrentPlaylistIndex-1] with // Playlist[CurrentPlaylistIndex] and reconstruct // playlist with newly moved item selected. TempIndex = Playlist[CurrentPlaylistIndex]; Playlist[CurrentPlaylistIndex] = Playlist[CurrentPlaylistIndex+1]; Playlist[CurrentPlaylistIndex+1] = TempIndex; CurrentPlaylistIndex+=1; db_ConstructPlaylistControl(CurrentPlaylistIndex); } char * db_GetCurrentMovieFilename(void) { return DatabaseCSVLine[CurrentMovieIndex][(int)(ConfigTXTLine[CONFIGTXT_VIDEOINFORMATION][1]-'a')]; } int db_GetCurrentMovieDiskNumber(void) { return atoi(DatabaseCSVLine[CurrentMovieIndex][(int)(ConfigTXTLine[CONFIGTXT_VIDEOINFORMATION][2]-'a')]); } char * db_GetProjectName(void) { return ConfigTXTLine[CONFIGTXT_PROJECT_NAME]; } int db_PlaylistCount(void) { return PlaylistCount; } char * db_PlaylistFilename(int PlaylistIndex) { return DatabaseCSVLine[Playlist[PlaylistIndex]][(int)(ConfigTXTLine[CONFIGTXT_VIDEOINFORMATION][1]-'a')]; } int db_PlaylistDiskNumber(int PlaylistIndex) { return atoi(DatabaseCSVLine[Playlist[PlaylistIndex]][(int)(ConfigTXTLine[CONFIGTXT_VIDEOINFORMATION][2]-'a')]); } void db_DeletePlaylist(void) { int PlaylistIndex; // I don't know how important this stuff is: for (PlaylistIndex=0; PlaylistIndex<PlaylistCount; PlaylistIndex++) { Playlist[PlaylistIndex] = 0; bPlaylistCheckState[PlaylistIndex] = FALSE; } // Set count to zero PlaylistCount=0; // Now update display TreeView_DeleteAllItems(GetDlgItem(hwndDialog, IDC_TREEPLAYLIST)); EnableWindow(GetDlgItem(hwndDialog,IDC_PRESENT), FALSE); EnableWindow(GetDlgItem(hwndDialog,IDC_MOVEUP), FALSE); EnableWindow(GetDlgItem(hwndDialog,IDC_MOVEDOWN), FALSE); EnableWindow(GetDlgItem(hwndDialog,IDC_DELETE), FALSE); } void db_DeleteNotes(void) { int NoteIndex; for (NoteIndex=0; NoteIndex<DATABASECSV_MAX_ROWS; NoteIndex++) { WFW_DELETE(Notes[NoteIndex].Note); } // Now update display... Set tab to movie info... CurrentMovieIndex = 0; // Set to first TAB TabCtrl_SetCurSel(GetDlgItem(hwndDialog,IDC_TABTEXT),0); } void db_ClearFilterOptions(void) { int FilterTabIndex,UniqueEntryIndex; TCITEM tie; // Reset filter options to none for (FilterTabIndex=0; FilterTabIndex<FilterTabCount; FilterTabIndex++) { for (UniqueEntryIndex=0; UniqueEntryIndex<FilterTab[FilterTabIndex].UniqueEntryNameCount; UniqueEntryIndex++) { FilterTab[FilterTabIndex].bUniqueEntryFiltered[UniqueEntryIndex] = FALSE; } FilterTab[FilterTabIndex].bAllFiltered = TRUE; // Set Non Checked Icon On TAB tie.mask = TCIF_IMAGE; tie.iImage = 0; TabCtrl_SetItem( GetDlgItem(hwndDialog,IDC_TABFILTER), FilterTabIndex, &tie ); } // Uncheck all in current filter tree TreeView_SetCheckStateAll( GetDlgItem(hwndDialog,IDC_TREEFILTER), FilterTab[TabCtrl_GetCurSel(GetDlgItem(hwndDialog,IDC_TABFILTER))].bUniqueEntryFiltered ); // Set to first TAB TabCtrl_SetCurSel(GetDlgItem(hwndDialog,IDC_TABFILTER),0); // Update the result list db_UpdateSelections(); // Set focus to result list SetFocus(GetDlgItem(hwndDialog, IDC_TREERESULTLIST)); } void db_ExportFilterSelections(HANDLE hFile) { int FilterTabIndex; for (FilterTabIndex=0; FilterTabIndex<FilterTabCount; FilterTabIndex++) { r3d_FileWrite(hFile,&FilterTab[FilterTabIndex].bUniqueEntryFiltered,sizeof(FilterTab[FilterTabIndex].bUniqueEntryFiltered)); r3d_FileWrite(hFile,&FilterTab[FilterTabIndex].bAllFiltered,sizeof(FilterTab[FilterTabIndex].bAllFiltered)); } } void db_ExportPlaylist(HANDLE hFile) { int PlaylistIndex; r3d_FileWrite(hFile,&PlaylistCount,sizeof(PlaylistCount)); for (PlaylistIndex=0; PlaylistIndex<PlaylistCount; PlaylistIndex++) { r3d_FileWrite(hFile,&Playlist[PlaylistIndex],sizeof(Playlist[PlaylistIndex])); } } void db_ExportNotes(HANDLE hFile) { int NoteIndex; for (NoteIndex=0; NoteIndex<DATABASECSV_MAX_ROWS; NoteIndex++) { r3d_FileWrite(hFile,&Notes[NoteIndex].NoteSize,sizeof(Notes[NoteIndex].NoteSize)); if (Notes[NoteIndex].NoteSize>0) { strcpy(TempNotes,Notes[NoteIndex].Note); r3d_FileWrite(hFile,&TempNotes,Notes[NoteIndex].NoteSize); } } } void db_ImportFilterSelections(HANDLE hFile) { int FilterTabIndex; for (FilterTabIndex=0; FilterTabIndex<FilterTabCount; FilterTabIndex++) { r3d_FileRead(hFile,&FilterTab[FilterTabIndex].bUniqueEntryFiltered,sizeof(FilterTab[FilterTabIndex].bUniqueEntryFiltered)); r3d_FileRead(hFile,&FilterTab[FilterTabIndex].bAllFiltered,sizeof(FilterTab[FilterTabIndex].bAllFiltered)); } TreeView_SetCheckStateAll( GetDlgItem(hwndDialog,IDC_TREEFILTER), FilterTab[TabCtrl_GetCurSel(GetDlgItem(hwndDialog,IDC_TABFILTER))].bUniqueEntryFiltered ); } void db_ImportPlaylist(HANDLE hFile) { int PlaylistIndex; r3d_FileRead(hFile,&PlaylistCount,sizeof(PlaylistCount)); for (PlaylistIndex=0; PlaylistIndex<PlaylistCount; PlaylistIndex++) { r3d_FileRead(hFile,&Playlist[PlaylistIndex],sizeof(Playlist[PlaylistIndex])); } db_ConstructPlaylistControl(0); } void db_ImportNotes(HANDLE hFile) { int NoteIndex; for (NoteIndex=0; NoteIndex<DATABASECSV_MAX_ROWS; NoteIndex++) { WFW_DELETE(Notes[NoteIndex].Note); Notes[NoteIndex].NoteSize = 0; r3d_FileRead(hFile,&Notes[NoteIndex].NoteSize,sizeof(Notes[NoteIndex].NoteSize)); if (Notes[NoteIndex].NoteSize>0) { Notes[NoteIndex].Note = new char[Notes[NoteIndex].NoteSize]; if ( NULL == Notes[NoteIndex].Note ) { MessageBox(hwndMain,"Error:\n\nCan not allocate memory for Video Clip Notes!","Error",MB_OK); } r3d_FileRead(hFile,&TempNotes,Notes[NoteIndex].NoteSize); strcpy(Notes[NoteIndex].Note,TempNotes); } } } char * db_GetStartTime(int MovieIndex) { return DatabaseCSVLine[MovieIndex][(int)(ConfigTXTLine[CONFIGTXT_VIDEOINFORMATION][3]-'a')]; } char * db_GetEndTime(int MovieIndex) { return DatabaseCSVLine[MovieIndex][(int)(ConfigTXTLine[CONFIGTXT_VIDEOINFORMATION][4]-'a')]; } float db_GetFramesPerSecond(int MovieIndex) { return (float)atof(DatabaseCSVLine[MovieIndex][(int)(ConfigTXTLine[CONFIGTXT_VIDEOINFORMATION][5]-'a')]); } int db_GetCurrentMovieIndex(void) { return CurrentMovieIndex; } int db_GetMovieIndexFromPlaylistIndex(int PlaylistIndex) { return Playlist[PlaylistIndex]; } int db_SetMovieIndex(BOOL bUsePlaylistIndex) { if (bUsePlaylistIndex) { if (PlaylistCount==0) CurrentMovieIndex = db_InternalGetMovieIndexResultList(); else CurrentMovieIndex = db_InternalGetMovieIndexPlaylist(); } else { if (ResultListCount==0) CurrentMovieIndex = db_InternalGetMovieIndexPlaylist(); else CurrentMovieIndex = db_InternalGetMovieIndexResultList(); } // Update Status Bar and ToolBar states if (CurrentMovieIndex==0) { Status_SetText(hwndStatusBar, 2, 0, " "); ToolBar_EnableButton(hwndToolBar, IDB_PLAY_PLAY, FALSE); ToolBar_EnableButton(hwndToolBar, IDB_PLAY_PAUSE, FALSE); ToolBar_EnableButton(hwndToolBar, IDB_PLAY_STOP, FALSE); } else { Status_SetText(hwndStatusBar, 2, 0, db_GetCurrentMovieFilename()); ToolBar_EnableButton(hwndToolBar, IDB_PLAY_PLAY, TRUE); ToolBar_EnableButton(hwndToolBar, IDB_PLAY_PAUSE, TRUE); ToolBar_EnableButton(hwndToolBar, IDB_PLAY_STOP, TRUE); } // Update Edit Box db_UpdateEditControl(); return CurrentMovieIndex; } void db_DeleteAllAllocated(void) { WFW_DELETE(DatabaseCSV); WFW_DELETE(ConfigTXT); WFW_DELETE(FilterTab); } int GetAppVersion(void) { char szFullPath[_MAX_PATH]; DWORD dwVerHnd; DWORD dwVerInfoSize; int VersionNumber=100; // Assume 1.00 UINT dwBytes = 0; LPVOID lpBuffer = 0; VS_FIXEDFILEINFO *lpvsFixedFileInfo = {0}; unsigned char *VersionMemory; // Get version information from the application GetModuleFileName(hInst, szFullPath, sizeof(szFullPath)); dwVerInfoSize = GetFileVersionInfoSize(szFullPath, &dwVerHnd); if (dwVerInfoSize) { // If we were able to get the information, process it: VersionMemory = new unsigned char[dwVerInfoSize]; if ( NULL == VersionMemory ) { MessageBox(hwndMain,"Can not allocate temporary memory for version information","Error",MB_OK|MB_ICONERROR); return 100; // We return 100 for program version 1.0 } GetFileVersionInfo(szFullPath, dwVerHnd, dwVerInfoSize, VersionMemory); VerQueryValue(VersionMemory, TEXT("\\"), &lpBuffer, &dwBytes); lpvsFixedFileInfo = (VS_FIXEDFILEINFO *)lpBuffer; VersionNumber = ((lpvsFixedFileInfo->dwProductVersionMS&0xFFFF0000)>>16); WFW_DELETE(VersionMemory); } return VersionNumber; }