# network_content_gui.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * 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 <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #if defined(ENABLE_NETWORK)
    00013 #include "../stdafx.h"
    00014 #include "../strings_func.h"
    00015 #include "../gfx_func.h"
    00016 #include "../window_func.h"
    00017 #include "../error.h"
    00018 #include "../ai/ai.hpp"
    00019 #include "../game/game.hpp"
    00020 #include "../base_media_base.h"
    00021 #include "../sortlist_type.h"
    00022 #include "../stringfilter_type.h"
    00023 #include "../querystring_gui.h"
    00024 #include "../core/geometry_func.hpp"
    00025 #include "../textfile_gui.h"
    00026 #include "network_content_gui.h"
    00027
    00028
    00029 #include "table/strings.h"
    00030 #include "../table/sprites.h"
    00031
    00033 struct ContentTextfileWindow : public TextfileWindow {
    00034   const ContentInfo *ci;
    00035
    00036   ContentTextfileWindow(TextfileType file_type, const ContentInfo *ci) : TextfileWindow(file_type), ci(ci)
    00037   {
    00038     const char *textfile = this->ci->GetTextfile(file_type);
    00039     this->LoadTextfile(textfile, GetContentInfoSubDir(this->ci->type));
    00040   }
    00041
    00042   StringID GetTypeString() const
    00043   {
    00044     switch (this->ci->type) {
    00045       case CONTENT_TYPE_NEWGRF:        return STR_CONTENT_TYPE_NEWGRF;
    00046       case CONTENT_TYPE_BASE_GRAPHICS: return STR_CONTENT_TYPE_BASE_GRAPHICS;
    00047       case CONTENT_TYPE_BASE_SOUNDS:   return STR_CONTENT_TYPE_BASE_SOUNDS;
    00048       case CONTENT_TYPE_BASE_MUSIC:    return STR_CONTENT_TYPE_BASE_MUSIC;
    00049       case CONTENT_TYPE_AI:            return STR_CONTENT_TYPE_AI;
    00050       case CONTENT_TYPE_AI_LIBRARY:    return STR_CONTENT_TYPE_AI_LIBRARY;
    00051       case CONTENT_TYPE_GAME:          return STR_CONTENT_TYPE_GAME_SCRIPT;
    00052       case CONTENT_TYPE_GAME_LIBRARY:  return STR_CONTENT_TYPE_GS_LIBRARY;
    00053       case CONTENT_TYPE_SCENARIO:      return STR_CONTENT_TYPE_SCENARIO;
    00054       case CONTENT_TYPE_HEIGHTMAP:     return STR_CONTENT_TYPE_HEIGHTMAP;
    00055       default: NOT_REACHED();
    00056     }
    00057   }
    00058
    00059   /* virtual */ void SetStringParameters(int widget) const
    00060   {
    00061     if (widget == WID_TF_CAPTION) {
    00062       SetDParam(0, this->GetTypeString());
    00063       SetDParamStr(1, this->ci->name);
    00064     }
    00065   }
    00066 };
    00067
    00068 void ShowContentTextfileWindow(TextfileType file_type, const ContentInfo *ci)
    00069 {
    00070   DeleteWindowByClass(WC_TEXTFILE);
    00071   new ContentTextfileWindow(file_type, ci);
    00072 }
    00073
    00075 static const NWidgetPart _nested_network_content_download_status_window_widgets[] = {
    00076   NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    00077   NWidget(WWT_PANEL, COLOUR_GREY, WID_NCDS_BACKGROUND),
    00078     NWidget(NWID_SPACER), SetMinimalSize(350, 0), SetMinimalTextLines(3, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 30),
    00079     NWidget(NWID_HORIZONTAL),
    00080       NWidget(NWID_SPACER), SetMinimalSize(125, 0),
    00081       NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCDS_CANCELOK), SetMinimalSize(101, 12), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
    00082       NWidget(NWID_SPACER), SetFill(1, 0),
    00083     EndContainer(),
    00084     NWidget(NWID_SPACER), SetMinimalSize(0, 4),
    00085   EndContainer(),
    00086 };
    00087
    00089 static const WindowDesc _network_content_download_status_window_desc(
    00090   WDP_CENTER, 0, 0,
    00091   WC_NETWORK_STATUS_WINDOW, WC_NONE,
    00092   WDF_MODAL,
    00093   _nested_network_content_download_status_window_widgets, lengthof(_nested_network_content_download_status_window_widgets)
    00094 );
    00095
    00096 BaseNetworkContentDownloadStatusWindow::BaseNetworkContentDownloadStatusWindow(const WindowDesc *desc) :
    00097     cur_id(UINT32_MAX)
    00098 {
    00099   _network_content_client.AddCallback(this);
    00100   _network_content_client.DownloadSelectedContent(this->total_files, this->total_bytes);
    00101
    00102   this->InitNested(desc, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD);
    00103 }
    00104
    00105 BaseNetworkContentDownloadStatusWindow::~BaseNetworkContentDownloadStatusWindow()
    00106 {
    00107   _network_content_client.RemoveCallback(this);
    00108 }
    00109
    00110 /* virtual */ void BaseNetworkContentDownloadStatusWindow::DrawWidget(const Rect &r, int widget) const
    00111 {
    00112   if (widget != WID_NCDS_BACKGROUND) return;
    00113
    00114   /* Draw nice progress bar :) */
    00115   DrawFrameRect(r.left + 20, r.top + 4, r.left + 20 + (int)((this->width - 40LL) * this->downloaded_bytes / this->total_bytes), r.top + 14, COLOUR_MAUVE, FR_NONE);
    00116
    00117   int y = r.top + 20;
    00118   SetDParam(0, this->downloaded_bytes);
    00119   SetDParam(1, this->total_bytes);
    00120   SetDParam(2, this->downloaded_bytes * 100LL / this->total_bytes);
    00121   DrawString(r.left + 2, r.right - 2, y, STR_CONTENT_DOWNLOAD_PROGRESS_SIZE, TC_FROMSTRING, SA_HOR_CENTER);
    00122
    00123   StringID str;
    00124   if (this->downloaded_bytes == this->total_bytes) {
    00125     str = STR_CONTENT_DOWNLOAD_COMPLETE;
    00126   } else if (!StrEmpty(this->name)) {
    00127     SetDParamStr(0, this->name);
    00128     SetDParam(1, this->downloaded_files);
    00129     SetDParam(2, this->total_files);
    00130     str = STR_CONTENT_DOWNLOAD_FILE;
    00131   } else {
    00132     str = STR_CONTENT_DOWNLOAD_INITIALISE;
    00133   }
    00134
    00135   y += FONT_HEIGHT_NORMAL + 5;
    00136   DrawStringMultiLine(r.left + 2, r.right - 2, y, y + FONT_HEIGHT_NORMAL * 2, str, TC_FROMSTRING, SA_CENTER);
    00137 }
    00138
    00139 /* virtual */ void BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(const ContentInfo *ci, int bytes)
    00140 {
    00141   if (ci->id != this->cur_id) {
    00142     strecpy(this->name, ci->filename, lastof(this->name));
    00143     this->cur_id = ci->id;
    00144     this->downloaded_files++;
    00145   }
    00146
    00147   this->downloaded_bytes += bytes;
    00148   this->SetDirty();
    00149 }
    00150
    00151
    00153 struct NetworkContentDownloadStatusWindow : public BaseNetworkContentDownloadStatusWindow {
    00154 private:
    00155   SmallVector<ContentType, 4> receivedTypes;
    00156
    00157 public:
    00162   NetworkContentDownloadStatusWindow() : BaseNetworkContentDownloadStatusWindow(&_network_content_download_status_window_desc)
    00163   {
    00164     this->parent = FindWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_CONTENT_LIST);
    00165   }
    00166
    00168   ~NetworkContentDownloadStatusWindow()
    00169   {
    00170     TarScanner::Mode mode = TarScanner::NONE;
    00171     for (ContentType *iter = this->receivedTypes.Begin(); iter != this->receivedTypes.End(); iter++) {
    00172       switch (*iter) {
    00173         case CONTENT_TYPE_AI:
    00174         case CONTENT_TYPE_AI_LIBRARY:
    00175           /* AI::Rescan calls the scanner. */
    00176           break;
    00177         case CONTENT_TYPE_GAME:
    00178         case CONTENT_TYPE_GAME_LIBRARY:
    00179           /* Game::Rescan calls the scanner. */
    00180           break;
    00181
    00182         case CONTENT_TYPE_BASE_GRAPHICS:
    00183         case CONTENT_TYPE_BASE_SOUNDS:
    00184         case CONTENT_TYPE_BASE_MUSIC:
    00185           mode |= TarScanner::BASESET;
    00186           break;
    00187
    00188         case CONTENT_TYPE_NEWGRF:
    00189           /* ScanNewGRFFiles calls the scanner. */
    00190           break;
    00191
    00192         case CONTENT_TYPE_SCENARIO:
    00193         case CONTENT_TYPE_HEIGHTMAP:
    00194           mode |= TarScanner::SCENARIO;
    00195           break;
    00196
    00197         default:
    00198           break;
    00199       }
    00200     }
    00201
    00202     TarScanner::DoScan(mode);
    00203
    00204     /* Tell all the backends about what we've downloaded */
    00205     for (ContentType *iter = this->receivedTypes.Begin(); iter != this->receivedTypes.End(); iter++) {
    00206       switch (*iter) {
    00207         case CONTENT_TYPE_AI:
    00208         case CONTENT_TYPE_AI_LIBRARY:
    00209           AI::Rescan();
    00210           break;
    00211
    00212         case CONTENT_TYPE_GAME:
    00213         case CONTENT_TYPE_GAME_LIBRARY:
    00214           Game::Rescan();
    00215           break;
    00216
    00217         case CONTENT_TYPE_BASE_GRAPHICS:
    00218           BaseGraphics::FindSets();
    00219           SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_OPTIONS);
    00220           break;
    00221
    00222         case CONTENT_TYPE_BASE_SOUNDS:
    00223           BaseSounds::FindSets();
    00224           SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_OPTIONS);
    00225           break;
    00226
    00227         case CONTENT_TYPE_BASE_MUSIC:
    00228           BaseMusic::FindSets();
    00229           SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_OPTIONS);
    00230           break;
    00231
    00232         case CONTENT_TYPE_NEWGRF:
    00233           ScanNewGRFFiles(NULL);
    00234           break;
    00235
    00236         case CONTENT_TYPE_SCENARIO:
    00237         case CONTENT_TYPE_HEIGHTMAP:
    00238           extern void ScanScenarios();
    00239           ScanScenarios();
    00240           InvalidateWindowData(WC_SAVELOAD, 0, 0);
    00241           break;
    00242
    00243         default:
    00244           break;
    00245       }
    00246     }
    00247
    00248     /* Always invalidate the download window; tell it we are going to be gone */
    00249     InvalidateWindowData(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_CONTENT_LIST, 2);
    00250   }
    00251
    00252   virtual void OnClick(Point pt, int widget, int click_count)
    00253   {
    00254     if (widget == WID_NCDS_CANCELOK) {
    00255       if (this->downloaded_bytes != this->total_bytes) {
    00256         _network_content_client.Close();
    00257         delete this;
    00258       } else {
    00259         /* If downloading succeeded, close the online content window. This will close
    00260          * the current window as well. */
    00261         DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_CONTENT_LIST);
    00262       }
    00263     }
    00264   }
    00265
    00266   virtual void OnDownloadProgress(const ContentInfo *ci, int bytes)
    00267   {
    00268     BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(ci, bytes);
    00269     this->receivedTypes.Include(ci->type);
    00270
    00271     /* When downloading is finished change cancel in ok */
    00272     if (this->downloaded_bytes == this->total_bytes) {
    00273       this->GetWidget<NWidgetCore>(WID_NCDS_CANCELOK)->widget_data = STR_BUTTON_OK;
    00274     }
    00275   }
    00276 };
    00277
    00279 class NetworkContentListWindow : public Window, ContentCallback {
    00281   typedef GUIList<const ContentInfo *, StringFilter &> GUIContentList;
    00282
    00283   static const uint EDITBOX_MAX_SIZE   =  50;
    00284
    00285   static Listing last_sorting;
    00286   static Filtering last_filtering;
    00287   static GUIContentList::SortFunction * const sorter_funcs[];
    00288   static GUIContentList::FilterFunction * const filter_funcs[];
    00289   GUIContentList content;
    00290   bool auto_select;
    00291   StringFilter string_filter;
    00292   QueryString filter_editbox;
    00293
    00294   const ContentInfo *selected;
    00295   int list_pos;
    00296   uint filesize_sum;
    00297   Scrollbar *vscroll;
    00298
    00303   void BuildContentList()
    00304   {
    00305     if (!this->content.NeedRebuild()) return;
    00306
    00307     /* Create temporary array of games to use for listing */
    00308     this->content.Clear();
    00309
    00310     for (ConstContentIterator iter = _network_content_client.Begin(); iter != _network_content_client.End(); iter++) {
    00311       *this->content.Append() = *iter;
    00312     }
    00313
    00314     this->FilterContentList();
    00315     this->content.Compact();
    00316     this->content.RebuildDone();
    00317     this->SortContentList();
    00318
    00319     this->vscroll->SetCount(this->content.Length()); // Update the scrollbar
    00320     this->ScrollToSelected();
    00321   }
    00322
    00324   static int CDECL NameSorter(const ContentInfo * const *a, const ContentInfo * const *b)
    00325   {
    00326     return strnatcmp((*a)->name, (*b)->name); // Sort by name (natural sorting).
    00327   }
    00328
    00330   static int CDECL TypeSorter(const ContentInfo * const *a, const ContentInfo * const *b)
    00331   {
    00332     int r = 0;
    00333     if ((*a)->type != (*b)->type) {
    00334       char a_str[64];
    00335       char b_str[64];
    00336       GetString(a_str, STR_CONTENT_TYPE_BASE_GRAPHICS + (*a)->type - CONTENT_TYPE_BASE_GRAPHICS, lastof(a_str));
    00337       GetString(b_str, STR_CONTENT_TYPE_BASE_GRAPHICS + (*b)->type - CONTENT_TYPE_BASE_GRAPHICS, lastof(b_str));
    00338       r = strnatcmp(a_str, b_str);
    00339     }
    00340     if (r == 0) r = NameSorter(a, b);
    00341     return r;
    00342   }
    00343
    00345   static int CDECL StateSorter(const ContentInfo * const *a, const ContentInfo * const *b)
    00346   {
    00347     int r = (*a)->state - (*b)->state;
    00348     if (r == 0) r = TypeSorter(a, b);
    00349     return r;
    00350   }
    00351
    00353   void SortContentList()
    00354   {
    00355     if (!this->content.Sort()) return;
    00356
    00357     for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) {
    00358       if (*iter == this->selected) {
    00359         this->list_pos = iter - this->content.Begin();
    00360         break;
    00361       }
    00362     }
    00363   }
    00364
    00366   static bool CDECL TagNameFilter(const ContentInfo * const *a, StringFilter &filter)
    00367   {
    00368     filter.ResetState();
    00369     for (int i = 0; i < (*a)->tag_count; i++) {
    00370       filter.AddLine((*a)->tags[i]);
    00371     }
    00372     filter.AddLine((*a)->name);
    00373     return filter.GetState();
    00374   }
    00375
    00377   void FilterContentList()
    00378   {
    00379     if (!this->content.Filter(this->string_filter)) return;
    00380
    00381     /* update list position */
    00382     for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) {
    00383       if (*iter == this->selected) {
    00384         this->list_pos = iter - this->content.Begin();
    00385         return;
    00386       }
    00387     }
    00388
    00389     /* previously selected item not in list anymore */
    00390     this->selected = NULL;
    00391     this->list_pos = 0;
    00392   }
    00393
    00395   void ScrollToSelected()
    00396   {
    00397     if (this->selected == NULL) return;
    00398
    00399     this->vscroll->ScrollTowards(this->list_pos);
    00400   }
    00401
    00402 public:
    00408   NetworkContentListWindow(const WindowDesc *desc, bool select_all) :
    00409       auto_select(select_all),
    00410       filter_editbox(EDITBOX_MAX_SIZE),
    00411       selected(NULL),
    00412       list_pos(0)
    00413   {
    00414     this->CreateNestedTree(desc);
    00415     this->vscroll = this->GetScrollbar(WID_NCL_SCROLLBAR);
    00416     this->FinishInitNested(desc, WN_NETWORK_WINDOW_CONTENT_LIST);
    00417
    00418     this->GetWidget<NWidgetStacked>(WID_NCL_SEL_ALL_UPDATE)->SetDisplayedPlane(select_all);
    00419
    00420     this->querystrings[WID_NCL_FILTER] = &this->filter_editbox;
    00421     this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
    00422     this->filter_editbox.afilter = CS_ALPHANUMERAL;
    00423     this->SetFocusedWidget(WID_NCL_FILTER);
    00424
    00425     _network_content_client.AddCallback(this);
    00426     this->content.SetListing(this->last_sorting);
    00427     this->content.SetFiltering(this->last_filtering);
    00428     this->content.SetSortFuncs(this->sorter_funcs);
    00429     this->content.SetFilterFuncs(this->filter_funcs);
    00430     this->content.ForceRebuild();
    00431     this->FilterContentList();
    00432     this->SortContentList();
    00433     this->InvalidateData();
    00434   }
    00435
    00437   ~NetworkContentListWindow()
    00438   {
    00439     _network_content_client.RemoveCallback(this);
    00440   }
    00441
    00442   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    00443   {
    00444     switch (widget) {
    00445       case WID_NCL_FILTER_CAPT:
    00446         *size = maxdim(*size, GetStringBoundingBox(STR_CONTENT_FILTER_TITLE));
    00447         break;
    00448
    00449       case WID_NCL_TYPE: {
    00450         Dimension d = *size;
    00451         for (int i = CONTENT_TYPE_BEGIN; i < CONTENT_TYPE_END; i++) {
    00452           d = maxdim(d, GetStringBoundingBox(STR_CONTENT_TYPE_BASE_GRAPHICS + i - CONTENT_TYPE_BASE_GRAPHICS));
    00453         }
    00454         size->width = d.width + WD_MATRIX_RIGHT + WD_MATRIX_LEFT;
    00455         break;
    00456       }
    00457
    00458       case WID_NCL_MATRIX:
    00459         resize->height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
    00460         size->height = 10 * resize->height;
    00461         break;
    00462     }
    00463   }
    00464
    00465
    00466   virtual void DrawWidget(const Rect &r, int widget) const
    00467   {
    00468     switch (widget) {
    00469       case WID_NCL_FILTER_CAPT:
    00470         DrawString(r.left, r.right, r.top, STR_CONTENT_FILTER_TITLE, TC_FROMSTRING, SA_RIGHT);
    00471         break;
    00472
    00473       case WID_NCL_DETAILS:
    00474         this->DrawDetails(r);
    00475         break;
    00476
    00477       case WID_NCL_MATRIX:
    00478         this->DrawMatrix(r);
    00479         break;
    00480     }
    00481   }
    00482
    00483   virtual void OnPaint()
    00484   {
    00485     const SortButtonState arrow = this->content.IsDescSortOrder() ? SBS_DOWN : SBS_UP;
    00486
    00487     if (this->content.NeedRebuild()) {
    00488       this->BuildContentList();
    00489     }
    00490
    00491     this->DrawWidgets();
    00492
    00493     switch (this->content.SortType()) {
    00494       case WID_NCL_CHECKBOX - WID_NCL_CHECKBOX: this->DrawSortButtonState(WID_NCL_CHECKBOX, arrow); break;
    00495       case WID_NCL_TYPE     - WID_NCL_CHECKBOX: this->DrawSortButtonState(WID_NCL_TYPE,     arrow); break;
    00496       case WID_NCL_NAME     - WID_NCL_CHECKBOX: this->DrawSortButtonState(WID_NCL_NAME,     arrow); break;
    00497     }
    00498   }
    00499
    00504   void DrawMatrix(const Rect &r) const
    00505   {
    00506     const NWidgetBase *nwi_checkbox = this->GetWidget<NWidgetBase>(WID_NCL_CHECKBOX);
    00507     const NWidgetBase *nwi_name = this->GetWidget<NWidgetBase>(WID_NCL_NAME);
    00508     const NWidgetBase *nwi_type = this->GetWidget<NWidgetBase>(WID_NCL_TYPE);
    00509
    00510
    00511     /* Fill the matrix with the information */
    00512     int sprite_y_offset = WD_MATRIX_TOP + (FONT_HEIGHT_NORMAL - 10) / 2;
    00513     uint y = r.top;
    00514     int cnt = 0;
    00515     for (ConstContentIterator iter = this->content.Get(this->vscroll->GetPosition()); iter != this->content.End() && cnt < this->vscroll->GetCapacity(); iter++, cnt++) {
    00516       const ContentInfo *ci = *iter;
    00517
    00518       if (ci == this->selected) GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->resize.step_height - 1, PC_GREY);
    00519
    00520       SpriteID sprite;
    00521       SpriteID pal = PAL_NONE;
    00522       switch (ci->state) {
    00523         case ContentInfo::UNSELECTED:     sprite = SPR_BOX_EMPTY;   break;
    00524         case ContentInfo::SELECTED:       sprite = SPR_BOX_CHECKED; break;
    00525         case ContentInfo::AUTOSELECTED:   sprite = SPR_BOX_CHECKED; break;
    00526         case ContentInfo::ALREADY_HERE:   sprite = SPR_BLOT; pal = PALETTE_TO_GREEN; break;
    00527         case ContentInfo::DOES_NOT_EXIST: sprite = SPR_BLOT; pal = PALETTE_TO_RED;   break;
    00528         default: NOT_REACHED();
    00529       }
    00530       DrawSprite(sprite, pal, nwi_checkbox->pos_x + (pal == PAL_NONE ? 2 : 3), y + sprite_y_offset + (pal == PAL_NONE ? 1 : 0));
    00531
    00532       StringID str = STR_CONTENT_TYPE_BASE_GRAPHICS + ci->type - CONTENT_TYPE_BASE_GRAPHICS;
    00533       DrawString(nwi_type->pos_x, nwi_type->pos_x + nwi_type->current_x - 1, y + WD_MATRIX_TOP, str, TC_BLACK, SA_HOR_CENTER);
    00534
    00535       DrawString(nwi_name->pos_x + WD_FRAMERECT_LEFT, nwi_name->pos_x + nwi_name->current_x - WD_FRAMERECT_RIGHT, y + WD_MATRIX_TOP, ci->name, TC_BLACK);
    00536       y += this->resize.step_height;
    00537     }
    00538   }
    00539
    00544   void DrawDetails(const Rect &r) const
    00545   {
    00546     static const int DETAIL_LEFT         =  5;
    00547     static const int DETAIL_RIGHT        =  5;
    00548     static const int DETAIL_TOP          =  5;
    00549
    00550     /* Height for the title banner */
    00551     int DETAIL_TITLE_HEIGHT = 5 * FONT_HEIGHT_NORMAL;
    00552
    00553     /* Create the nice grayish rectangle at the details top */
    00554     GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + DETAIL_TITLE_HEIGHT, PC_DARK_BLUE);
    00555     DrawString(r.left + WD_INSET_LEFT, r.right - WD_INSET_RIGHT, r.top + FONT_HEIGHT_NORMAL + WD_INSET_TOP, STR_CONTENT_DETAIL_TITLE, TC_FROMSTRING, SA_HOR_CENTER);
    00556
    00557     /* Draw the total download size */
    00558     SetDParam(0, this->filesize_sum);
    00559     DrawString(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, r.bottom - FONT_HEIGHT_NORMAL - WD_PAR_VSEP_NORMAL, STR_CONTENT_TOTAL_DOWNLOAD_SIZE);
    00560
    00561     if (this->selected == NULL) return;
    00562
    00563     /* And fill the rest of the details when there's information to place there */
    00564     DrawStringMultiLine(r.left + WD_INSET_LEFT, r.right - WD_INSET_RIGHT, r.top + DETAIL_TITLE_HEIGHT / 2, r.top + DETAIL_TITLE_HEIGHT, STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED + this->selected->state, TC_FROMSTRING, SA_CENTER);
    00565
    00566     /* Also show the total download size, so keep some space from the bottom */
    00567     const uint max_y = r.bottom - FONT_HEIGHT_NORMAL - WD_PAR_VSEP_WIDE;
    00568     int y = r.top + DETAIL_TITLE_HEIGHT + DETAIL_TOP;
    00569
    00570     if (this->selected->upgrade) {
    00571       SetDParam(0, STR_CONTENT_TYPE_BASE_GRAPHICS + this->selected->type - CONTENT_TYPE_BASE_GRAPHICS);
    00572       y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_UPDATE);
    00573       y += WD_PAR_VSEP_WIDE;
    00574     }
    00575
    00576     SetDParamStr(0, this->selected->name);
    00577     y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_NAME);
    00578
    00579     if (!StrEmpty(this->selected->version)) {
    00580       SetDParamStr(0, this->selected->version);
    00581       y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_VERSION);
    00582     }
    00583
    00584     if (!StrEmpty(this->selected->description)) {
    00585       SetDParamStr(0, this->selected->description);
    00586       y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_DESCRIPTION);
    00587     }
    00588
    00589     if (!StrEmpty(this->selected->url)) {
    00590       SetDParamStr(0, this->selected->url);
    00591       y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_URL);
    00592     }
    00593
    00594     SetDParam(0, STR_CONTENT_TYPE_BASE_GRAPHICS + this->selected->type - CONTENT_TYPE_BASE_GRAPHICS);
    00595     y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_TYPE);
    00596
    00597     y += WD_PAR_VSEP_WIDE;
    00598     SetDParam(0, this->selected->filesize);
    00599     y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_FILESIZE);
    00600
    00601     if (this->selected->dependency_count != 0) {
    00602       /* List dependencies */
    00603       char buf[DRAW_STRING_BUFFER] = "";
    00604       char *p = buf;
    00605       for (uint i = 0; i < this->selected->dependency_count; i++) {
    00606         ContentID cid = this->selected->dependencies[i];
    00607
    00608         /* Try to find the dependency */
    00609         ConstContentIterator iter = _network_content_client.Begin();
    00610         for (; iter != _network_content_client.End(); iter++) {
    00611           const ContentInfo *ci = *iter;
    00612           if (ci->id != cid) continue;
    00613
    00614           p += seprintf(p, lastof(buf), p == buf ? "%s" : ", %s", (*iter)->name);
    00615           break;
    00616         }
    00617       }
    00618       SetDParamStr(0, buf);
    00619       y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_DEPENDENCIES);
    00620     }
    00621
    00622     if (this->selected->tag_count != 0) {
    00623       /* List all tags */
    00624       char buf[DRAW_STRING_BUFFER] = "";
    00625       char *p = buf;
    00626       for (uint i = 0; i < this->selected->tag_count; i++) {
    00627         p += seprintf(p, lastof(buf), i == 0 ? "%s" : ", %s", this->selected->tags[i]);
    00628       }
    00629       SetDParamStr(0, buf);
    00630       y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_TAGS);
    00631     }
    00632
    00633     if (this->selected->IsSelected()) {
    00634       /* When selected show all manually selected content that depends on this */
    00635       ConstContentVector tree;
    00636       _network_content_client.ReverseLookupTreeDependency(tree, this->selected);
    00637
    00638       char buf[DRAW_STRING_BUFFER] = "";
    00639       char *p = buf;
    00640       for (ConstContentIterator iter = tree.Begin(); iter != tree.End(); iter++) {
    00641         const ContentInfo *ci = *iter;
    00642         if (ci == this->selected || ci->state != ContentInfo::SELECTED) continue;
    00643
    00644         p += seprintf(p, lastof(buf), buf == p ? "%s" : ", %s", ci->name);
    00645       }
    00646       if (p != buf) {
    00647         SetDParamStr(0, buf);
    00648         y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF);
    00649       }
    00650     }
    00651   }
    00652
    00653   virtual void OnClick(Point pt, int widget, int click_count)
    00654   {
    00655     if (widget >= WID_NCL_TEXTFILE && widget < WID_NCL_TEXTFILE + TFT_END) {
    00656       if (this->selected == NULL || this->selected->state != ContentInfo::ALREADY_HERE) return;
    00657
    00658       ShowContentTextfileWindow((TextfileType)(widget - WID_NCL_TEXTFILE), this->selected);
    00659       return;
    00660     }
    00661
    00662     switch (widget) {
    00663       case WID_NCL_MATRIX: {
    00664         uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NCL_MATRIX);
    00665         if (id_v >= this->content.Length()) return; // click out of bounds
    00666
    00667         this->selected = *this->content.Get(id_v);
    00668         this->list_pos = id_v;
    00669
    00670         const NWidgetBase *checkbox = this->GetWidget<NWidgetBase>(WID_NCL_CHECKBOX);
    00671         if (click_count > 1 || IsInsideBS(pt.x, checkbox->pos_x, checkbox->current_x)) {
    00672           _network_content_client.ToggleSelectedState(this->selected);
    00673           this->content.ForceResort();
    00674         }
    00675
    00676         this->InvalidateData();
    00677         break;
    00678       }
    00679
    00680       case WID_NCL_CHECKBOX:
    00681       case WID_NCL_TYPE:
    00682       case WID_NCL_NAME:
    00683         if (this->content.SortType() == widget - WID_NCL_CHECKBOX) {
    00684           this->content.ToggleSortOrder();
    00685           this->list_pos = this->content.Length() - this->list_pos - 1;
    00686         } else {
    00687           this->content.SetSortType(widget - WID_NCL_CHECKBOX);
    00688           this->content.ForceResort();
    00689           this->SortContentList();
    00690         }
    00691         this->ScrollToSelected();
    00692         this->InvalidateData();
    00693         break;
    00694
    00695       case WID_NCL_SELECT_ALL:
    00696         _network_content_client.SelectAll();
    00697         this->InvalidateData();
    00698         break;
    00699
    00700       case WID_NCL_SELECT_UPDATE:
    00701         _network_content_client.SelectUpgrade();
    00702         this->InvalidateData();
    00703         break;
    00704
    00705       case WID_NCL_UNSELECT:
    00706         _network_content_client.UnselectAll();
    00707         this->InvalidateData();
    00708         break;
    00709
    00710       case WID_NCL_CANCEL:
    00711         delete this;
    00712         break;
    00713
    00714       case WID_NCL_OPEN_URL:
    00715         if (this->selected != NULL) {
    00716           extern void OpenBrowser(const char *url);
    00717           OpenBrowser(this->selected->url);
    00718         }
    00719         break;
    00720
    00721       case WID_NCL_DOWNLOAD:
    00722         if (BringWindowToFrontById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD) == NULL) new NetworkContentDownloadStatusWindow();
    00723         break;
    00724     }
    00725   }
    00726
    00727   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
    00728   {
    00729     switch (keycode) {
    00730       case WKC_UP:
    00731         /* scroll up by one */
    00732         if (this->list_pos > 0) this->list_pos--;
    00733         break;
    00734       case WKC_DOWN:
    00735         /* scroll down by one */
    00736         if (this->list_pos < (int)this->content.Length() - 1) this->list_pos++;
    00737         break;
    00738       case WKC_PAGEUP:
    00739         /* scroll up a page */
    00740         this->list_pos = (this->list_pos < this->vscroll->GetCapacity()) ? 0 : this->list_pos - this->vscroll->GetCapacity();
    00741         break;
    00742       case WKC_PAGEDOWN:
    00743         /* scroll down a page */
    00744         this->list_pos = min(this->list_pos + this->vscroll->GetCapacity(), (int)this->content.Length() - 1);
    00745         break;
    00746       case WKC_HOME:
    00747         /* jump to beginning */
    00748         this->list_pos = 0;
    00749         break;
    00750       case WKC_END:
    00751         /* jump to end */
    00752         this->list_pos = this->content.Length() - 1;
    00753         break;
    00754
    00755       case WKC_SPACE:
    00756       case WKC_RETURN:
    00757         if (keycode == WKC_RETURN || !IsWidgetFocused(WID_NCL_FILTER)) {
    00758           if (this->selected != NULL) {
    00759             _network_content_client.ToggleSelectedState(this->selected);
    00760             this->content.ForceResort();
    00761             this->InvalidateData();
    00762           }
    00763           return ES_HANDLED;
    00764         }
    00765         /* FALL THROUGH, space is pressed and filter isn't focused. */
    00766
    00767       default:
    00768         return ES_NOT_HANDLED;
    00769     }
    00770
    00771     if (_network_content_client.Length() == 0) return ES_HANDLED;
    00772
    00773     this->selected = *this->content.Get(this->list_pos);
    00774
    00775     /* scroll to the new server if it is outside the current range */
    00776     this->ScrollToSelected();
    00777
    00778     /* redraw window */
    00779     this->InvalidateData();
    00780     return ES_HANDLED;
    00781   }
    00782
    00783   virtual void OnEditboxChanged(int wid)
    00784   {
    00785     if (wid == WID_NCL_FILTER) {
    00786       this->string_filter.SetFilterTerm(this->filter_editbox.text.buf);
    00787       this->content.SetFilterState(!this->string_filter.IsEmpty());
    00788       this->content.ForceRebuild();
    00789       this->InvalidateData();
    00790     }
    00791   }
    00792
    00793   virtual void OnResize()
    00794   {
    00795     this->vscroll->SetCapacityFromWidget(this, WID_NCL_MATRIX);
    00796     this->GetWidget<NWidgetCore>(WID_NCL_MATRIX)->widget_data = (this->vscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
    00797   }
    00798
    00799   virtual void OnReceiveContentInfo(const ContentInfo *rci)
    00800   {
    00801     if (this->auto_select && !rci->IsSelected()) _network_content_client.ToggleSelectedState(rci);
    00802     this->content.ForceRebuild();
    00803     this->InvalidateData();
    00804   }
    00805
    00806   virtual void OnDownloadComplete(ContentID cid)
    00807   {
    00808     this->content.ForceResort();
    00809     this->InvalidateData();
    00810   }
    00811
    00812   virtual void OnConnect(bool success)
    00813   {
    00814     if (!success) {
    00815       ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_CONNECT, INVALID_STRING_ID, WL_ERROR);
    00816       delete this;
    00817       return;
    00818     }
    00819
    00820     this->InvalidateData();
    00821   }
    00822
    00828   virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
    00829   {
    00830     if (!gui_scope) return;
    00831     if (this->content.NeedRebuild()) this->BuildContentList();
    00832
    00833     /* To sum all the bytes we intend to download */
    00834     this->filesize_sum = 0;
    00835     bool show_select_all = false;
    00836     bool show_select_upgrade = false;
    00837     for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) {
    00838       const ContentInfo *ci = *iter;
    00839       switch (ci->state) {
    00840         case ContentInfo::SELECTED:
    00841         case ContentInfo::AUTOSELECTED:
    00842           this->filesize_sum += ci->filesize;
    00843           break;
    00844
    00845         case ContentInfo::UNSELECTED:
    00846           show_select_all = true;
    00847           show_select_upgrade |= ci->upgrade;
    00848           break;
    00849
    00850         default:
    00851           break;
    00852       }
    00853     }
    00854
    00855     /* If data == 2 then the status window caused this OnInvalidate */
    00856     this->SetWidgetDisabledState(WID_NCL_DOWNLOAD, this->filesize_sum == 0 || (FindWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD) != NULL && data != 2));
    00857     this->SetWidgetDisabledState(WID_NCL_UNSELECT, this->filesize_sum == 0);
    00858     this->SetWidgetDisabledState(WID_NCL_SELECT_ALL, !show_select_all);
    00859     this->SetWidgetDisabledState(WID_NCL_SELECT_UPDATE, !show_select_upgrade);
    00860     this->SetWidgetDisabledState(WID_NCL_OPEN_URL, this->selected == NULL || StrEmpty(this->selected->url));
    00861     for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) {
    00862       this->SetWidgetDisabledState(WID_NCL_TEXTFILE + tft, this->selected == NULL || this->selected->state != ContentInfo::ALREADY_HERE || this->selected->GetTextfile(tft) == NULL);
    00863     }
    00864
    00865     this->GetWidget<NWidgetCore>(WID_NCL_CANCEL)->widget_data = this->filesize_sum == 0 ? STR_AI_SETTINGS_CLOSE : STR_AI_LIST_CANCEL;
    00866   }
    00867 };
    00868
    00869 Listing NetworkContentListWindow::last_sorting = {false, 1};
    00870 Filtering NetworkContentListWindow::last_filtering = {false, 0};
    00871
    00872 NetworkContentListWindow::GUIContentList::SortFunction * const NetworkContentListWindow::sorter_funcs[] = {
    00873   &StateSorter,
    00874   &TypeSorter,
    00875   &NameSorter,
    00876 };
    00877
    00878 NetworkContentListWindow::GUIContentList::FilterFunction * const NetworkContentListWindow::filter_funcs[] = {
    00879   &TagNameFilter,
    00880 };
    00881
    00883 static const NWidgetPart _nested_network_content_list_widgets[] = {
    00884   NWidget(NWID_HORIZONTAL),
    00885     NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
    00886     NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_CONTENT_TITLE, STR_NULL),
    00887   EndContainer(),
    00888   NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NCL_BACKGROUND),
    00889     NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0),
    00890     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
    00891       /* Top */
    00892       NWidget(WWT_EMPTY, COLOUR_LIGHT_BLUE, WID_NCL_FILTER_CAPT), SetFill(1, 0), SetResize(1, 0),
    00893       NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NCL_FILTER), SetFill(1, 0), SetResize(1, 0),
    00894             SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
    00895     EndContainer(),
    00896     NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0),
    00897     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
    00898       /* Left side. */
    00899       NWidget(NWID_VERTICAL),
    00900         NWidget(NWID_HORIZONTAL),
    00901           NWidget(NWID_VERTICAL),
    00902             NWidget(NWID_HORIZONTAL),
    00903               NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_CHECKBOX), SetMinimalSize(13, 1), SetDataTip(STR_EMPTY, STR_NULL),
    00904               NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TYPE),
    00905                       SetDataTip(STR_CONTENT_TYPE_CAPTION, STR_CONTENT_TYPE_CAPTION_TOOLTIP),
    00906               NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_NAME), SetResize(1, 0), SetFill(1, 0),
    00907                       SetDataTip(STR_CONTENT_NAME_CAPTION, STR_CONTENT_NAME_CAPTION_TOOLTIP),
    00908             EndContainer(),
    00909             NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NCL_MATRIX), SetResize(1, 14), SetFill(1, 1), SetScrollbar(WID_NCL_SCROLLBAR), SetDataTip(STR_NULL, STR_CONTENT_MATRIX_TOOLTIP),
    00910           EndContainer(),
    00911           NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NCL_SCROLLBAR),
    00912         EndContainer(),
    00913       EndContainer(),
    00914       /* Right side. */
    00915       NWidget(NWID_VERTICAL),
    00916         NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NCL_DETAILS), SetResize(1, 1), SetFill(1, 1), EndContainer(),
    00917         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7),
    00918           NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL),
    00919           NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL),
    00920           NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL),
    00921         EndContainer(),
    00922       EndContainer(),
    00923     EndContainer(),
    00924     NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0),
    00925     /* Bottom. */
    00926     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
    00927       NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
    00928         NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NCL_SEL_ALL_UPDATE), SetResize(1, 0), SetFill(1, 0),
    00929           NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_UPDATE), SetResize(1, 0), SetFill(1, 0),
    00930                       SetDataTip(STR_CONTENT_SELECT_UPDATES_CAPTION, STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP),
    00931           NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_ALL), SetResize(1, 0), SetFill(1, 0),
    00932                       SetDataTip(STR_CONTENT_SELECT_ALL_CAPTION, STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP),
    00933         EndContainer(),
    00934         NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_UNSELECT), SetResize(1, 0), SetFill(1, 0),
    00935                       SetDataTip(STR_CONTENT_UNSELECT_ALL_CAPTION, STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP),
    00936       EndContainer(),
    00937       NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8),
    00938         NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_OPEN_URL), SetResize(1, 0), SetFill(1, 0),
    00939                       SetDataTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
    00940         NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_CANCEL), SetResize(1, 0), SetFill(1, 0),
    00941                       SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
    00942         NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_DOWNLOAD), SetResize(1, 0), SetFill(1, 0),
    00943                       SetDataTip(STR_CONTENT_DOWNLOAD_CAPTION, STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP),
    00944       EndContainer(),
    00945     EndContainer(),
    00946     NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetResize(1, 0),
    00947     /* Resize button. */
    00948     NWidget(NWID_HORIZONTAL),
    00949       NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
    00950       NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE),
    00951     EndContainer(),
    00952   EndContainer(),
    00953 };
    00954
    00956 static const WindowDesc _network_content_list_desc(
    00957   WDP_CENTER, 630, 460,
    00958   WC_NETWORK_WINDOW, WC_NONE,
    00959   0,
    00960   _nested_network_content_list_widgets, lengthof(_nested_network_content_list_widgets)
    00961 );
    00962
    00968 void ShowNetworkContentListWindow(ContentVector *cv, ContentType type)
    00969 {
    00970 #if defined(WITH_ZLIB)
    00971   _network_content_client.Clear();
    00972   if (cv == NULL) {
    00973     _network_content_client.RequestContentList(type);
    00974   } else {
    00975     _network_content_client.RequestContentList(cv, true);
    00976   }
    00977
    00978   DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_CONTENT_LIST);
    00979   new NetworkContentListWindow(&_network_content_list_desc, cv != NULL);
    00980 #else
    00981   ShowErrorMessage(STR_CONTENT_NO_ZLIB, STR_CONTENT_NO_ZLIB_SUB, WL_ERROR);
    00982   /* Connection failed... clean up the mess */
    00983   if (cv != NULL) {
    00984     for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) delete *iter;
    00985   }
    00986 #endif /* WITH_ZLIB */
    00987 }
    00988
    00989 #endif /* ENABLE_NETWORK */