From 1b10910af6b8bec0a5900478119d8e8541bb2e5b Mon Sep 17 00:00:00 2001 From: frosch Date: Mon, 18 Feb 2013 19:30:24 +0000 Subject: (svn r25024) -Feature: Searching of (missing) content via GrfCrawler. --- src/lang/english.txt | 4 ++ src/network/network_content_gui.cpp | 100 +++++++++++++++++++++++++++++---- src/script/api/game/game_window.hpp.sq | 1 + src/script/api/script_window.hpp | 1 + src/widgets/network_content_widget.h | 1 + 5 files changed, 96 insertions(+), 11 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 2417042fc..41ce608a1 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2080,6 +2080,10 @@ STR_CONTENT_SELECT_UPDATES_CAPTION :{BLACK}Select u STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP :{BLACK}Mark all content that is an upgrade for existing content to be downloaded STR_CONTENT_UNSELECT_ALL_CAPTION :{BLACK}Unselect all STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP :{BLACK}Mark all content to be not downloaded +STR_CONTENT_SEARCH_EXTERNAL :{BLACK}Search external websites +STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP :{BLACK}Search content not available on OpenTTD's content service on websites not associated to OpenTTD +STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION :{WHITE}You are leaving OpenTTD! +STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER :{WHITE}The terms and conditions for downloading content from external websites vary.{}You will have to refer to the external sites for instructions how to install the content into OpenTTD.{}Do you want to continue? STR_CONTENT_FILTER_TITLE :{BLACK}Tag/name filter: STR_CONTENT_OPEN_URL :{BLACK}Visit website STR_CONTENT_OPEN_URL_TOOLTIP :{BLACK}Visit the website for this content diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index 54ebcfef0..3c387c2d0 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -29,6 +29,11 @@ #include "table/strings.h" #include "../table/sprites.h" + +/** Whether the user accepted to enter external websites during this session. */ +static bool _accepted_external_search = false; + + /** Window for displaying the textfile of an item in the content list. */ struct ContentTextfileWindow : public TextfileWindow { const ContentInfo *ci; ///< View the textfile of this ContentInfo. @@ -296,6 +301,63 @@ class NetworkContentListWindow : public Window, ContentCallback { uint filesize_sum; ///< The sum of all selected file sizes Scrollbar *vscroll; ///< Cache of the vertical scrollbar + /** Search external websites for content */ + void OpenExternalSearch() + { + extern void OpenBrowser(const char *url); + + char url[1024]; + const char *last = lastof(url); + + char *pos = strecpy(url, "http://grfsearch.openttd.org/?", last); + + if (this->auto_select) { + pos = strecpy(pos, "do=searchgrfid&q=", last); + + bool first = true; + for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) { + const ContentInfo *ci = *iter; + if (ci->state != ContentInfo::DOES_NOT_EXIST) continue; + + if (!first) pos = strecpy(pos, ",", last); + first = false; + + pos += seprintf(pos, last, "%08X", ci->unique_id); + pos = strecpy(pos, ":", last); + pos = md5sumToString(pos, last, ci->md5sum); + } + } else { + pos = strecpy(pos, "do=searchtext&q=", last); + + /* Escape search term */ + for (const char *search = this->filter_editbox.text.buf; *search != '\0'; search++) { + /* Remove quotes */ + if (*search == '\'' || *search == '"') continue; + + /* Escape special chars, such as &%,= */ + if (*search < 0x30) { + pos += seprintf(pos, last, "%%%02X", *search); + } else if (pos < last) { + *pos = *search; + *++pos = '\0'; + } + } + } + + OpenBrowser(url); + } + + /** + * Callback function for disclaimer about entering external websites. + */ + static void ExternalSearchDisclaimerCallback(Window *w, bool accepted) + { + if (accepted) { + _accepted_external_search = true; + ((NetworkContentListWindow*)w)->OpenExternalSearch(); + } + } + /** * (Re)build the network game list as its amount has changed because * an item has been added or deleted for example @@ -307,10 +369,15 @@ class NetworkContentListWindow : public Window, ContentCallback { /* Create temporary array of games to use for listing */ this->content.Clear(); + bool all_available = true; + for (ConstContentIterator iter = _network_content_client.Begin(); iter != _network_content_client.End(); iter++) { + if ((*iter)->state == ContentInfo::DOES_NOT_EXIST) all_available = false; *this->content.Append() = *iter; } + this->SetWidgetDisabledState(WID_NCL_SEARCH_EXTERNAL, this->auto_select && all_available); + this->FilterContentList(); this->content.Compact(); this->content.RebuildDone(); @@ -421,6 +488,7 @@ public: this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR; this->filter_editbox.afilter = CS_ALPHANUMERAL; this->SetFocusedWidget(WID_NCL_FILTER); + this->SetWidgetDisabledState(WID_NCL_SEARCH_EXTERNAL, this->auto_select); _network_content_client.AddCallback(this); this->content.SetListing(this->last_sorting); @@ -721,6 +789,14 @@ public: case WID_NCL_DOWNLOAD: if (BringWindowToFrontById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD) == NULL) new NetworkContentDownloadStatusWindow(); break; + + case WID_NCL_SEARCH_EXTERNAL: + if (_accepted_external_search) { + this->OpenExternalSearch(); + } else { + ShowQuery(STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION, STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER, this, ExternalSearchDisclaimerCallback); + } + break; } } @@ -896,7 +972,7 @@ static const NWidgetPart _nested_network_content_list_widgets[] = { NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8), /* Left side. */ - NWidget(NWID_VERTICAL), + NWidget(NWID_VERTICAL), SetPIP(0, 4, 0), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), @@ -910,6 +986,16 @@ static const NWidgetPart _nested_network_content_list_widgets[] = { EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NCL_SCROLLBAR), EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, 8, 0), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NCL_SEL_ALL_UPDATE), SetResize(1, 0), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_UPDATE), SetResize(1, 0), SetFill(1, 0), + SetDataTip(STR_CONTENT_SELECT_UPDATES_CAPTION, STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_ALL), SetResize(1, 0), SetFill(1, 0), + SetDataTip(STR_CONTENT_SELECT_ALL_CAPTION, STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP), + EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_UNSELECT), SetResize(1, 0), SetFill(1, 0), + SetDataTip(STR_CONTENT_UNSELECT_ALL_CAPTION, STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP), + EndContainer(), EndContainer(), /* Right side. */ NWidget(NWID_VERTICAL), SetPIP(0, 4, 0), @@ -927,16 +1013,8 @@ static const NWidgetPart _nested_network_content_list_widgets[] = { NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0), /* Bottom. */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, 8, 0), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NCL_SEL_ALL_UPDATE), SetResize(1, 0), SetFill(1, 0), - NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_UPDATE), SetResize(1, 0), SetFill(1, 0), - SetDataTip(STR_CONTENT_SELECT_UPDATES_CAPTION, STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_ALL), SetResize(1, 0), SetFill(1, 0), - SetDataTip(STR_CONTENT_SELECT_ALL_CAPTION, STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP), - EndContainer(), - NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_UNSELECT), SetResize(1, 0), SetFill(1, 0), - SetDataTip(STR_CONTENT_UNSELECT_ALL_CAPTION, STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP), - EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SEARCH_EXTERNAL), SetResize(1, 0), SetFill(1, 0), + SetDataTip(STR_CONTENT_SEARCH_EXTERNAL, STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, 8, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), diff --git a/src/script/api/game/game_window.hpp.sq b/src/script/api/game/game_window.hpp.sq index 11a930383..057af86ed 100644 --- a/src/script/api/game/game_window.hpp.sq +++ b/src/script/api/game/game_window.hpp.sq @@ -655,6 +655,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_CANCEL, "WID_NCL_CANCEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_DOWNLOAD, "WID_NCL_DOWNLOAD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SEL_ALL_UPDATE, "WID_NCL_SEL_ALL_UPDATE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SEARCH_EXTERNAL, "WID_NCL_SEARCH_EXTERNAL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MAIN, "WID_NG_MAIN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CONNECTION, "WID_NG_CONNECTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CONN_BTN, "WID_NG_CONN_BTN"); diff --git a/src/script/api/script_window.hpp b/src/script/api/script_window.hpp index 5500f53fc..a59013b36 100644 --- a/src/script/api/script_window.hpp +++ b/src/script/api/script_window.hpp @@ -1611,6 +1611,7 @@ public: WID_NCL_DOWNLOAD = ::WID_NCL_DOWNLOAD, ///< 'Download' button. WID_NCL_SEL_ALL_UPDATE = ::WID_NCL_SEL_ALL_UPDATE, ///< #NWID_SELECTION widget for select all/update buttons.. + WID_NCL_SEARCH_EXTERNAL = ::WID_NCL_SEARCH_EXTERNAL, ///< Search external sites for missing NewGRF. }; /* automatically generated from ../../widgets/network_widget.h */ diff --git a/src/widgets/network_content_widget.h b/src/widgets/network_content_widget.h index d90afb3d4..e659743d4 100644 --- a/src/widgets/network_content_widget.h +++ b/src/widgets/network_content_widget.h @@ -45,6 +45,7 @@ enum NetworkContentListWidgets { WID_NCL_DOWNLOAD, ///< 'Download' button. WID_NCL_SEL_ALL_UPDATE, ///< #NWID_SELECTION widget for select all/update buttons.. + WID_NCL_SEARCH_EXTERNAL, ///< Search external sites for missing NewGRF. }; #endif /* WIDGETS_NETWORK_CONTENT_WIDGET_H */ -- cgit v1.2.3-54-g00ecf