diff --git a/browserevents.c b/browserevents.c index 308e9b7..74bb679 100644 --- a/browserevents.c +++ b/browserevents.c @@ -84,14 +84,7 @@ static void HandleEvent(int eventCode, WmTaskRec *taskRec) { case wInControl: switch (taskRec->wmTaskData4) { case searchButton: - DoSearch(); - break; - - case forIIGSRadio: - gsDisksOnly = true; - break; - case forAnyAppleIIRadio: - gsDisksOnly = false; + DoSearch(false); break; case mountDiskButton: diff --git a/browserwindow.c b/browserwindow.c index 6dc6659..39fbfa9 100644 --- a/browserwindow.c +++ b/browserwindow.c @@ -23,11 +23,15 @@ #include "browserwindow.h" #include "diskbrowser.h" #include "browserevents.h" +#include "disksearch.h" /* Rectangles outlining the buttons in the style of "default" buttons */ static Rect searchRect = {8, 305, 26, 414}; static Rect mountRect = {150, 301, 168, 414}; +static char showMoreString[] = "\pShow More"; +static char mountDiskString[] = "\pMount Disk"; + /* Has the resource file been opened? (True while window is displayed.) */ static Boolean resourceFileOpened; @@ -48,6 +52,9 @@ static CtlRecHndl searchButtonHandle; /* Target control ID last time we checked */ static unsigned long lastTargetCtlID = 0; +/* Is "More Results" selected in the disk list? */ +static boolean moreResultsSelected = false; + static void DrawContents(void); static void DrawButtonOutlines(boolean justChanged); @@ -109,7 +116,17 @@ void ShowBrowserWindow(void) { wantToOpenWindow = 0; + moreResultsSelected = false; + InitEventState(); + + diskList = malloc(DISK_LIST_MAX_LENGTH * sizeof(*diskList)); + if (diskList == NULL) { + CloseWindow(window); + windowOpened = false; + window = NULL; + goto cleanup; + } cleanup: if (resourceFileOpened && !windowOpened) { @@ -127,20 +144,16 @@ void CloseBrowserWindow(void) { CloseWindow(window); windowOpened = false; window = NULL; - - /* reset state */ - gsDisksOnly = true; } if (resourceFileOpened) { CloseResourceFile(resourceFileID); resourceFileOpened = false; } + + free(diskList); - if (json) { - json_value_free(json); - json = NULL; - } + FreeJSON(); } #pragma databank 0 @@ -202,7 +215,23 @@ void UpdateControlState(void) { } /* Only allow "Mount Disk" to be clicked if there is a disk selected */ - if (NextMember2(0, (Handle)disksListHandle) != 0) { + int currentSelection = NextMember2(0, (Handle)disksListHandle); + if (currentSelection != 0) { + if (diskList[currentSelection-1].memPtr == moreResultsString) { + if (!moreResultsSelected) { + SetCtlMoreFlags(GetCtlMoreFlags(mountButtonHandle) & 0xFFFC, + mountButtonHandle); + SetCtlTitle(showMoreString, (Handle)mountButtonHandle); + moreResultsSelected = true; + } + } else { + if (moreResultsSelected) { + SetCtlMoreFlags(GetCtlMoreFlags(mountButtonHandle) & 0xFFFC, + mountButtonHandle); + SetCtlTitle(mountDiskString, (Handle)mountButtonHandle); + moreResultsSelected = false; + } + } HiliteControl(noHilite, mountButtonHandle); } else { HiliteControl(inactiveHilite, mountButtonHandle); diff --git a/diskbrowser.c b/diskbrowser.c index daed6b6..3648603 100644 --- a/diskbrowser.c +++ b/diskbrowser.c @@ -27,24 +27,24 @@ GrafPortPtr window; /* Is the window open? */ Boolean windowOpened; -/* User preference: IIGS disks or all Apple II disks? */ -boolean gsDisksOnly = true; - /* Disks list control */ CtlRecHndl disksListHandle; /* List of disks, used for list control & mounting disks */ -struct diskListEntry diskList[DISK_LIST_LENGTH]; +struct diskListEntry *diskList; /* Do we want to open a window with disk contents? Counts down until ready. */ int wantToOpenWindow = 0; /* JSON for current disk list (needs to be kept in memory while it's shown) */ -json_value *json = NULL; +json_value *json[MAX_PAGES]; /* User ID of this program */ Word myUserID; +/* String for "More Results" (used to identify that list entry) */ +char moreResultsString[] = " "; + /***/ static char menuTitle[] = "\pArchive.org Disk Browser\xC9"; diff --git a/diskbrowser.h b/diskbrowser.h index fdf8e33..428baaa 100644 --- a/diskbrowser.h +++ b/diskbrowser.h @@ -22,15 +22,9 @@ extern GrafPortPtr window; /* Is the window open? */ extern Boolean windowOpened; -/* User preference: IIGS disks or all Apple II disks? */ -extern boolean gsDisksOnly; - /* Disks list control */ extern CtlRecHndl disksListHandle; -/* Length of disks list */ -#define DISK_LIST_LENGTH 30 - struct diskListEntry { char *memPtr; Byte memFlag; @@ -38,14 +32,25 @@ struct diskListEntry { char *extPtr; }; +/* Maximum number of entries in list */ +#define DISK_LIST_MAX_LENGTH (int)(0xFFFF/sizeof(struct diskListEntry)) + +/* How many results to fetch at a time */ +#define PAGE_SIZE 30 + +#define MAX_PAGES ((DISK_LIST_MAX_LENGTH + PAGE_SIZE - 1) / PAGE_SIZE) + /* List of disks, used for list control & mounting disks */ -extern struct diskListEntry diskList[DISK_LIST_LENGTH]; +extern struct diskListEntry *diskList; + +/* String for "More Results" (used to identify that list entry) */ +extern char moreResultsString[]; /* Do we want to open a window with disk contents? Counts down until ready. */ extern int wantToOpenWindow; /* JSON for current disk list (needs to be kept in memory while it's shown) */ -extern json_value *json; +extern json_value *json[MAX_PAGES]; /* User ID of this program */ extern Word myUserID; diff --git a/diskbrowser.rez b/diskbrowser.rez index d9828d7..34e1e22 100644 --- a/diskbrowser.rez +++ b/diskbrowser.rez @@ -123,14 +123,14 @@ resource rPString (forAnyAppleIIRadio) {"Any Apple II"}; resource rControlTemplate (disksList) { disksList, /* control ID */ - {45, 10, 147, 410}, /* control rect */ + {45, 10, 147, 386}, /* control rect */ ListControl {{ - $0007, /* flags */ + $0000, /* flags */ $1400, /* more flags */ 0, /* refcon */ 0, /* list size */ 10, /* List View */ - $0000, /* List Type */ + $0003, /* List Type */ 0, /* List Start */ 10, /* ListMemHeight */ 13, /* List Mem Size */ diff --git a/diskmount.c b/diskmount.c index e67396c..ecd36ea 100644 --- a/diskmount.c +++ b/diskmount.c @@ -24,6 +24,7 @@ #include "diskbrowser.h" #include "diskmount.h" #include "browserutil.h" +#include "disksearch.h" /* Item ID and file extension for the disk image we want to open */ static char *wantedExt; @@ -50,6 +51,11 @@ void DoMount(void) { } itemNumber--; + if (diskList[itemNumber].memPtr == moreResultsString) { + DoSearch(true); + return; + } + if (diskList[itemNumber].idPtr == NULL) { result = 2; goto errorReturn; diff --git a/disksearch.c b/disksearch.c index 16130c7..6231607 100644 --- a/disksearch.c +++ b/disksearch.c @@ -8,8 +8,10 @@ #include #include +#include #include #include +#include #include #include @@ -24,22 +26,47 @@ #include "disksearch.h" #include "browserutil.h" -/* Current position in disk list */ -static int diskListPos = 0; +/* Rectangle of the disk list control */ +static Rect diskListRect = {45, 10, 147, 386}; + +/* Current length in disk list */ +static int diskListLength = 0; + +/* Number of current page of results from server */ +int pageNum; static boolean processDoc(json_value *docObj); static char *EncodeQueryString(char *queryString); +struct diskListEntry moreResultsEntry = {moreResultsString , 0, "", ""}; + +static void InsertDiskListEntry(struct diskListEntry *entry); + /* Do a search */ -void DoSearch(void) { +void DoSearch(boolean getMore) { static char queryBuf[257]; + static boolean gsDisksOnly = true; /* User preference: IIGS disks only? */ char *searchURL = NULL; enum NetDiskError result = 0; + int initialDiskListLength = diskListLength; + WaitCursor(); - GetLETextByID(window, searchLine, (StringPtr)&queryBuf); + if (!getMore) { + FreeJSON(); + GetLETextByID(window, searchLine, (StringPtr)&queryBuf); + gsDisksOnly = (FindRadioButton(window, 2) == 0); + pageNum = 0; + } else { + if (pageNum >= MAX_PAGES - 1) { + InitCursor(); + SysBeep(); + return; + } + pageNum++; + } char *queryString = EncodeQueryString(queryBuf+1); if (queryString == NULL) { @@ -56,8 +83,8 @@ void DoSearch(void) { "&rows=%i&page=%i&output=json", gsDisksOnly ? "apple2gs" : "apple2%2A", queryString, - DISK_LIST_LENGTH, - /*pageNum*/ 0); + PAGE_SIZE, + pageNum + 1); if (searchURL == NULL) { result = URL_TOO_LONG; goto errorReturn; @@ -65,19 +92,25 @@ void DoSearch(void) { free(queryString); queryString = NULL; - if (json) - json_value_free(json); - result = ReadJSONFromURL(searchURL, &json); + if (!getMore) { + FreeJSON(); + } + result = ReadJSONFromURL(searchURL, &json[pageNum]); if (result != OPERATION_SUCCESSFUL) goto errorReturn; - json_value *response = findEntryInObject(json, "response", json_object); + json_value *response = + findEntryInObject(json[pageNum], "response", json_object); if (response == NULL) { result = NOT_EXPECTED_CONTENTS; goto errorReturn; } - diskListPos = 0; + if (!getMore) { + diskListLength = 0; + } else { + diskListLength--; + } json_value *docs = findEntryInObject(response, "docs", json_array); if (docs == NULL) { result = NOT_EXPECTED_CONTENTS; @@ -85,9 +118,14 @@ void DoSearch(void) { } processArray(docs, json_object, processDoc); - diskList[0].memFlag = 0x80; - for (int i = 1; i < DISK_LIST_LENGTH; i++) { - diskList[i].memFlag = 0; + if (!getMore) { + diskList[0].memFlag = 0x80; + } + + json_value *numFoundValue = + findEntryInObject(response, "numFound", json_integer); + if (numFoundValue != NULL && numFoundValue->u.integer > diskListLength) { + InsertDiskListEntry(&moreResultsEntry); } /* Update state of controls once disk list is available */ @@ -97,9 +135,16 @@ void DoSearch(void) { disksListHandle); NewList2(NULL, 1, (Ref) diskList, refIsPointer, - diskListPos, (Handle)disksListHandle); + diskListLength, (Handle)disksListHandle); - if (diskListPos > 0) { + if (getMore) { + if (diskListLength >= initialDiskListLength) { + SelectMember2(initialDiskListLength, (Handle)disksListHandle); + ValidRect(&diskListRect); + } + } + + if (diskListLength > 0) { if (FindTargetCtl() != disksListHandle) { MakeThisCtlTarget(disksListHandle); CallCtlDefProc(disksListHandle, ctlChangeTarget, 0); @@ -119,7 +164,7 @@ errorReturn: } static boolean processDoc(json_value *docObj) { - if (diskListPos >= DISK_LIST_LENGTH) + if (diskListLength >= DISK_LIST_MAX_LENGTH) return false; if (docObj == NULL || docObj->type != json_object) @@ -129,10 +174,11 @@ static boolean processDoc(json_value *docObj) { json_value *ext = findEntryInObject(docObj, "emulator_ext", json_string); if (id == NULL || title == NULL || ext == NULL) return true; - diskList[diskListPos].idPtr = id->u.string.ptr; + diskList[diskListLength].idPtr = id->u.string.ptr; // TODO character set translation - diskList[diskListPos].memPtr = title->u.string.ptr; - diskList[diskListPos++].extPtr = ext->u.string.ptr; + diskList[diskListLength].memPtr = title->u.string.ptr; + diskList[diskListLength].extPtr = ext->u.string.ptr; + diskList[diskListLength++].memFlag = 0; return true; } @@ -164,3 +210,20 @@ static char *EncodeQueryString(char *queryString) { *s = '\0'; return encodedStr; } + +static void InsertDiskListEntry(struct diskListEntry *entry) { + if (diskListLength >= DISK_LIST_MAX_LENGTH) + return; + + diskList[diskListLength++] = *entry; +} + +void FreeJSON(void) { + for (int i = 0; i < MAX_PAGES; i++) { + if (json[i] != NULL) { + json_value_free(json[i]); + json[i] = NULL; + } + } +} + diff --git a/disksearch.h b/disksearch.h index 7c31fab..7fa1d33 100644 --- a/disksearch.h +++ b/disksearch.h @@ -1,6 +1,7 @@ #ifndef DISKSEARCH_H #define DISKSEARCH_H -void DoSearch(void); +void DoSearch(boolean getMore); +void FreeJSON(void); #endif