diff --git a/src/ai/ai.hpp b/src/ai/ai.hpp --- a/src/ai/ai.hpp +++ b/src/ai/ai.hpp @@ -14,6 +14,7 @@ #include "../script/api/script_event_types.hpp" #include "../core/string_compare_type.hpp" +#include "ai_scanner.hpp" #include /** A list that maps AI names to their AIInfo object. */ @@ -140,6 +141,12 @@ * found it is removed from the config. */ static void Rescan(); + + /** Gets the ScriptScanner instance that is used to find AIs */ + static AIScannerInfo *GetScannerInfo(); + /** Gets the ScriptScanner instance that is used to find AI Libraries */ + static AIScannerLibrary *GetScannerLibrary(); + #if defined(ENABLE_NETWORK) /** Wrapper function for AIScanner::HasAI */ static bool HasAI(const struct ContentInfo *ci, bool md5sum); diff --git a/src/ai/ai_core.cpp b/src/ai/ai_core.cpp --- a/src/ai/ai_core.cpp +++ b/src/ai/ai_core.cpp @@ -352,3 +352,13 @@ } #endif /* defined(ENABLE_NETWORK) */ + +/* static */ AIScannerInfo *AI::GetScannerInfo() +{ + return AI::scanner_info; +} +/* static */ AIScannerLibrary *AI::GetScannerLibrary() +{ + return AI::scanner_library; +} + diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -646,8 +646,6 @@ ScriptTextfileWindow(TextfileType file_type, CompanyID slot) : TextfileWindow(file_type), slot(slot) { - this->GetWidget(WID_TF_CAPTION)->SetDataTip(STR_TEXTFILE_README_CAPTION + file_type, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS); - const char *textfile = GetConfig(slot)->GetTextfile(file_type, slot); this->LoadTextfile(textfile, (slot == OWNER_DEITY) ? GAME_DIR : AI_DIR); } diff --git a/src/base_media_base.h b/src/base_media_base.h --- a/src/base_media_base.h +++ b/src/base_media_base.h @@ -201,6 +201,8 @@ return num + fs.Scan(GetExtension(), BASESET_DIR, Tbase_set::SEARCH_IN_TARS); } + static Tbase_set *GetAvailableSets(); + static bool SetSet(const char *name); static char *GetSetsList(char *p, const char *last); static int GetNumSets(); @@ -217,6 +219,15 @@ static bool HasSet(const ContentInfo *ci, bool md5sum); }; +/** + * Check whether there's a base set matching some information. + * @param ci The content info to compare it to. + * @param md5sum Should the MD5 checksum be tested as well? + * @param s The list with sets. + * @return The filename of the first file of the base set, or \c NULL if there is no match. + */ +template +const char *HasBaseSet(const ContentInfo *ci, bool md5sum, const Tbase_set *s); /** Types of graphics in the base graphics set */ enum GraphicsFileType { diff --git a/src/base_media_func.h b/src/base_media_func.h --- a/src/base_media_func.h +++ b/src/base_media_func.h @@ -7,7 +7,10 @@ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . */ -/** @file base_media_func.h Generic function implementations for base data (graphics, sounds). */ +/** + * @file base_media_func.h Generic function implementations for base data (graphics, sounds). + * @note You should _never_ include this file due to the SET_TYPE define. + */ #include "base_media_base.h" #include "debug.h" @@ -274,19 +277,13 @@ #if defined(ENABLE_NETWORK) #include "network/network_content.h" -/** - * Check whether there's a base set matching some information. - * @param ci The content info to compare it to. - * @param md5sum Should the MD5 checksum be tested as well? - * @param s The list with sets. - */ -template bool HasBaseSet(const ContentInfo *ci, bool md5sum, const Tbase_set *s) +template const char *HasBaseSet(const ContentInfo *ci, bool md5sum, const Tbase_set *s) { for (; s != NULL; s = s->next) { if (s->GetNumMissing() != 0) continue; if (s->shortname != ci->unique_id) continue; - if (!md5sum) return true; + if (!md5sum) return s->files[0].filename; byte md5[16]; memset(md5, 0, sizeof(md5)); @@ -295,22 +292,27 @@ md5[j] ^= s->files[i].hash[j]; } } - if (memcmp(md5, ci->md5sum, sizeof(md5)) == 0) return true; + if (memcmp(md5, ci->md5sum, sizeof(md5)) == 0) return s->files[0].filename; } - - return false; + return NULL; } template /* static */ bool BaseMedia::HasSet(const ContentInfo *ci, bool md5sum) { - return HasBaseSet(ci, md5sum, BaseMedia::available_sets) || - HasBaseSet(ci, md5sum, BaseMedia::duplicate_sets); + return (HasBaseSet(ci, md5sum, BaseMedia::available_sets) != NULL) || + (HasBaseSet(ci, md5sum, BaseMedia::duplicate_sets) != NULL); } #else template +const char *HasBaseSet(const ContentInfo *ci, bool md5sum, const Tbase_set *s) +{ + return NULL; +} + +template /* static */ bool BaseMedia::HasSet(const ContentInfo *ci, bool md5sum) { return false; @@ -375,6 +377,16 @@ } /** + * Return the available sets. + * @return The available sets. + */ +template +/* static */ Tbase_set *BaseMedia::GetAvailableSets() +{ + return BaseMedia::available_sets; +} + +/** * Force instantiation of methods so we don't get linker errors. * @param repl_type the type of the BaseMedia to instantiate * @param set_type the type of the BaseSet to instantiate @@ -390,5 +402,6 @@ template int repl_type::GetIndexOfUsedSet(); \ template const set_type *repl_type::GetSet(int index); \ template const set_type *repl_type::GetUsedSet(); \ - template bool repl_type::DetermineBestSet(); + template bool repl_type::DetermineBestSet(); \ + template set_type *repl_type::GetAvailableSets(); diff --git a/src/fios.cpp b/src/fios.cpp --- a/src/fios.cpp +++ b/src/fios.cpp @@ -561,8 +561,9 @@ /** Basic data to distinguish a scenario. Used in the server list window */ struct ScenarioIdentifier { - uint32 scenid; ///< ID for the scenario (generated by content) - uint8 md5sum[16]; ///< MD5 checksum of file + uint32 scenid; ///< ID for the scenario (generated by content). + uint8 md5sum[16]; ///< MD5 checksum of file. + char filename[MAX_PATH]; ///< filename of the file. bool operator == (const ScenarioIdentifier &other) const { @@ -606,6 +607,7 @@ int fret = fscanf(f, "%i", &id.scenid); FioFCloseFile(f); if (fret != 1) return false; + strecpy(id.filename, filename, lastof(id.filename)); Md5 checksum; uint8 buffer[1024]; @@ -638,24 +640,34 @@ static ScenarioScanner _scanner; /** - * Check whether we've got a given scenario based on its unique ID. - * @param ci the content info to compare it to - * @param md5sum whether to look at the md5sum or the id - * @return true if we've got the scenario + * Find a given scenario based on its unique ID. + * @param ci The content info to compare it to. + * @param md5sum Whether to look at the md5sum or the id. + * @return The filename of the file, else \c NULL. */ -bool HasScenario(const ContentInfo *ci, bool md5sum) +const char *FindScenario(const ContentInfo *ci, bool md5sum) { _scanner.Scan(false); for (ScenarioIdentifier *id = _scanner.Begin(); id != _scanner.End(); id++) { - if (md5sum ? - (memcmp(id->md5sum, ci->md5sum, sizeof(id->md5sum)) == 0) : - (id->scenid == ci->unique_id)) { - return true; + if (md5sum ? (memcmp(id->md5sum, ci->md5sum, sizeof(id->md5sum)) == 0) + : (id->scenid == ci->unique_id)) { + return id->filename; } } - return false; + return NULL; +} + +/** + * Check whether we've got a given scenario based on its unique ID. + * @param ci The content info to compare it to. + * @param md5sum Whether to look at the md5sum or the id. + * @return True iff we've got the scenario. + */ +bool HasScenario(const ContentInfo *ci, bool md5sum) +{ + return (FindScenario(ci, md5sum) != NULL); } /** diff --git a/src/fios.h b/src/fios.h --- a/src/fios.h +++ b/src/fios.h @@ -15,6 +15,7 @@ #include "gfx_type.h" #include "company_base.h" #include "newgrf_config.h" +#include "network/core/tcp_content.h" typedef SmallMap CompanyPropertiesMap; @@ -180,4 +181,6 @@ void BuildFileList(); void SetFiosType(const byte fiostype); +const char *FindScenario(const ContentInfo *ci, bool md5sum); + #endif /* FIOS_H */ diff --git a/src/game/game.hpp b/src/game/game.hpp --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -13,6 +13,7 @@ #define GAME_HPP #include "../core/string_compare_type.hpp" +#include "game_scanner.hpp" #include /** A list that maps AI names to their AIInfo object. */ @@ -101,6 +102,10 @@ static bool HasGame(const struct ContentInfo *ci, bool md5sum); static bool HasGameLibrary(const ContentInfo *ci, bool md5sum); #endif + /** Gets the ScriptScanner instance that is used to find Game scripts */ + static GameScannerInfo *GetScannerInfo(); + /** Gets the ScriptScanner instance that is used to find Game Libraries */ + static GameScannerLibrary *GetScannerLibrary(); private: static uint frame_counter; ///< Tick counter for the Game code. diff --git a/src/game/game_core.cpp b/src/game/game_core.cpp --- a/src/game/game_core.cpp +++ b/src/game/game_core.cpp @@ -253,3 +253,12 @@ } #endif /* defined(ENABLE_NETWORK) */ + +/* static */ GameScannerInfo *Game::GetScannerInfo() +{ + return Game::scanner_info; +} +/* static */ GameScannerLibrary *Game::GetScannerLibrary() +{ + return Game::scanner_library; +} diff --git a/src/network/core/tcp_content.cpp b/src/network/core/tcp_content.cpp --- a/src/network/core/tcp_content.cpp +++ b/src/network/core/tcp_content.cpp @@ -14,6 +14,13 @@ #ifdef ENABLE_NETWORK #include "../../stdafx.h" +#include "../../textfile_gui.h" +#include "../../fileio_func.h" +#include "../../newgrf_config.h" +#include "../../base_media_base.h" +#include "../../ai/ai.hpp" +#include "../../game/game.hpp" +#include "../../fios.h" #include "tcp_content.h" /** Clear everything in the struct */ @@ -86,6 +93,48 @@ return this->state < ContentInfo::INVALID && this->type >= CONTENT_TYPE_BEGIN && this->type < CONTENT_TYPE_END; } +/** + * Search a textfile file next to this file in the content list. + * @param type The type of the textfile to search for. + * @return The filename for the textfile, \c NULL otherwise. + */ +const char *ContentInfo::GetTextfile(TextfileType type) const +{ + char filepath[MAX_PATH]; + switch (this->type) { + default: NOT_REACHED(); + case CONTENT_TYPE_AI: + strecpy(filepath, AI::GetScannerInfo()->FindScript(this, (this->md5sum != NULL)), lastof(filepath)); + break; + case CONTENT_TYPE_AI_LIBRARY: + strecpy(filepath, AI::GetScannerLibrary()->FindScript(this, (this->md5sum != NULL)), lastof(filepath)); + break; + case CONTENT_TYPE_GAME: + strecpy(filepath, Game::GetScannerInfo()->FindScript(this, (this->md5sum != NULL)), lastof(filepath)); + break; + case CONTENT_TYPE_GAME_LIBRARY: + strecpy(filepath, Game::GetScannerLibrary()->FindScript(this, (this->md5sum != NULL)), lastof(filepath)); + break; + case CONTENT_TYPE_NEWGRF: + strecpy(filepath, FindGRFConfig(BSWAP32(this->unique_id), this->md5sum != NULL ? FGCM_EXACT : FGCM_ANY, this->md5sum != NULL ? this->md5sum : NULL)->filename, lastof(filepath)); + break; + case CONTENT_TYPE_BASE_GRAPHICS: + strecpy(filepath, HasBaseSet(this, (this->md5sum != NULL), BaseGraphics::GetAvailableSets()), lastof(filepath)); + break; + case CONTENT_TYPE_BASE_SOUNDS: + strecpy(filepath, HasBaseSet(this, (this->md5sum != NULL), BaseSounds::GetAvailableSets()), lastof(filepath)); + break; + case CONTENT_TYPE_BASE_MUSIC: + strecpy(filepath, HasBaseSet(this, (this->md5sum != NULL), BaseMusic::GetAvailableSets()), lastof(filepath)); + break; + case CONTENT_TYPE_SCENARIO: + case CONTENT_TYPE_HEIGHTMAP: + strecpy(filepath, FindScenario(this, (this->md5sum != NULL)), lastof(filepath)); + break; + } + return ::GetTextfile(type, GetContentInfoSubDir(this->type), filepath); +} + void NetworkContentSocketHandler::Close() { CloseConnection(); @@ -163,4 +212,30 @@ bool NetworkContentSocketHandler::Receive_CLIENT_CONTENT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_CONTENT); } bool NetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_SERVER_CONTENT); } +/** + * Helper to get the subdirectory a #ContentInfo is located in. + * @param type The type of content. + * @return The subdirectory the content is located in. + */ +Subdirectory GetContentInfoSubDir(ContentType type) +{ + switch (type) { + default: return NO_DIRECTORY; + case CONTENT_TYPE_AI: return AI_DIR; + case CONTENT_TYPE_AI_LIBRARY: return AI_LIBRARY_DIR; + case CONTENT_TYPE_GAME: return GAME_DIR; + case CONTENT_TYPE_GAME_LIBRARY: return GAME_LIBRARY_DIR; + case CONTENT_TYPE_NEWGRF: return NEWGRF_DIR; + + case CONTENT_TYPE_BASE_GRAPHICS: + case CONTENT_TYPE_BASE_SOUNDS: + case CONTENT_TYPE_BASE_MUSIC: + return BASESET_DIR; + + case CONTENT_TYPE_SCENARIO: + case CONTENT_TYPE_HEIGHTMAP: + return SCENARIO_DIR; + } +} + #endif /* ENABLE_NETWORK */ diff --git a/src/network/core/tcp_content.h b/src/network/core/tcp_content.h --- a/src/network/core/tcp_content.h +++ b/src/network/core/tcp_content.h @@ -91,6 +91,7 @@ size_t Size() const; bool IsSelected() const; bool IsValid() const; + const char *GetTextfile(TextfileType type) const; }; /** Base socket handler for all Content TCP sockets */ @@ -206,6 +207,8 @@ void ReceivePackets(); }; +Subdirectory GetContentInfoSubDir(ContentType type); + #endif /* ENABLE_NETWORK */ #endif /* NETWORK_CORE_TCP_CONTENT_H */ diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp --- a/src/network/network_content.cpp +++ b/src/network/network_content.cpp @@ -384,20 +384,8 @@ */ static char *GetFullFilename(const ContentInfo *ci, bool compressed) { - Subdirectory dir; - switch (ci->type) { - default: return NULL; - case CONTENT_TYPE_BASE_GRAPHICS: dir = BASESET_DIR; break; - case CONTENT_TYPE_BASE_MUSIC: dir = BASESET_DIR; break; - case CONTENT_TYPE_BASE_SOUNDS: dir = BASESET_DIR; break; - case CONTENT_TYPE_NEWGRF: dir = NEWGRF_DIR; break; - case CONTENT_TYPE_AI: dir = AI_DIR; break; - case CONTENT_TYPE_AI_LIBRARY: dir = AI_LIBRARY_DIR; break; - case CONTENT_TYPE_SCENARIO: dir = SCENARIO_DIR; break; - case CONTENT_TYPE_HEIGHTMAP: dir = HEIGHTMAP_DIR; break; - case CONTENT_TYPE_GAME: dir = GAME_DIR; break; - case CONTENT_TYPE_GAME_LIBRARY: dir = GAME_LIBRARY_DIR; break; - } + Subdirectory dir = GetContentInfoSubDir(ci->type); + if (dir == NO_DIRECTORY) return NULL; static char buf[MAX_PATH]; FioGetFullPath(buf, lengthof(buf), SP_AUTODOWNLOAD_DIR, dir, ci->filename); @@ -544,41 +532,8 @@ if (GunzipFile(this->curInfo)) { unlink(GetFullFilename(this->curInfo, true)); - Subdirectory sd = NO_DIRECTORY; - switch (this->curInfo->type) { - case CONTENT_TYPE_AI: - sd = AI_DIR; - break; - - case CONTENT_TYPE_AI_LIBRARY: - sd = AI_LIBRARY_DIR; - break; - - case CONTENT_TYPE_GAME: - sd = GAME_DIR; - break; - - case CONTENT_TYPE_GAME_LIBRARY: - sd = GAME_LIBRARY_DIR; - break; - - case CONTENT_TYPE_BASE_GRAPHICS: - case CONTENT_TYPE_BASE_SOUNDS: - case CONTENT_TYPE_BASE_MUSIC: - sd = BASESET_DIR; - break; - - case CONTENT_TYPE_NEWGRF: - sd = NEWGRF_DIR; - break; - - case CONTENT_TYPE_SCENARIO: - case CONTENT_TYPE_HEIGHTMAP: - sd = SCENARIO_DIR; - break; - - default: NOT_REACHED(); - } + Subdirectory sd = GetContentInfoSubDir(this->curInfo->type); + if (sd == NO_DIRECTORY) NOT_REACHED(); TarScanner ts; ts.AddFile(sd, GetFullFilename(this->curInfo, false)); diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -22,12 +22,55 @@ #include "../stringfilter_type.h" #include "../querystring_gui.h" #include "../core/geometry_func.hpp" +#include "../textfile_gui.h" #include "network_content_gui.h" #include "table/strings.h" #include "../table/sprites.h" +/** 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. + + ContentTextfileWindow(TextfileType file_type, const ContentInfo *ci) : TextfileWindow(file_type), ci(ci) + { + const char *textfile = this->ci->GetTextfile(file_type); + this->LoadTextfile(textfile, GetContentInfoSubDir(this->ci->type)); + } + + StringID GetTypeString() const + { + switch (this->ci->type) { + case CONTENT_TYPE_NEWGRF: return STR_CONTENT_TYPE_NEWGRF; + case CONTENT_TYPE_BASE_GRAPHICS: return STR_CONTENT_TYPE_BASE_GRAPHICS; + case CONTENT_TYPE_BASE_SOUNDS: return STR_CONTENT_TYPE_BASE_SOUNDS; + case CONTENT_TYPE_BASE_MUSIC: return STR_CONTENT_TYPE_BASE_MUSIC; + case CONTENT_TYPE_AI: return STR_CONTENT_TYPE_AI; + case CONTENT_TYPE_AI_LIBRARY: return STR_CONTENT_TYPE_AI_LIBRARY; + case CONTENT_TYPE_GAME: return STR_CONTENT_TYPE_GAME_SCRIPT; + case CONTENT_TYPE_GAME_LIBRARY: return STR_CONTENT_TYPE_GS_LIBRARY; + case CONTENT_TYPE_SCENARIO: return STR_CONTENT_TYPE_SCENARIO; + case CONTENT_TYPE_HEIGHTMAP: return STR_CONTENT_TYPE_HEIGHTMAP; + default: NOT_REACHED(); + } + } + + /* virtual */ void SetStringParameters(int widget) const + { + if (widget == WID_TF_CAPTION) { + SetDParam(0, this->GetTypeString()); + SetDParamStr(1, this->ci->name); + } + } +}; + +void ShowContentTextfileWindow(TextfileType file_type, const ContentInfo *ci) +{ + DeleteWindowByClass(WC_TEXTFILE); + new ContentTextfileWindow(file_type, ci); +} + /** Nested widgets for the download window. */ static const NWidgetPart _nested_network_content_download_status_window_widgets[] = { NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), @@ -611,6 +654,13 @@ virtual void OnClick(Point pt, int widget, int click_count) { + if (widget >= WID_NCL_TEXTFILE && widget < WID_NCL_TEXTFILE + TFT_END) { + if (this->selected == NULL || this->selected->state != ContentInfo::ALREADY_HERE) return; + + ShowContentTextfileWindow((TextfileType)(widget - WID_NCL_TEXTFILE), this->selected); + return; + } + switch (widget) { case WID_NCL_MATRIX: { uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NCL_MATRIX); @@ -820,6 +870,9 @@ this->SetWidgetDisabledState(WID_NCL_SELECT_ALL, !show_select_all); this->SetWidgetDisabledState(WID_NCL_SELECT_UPDATE, !show_select_upgrade); this->SetWidgetDisabledState(WID_NCL_OPEN_URL, this->selected == NULL || StrEmpty(this->selected->url)); + for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { + this->SetWidgetDisabledState(WID_NCL_TEXTFILE + tft, this->selected == NULL || this->selected->state != ContentInfo::ALREADY_HERE || this->selected->GetTextfile(tft) == NULL); + } this->GetWidget(WID_NCL_CANCEL)->widget_data = this->filesize_sum == 0 ? STR_AI_SETTINGS_CLOSE : STR_AI_LIST_CANCEL; } @@ -873,6 +926,11 @@ /* Right side. */ NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NCL_DETAILS), SetResize(1, 1), SetFill(1, 1), EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + EndContainer(), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0), diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -542,8 +542,6 @@ NewGRFTextfileWindow(TextfileType file_type, const GRFConfig *c) : TextfileWindow(file_type), grf_config(c) { - this->GetWidget(WID_TF_CAPTION)->SetDataTip(STR_TEXTFILE_README_CAPTION + file_type, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS); - const char *textfile = this->grf_config->GetTextfile(file_type); this->LoadTextfile(textfile, NEWGRF_DIR); } diff --git a/src/script/api/script_window.hpp b/src/script/api/script_window.hpp --- a/src/script/api/script_window.hpp +++ b/src/script/api/script_window.hpp @@ -1523,6 +1523,7 @@ WID_NCL_SELECT_ALL = ::WID_NCL_SELECT_ALL, ///< 'Select all' button. WID_NCL_SELECT_UPDATE = ::WID_NCL_SELECT_UPDATE, ///< 'Select updates' button. WID_NCL_UNSELECT = ::WID_NCL_UNSELECT, ///< 'Unselect all' button. + WID_NCL_TEXTFILE = ::WID_NCL_TEXTFILE, ///< Open textfile (readme, changelog (+1) or license (+2)) of some content. WID_NCL_OPEN_URL = ::WID_NCL_OPEN_URL, ///< 'Open url' button. WID_NCL_CANCEL = ::WID_NCL_CANCEL, ///< 'Cancel' button. WID_NCL_DOWNLOAD = ::WID_NCL_DOWNLOAD, ///< 'Download' button. diff --git a/src/script/script_scanner.cpp b/src/script/script_scanner.cpp --- a/src/script/script_scanner.cpp +++ b/src/script/script_scanner.cpp @@ -271,4 +271,12 @@ return false; } +const char *ScriptScanner::FindScript(const ContentInfo *ci, bool md5sum) +{ + for (ScriptInfoList::iterator it = this->info_list.begin(); it != this->info_list.end(); it++) { + if (IsSameScript(ci, md5sum, (*it).second, this->GetDirectory())) return (*it).second->GetMainScript(); + } + return NULL; +} + #endif /* ENABLE_NETWORK */ diff --git a/src/script/script_scanner.hpp b/src/script/script_scanner.hpp --- a/src/script/script_scanner.hpp +++ b/src/script/script_scanner.hpp @@ -69,6 +69,14 @@ */ bool HasScript(const struct ContentInfo *ci, bool md5sum); + /** + * Find a script of a #ContentInfo + * @param ci The information to compare to. + * @param md5sum Whether to check the MD5 checksum. + * @return A filename of a file of the content, else \c NULL. + */ + const char *FindScript(const ContentInfo *ci, bool md5sum); + /* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename); /** diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -127,8 +127,6 @@ BaseSetTextfileWindow(TextfileType file_type, const TBaseSet* baseset, StringID content_type) : TextfileWindow(file_type), baseset(baseset), content_type(content_type) { - this->GetWidget(WID_TF_CAPTION)->SetDataTip(STR_TEXTFILE_README_CAPTION + file_type, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS); - const char *textfile = this->baseset->GetTextfile(file_type); this->LoadTextfile(textfile, BASESET_DIR); } diff --git a/src/textfile_gui.cpp b/src/textfile_gui.cpp --- a/src/textfile_gui.cpp +++ b/src/textfile_gui.cpp @@ -55,6 +55,7 @@ this->vscroll = this->GetScrollbar(WID_TF_VSCROLLBAR); this->hscroll = this->GetScrollbar(WID_TF_HSCROLLBAR); this->FinishInitNested(&_textfile_desc); + this->GetWidget(WID_TF_CAPTION)->SetDataTip(STR_TEXTFILE_README_CAPTION + file_type, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS); } /* virtual */ TextfileWindow::~TextfileWindow() diff --git a/src/widgets/network_content_widget.h b/src/widgets/network_content_widget.h --- a/src/widgets/network_content_widget.h +++ b/src/widgets/network_content_widget.h @@ -12,6 +12,8 @@ #ifndef WIDGETS_NETWORK_CONTENT_WIDGET_H #define WIDGETS_NETWORK_CONTENT_WIDGET_H +#include "../textfile_type.h" + /** Widgets of the #NetworkContentDownloadStatusWindow class. */ enum NetworkContentDownloadStatusWidgets { WID_NCDS_BACKGROUND, ///< Background of the window. @@ -33,8 +35,9 @@ WID_NCL_SCROLLBAR, ///< Scrollbar of matrix. WID_NCL_DETAILS, ///< Panel with content details. + WID_NCL_TEXTFILE, ///< Open readme, changelog (+1) or license (+2) of a file in the content window. - WID_NCL_SELECT_ALL, ///< 'Select all' button. + WID_NCL_SELECT_ALL = WID_NCL_TEXTFILE + TFT_END, ///< 'Select all' button. WID_NCL_SELECT_UPDATE, ///< 'Select updates' button. WID_NCL_UNSELECT, ///< 'Unselect all' button. WID_NCL_OPEN_URL, ///< 'Open url' button.