OpenClonk
C4DownloadDlg.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2007-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2013-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // HTTP download dialog; downloads a file
17 
18 #include "C4Include.h"
19 #include "gui/C4DownloadDlg.h"
20 #include "network/C4HTTP.h"
21 
23 
24 C4DownloadDlg::C4DownloadDlg(const char *szDLType) : C4GUI::Dialog(C4GUI_ProgressDlgWdt, 100, FormatString(LoadResStr("IDS_CTL_DL_TITLE"), szDLType).getData(), false), szError(nullptr)
25 {
26 #ifdef HAVE_WINSOCK
27  fWinSock = AcquireWinSock();
28 #endif
29  // add all elements - will be reposisioned when text is displayed
31  AddElement(pStatusLabel = new C4GUI::Label("", C4Rect(), ACenter, C4GUI_MessageFontClr, &::GraphicsResource.TextFont, false));
32  pProgressBar = nullptr; // created when necessary
33  AddElement(pCancelBtn = new C4GUI::CancelButton(C4Rect()));
34 }
35 
37 {
38 #ifdef HAVE_WINSOCK
39  if (fWinSock) ReleaseWinSock();
40 #endif
41 }
42 
43 void C4DownloadDlg::SetStatus(const char *szNewText, int32_t iProgressPercent)
44 {
45  // get positions
47  // place icon
48  pIcon->SetBounds(caMain.GetFromLeft(C4GUI_IconWdt, C4GUI_IconWdt));
49  // place message label
50  // use text with line breaks
51  StdStrBuf sMsgBroken;
52  int iMsgHeight = ::GraphicsResource.TextFont.BreakMessage(szNewText, caMain.GetInnerWidth(), &sMsgBroken, true);
53  pStatusLabel->SetBounds(caMain.GetFromTop(iMsgHeight));
54  pStatusLabel->SetText(sMsgBroken.getData());
55  // place progress bar
56  if (iProgressPercent >= 0)
57  {
58  if (!pProgressBar)
59  {
60  AddElement(pProgressBar = new C4GUI::ProgressBar(caMain.GetFromTop(C4GUI_ProgressDlgPBHgt)));
61  }
62  else
63  {
64  pProgressBar->SetBounds(caMain.GetFromTop(C4GUI_ProgressDlgPBHgt));
65  }
66  pProgressBar->SetProgress(iProgressPercent);
67  }
68  else
69  {
70  // no progress desired
71  if (pProgressBar) { delete pProgressBar; pProgressBar = nullptr; }
72  }
73  // place button
74  caMain.ExpandLeft(C4GUI_DefDlgIndent*2 + C4GUI_IconWdt);
75  C4GUI::ComponentAligner caButtonArea(caMain.GetFromTop(C4GUI_ButtonAreaHgt), 0,0);
76  pCancelBtn->SetBounds(caButtonArea.GetCentered(C4GUI_DefButtonWdt, C4GUI_ButtonHgt));
77  pCancelBtn->SetToolTip(LoadResStr("IDS_DL_CANCEL"));
78  // resize to actually needed size
79  SetClientSize(GetClientRect().Wdt, GetClientRect().Hgt - caMain.GetHeight());
80 }
81 
83 {
84  // continue query process
85  if (!HTTPClient.Execute())
86  {
87  // query aborted
88  Close(false);
89  return;
90  }
91  if (!HTTPClient.isBusy())
92  {
93  // download done or aborted
94  Close(HTTPClient.isSuccess());
95  return;
96  }
97  StdStrBuf sStatus; int32_t iProgress = -1;
98  StdStrBuf sSize("");
99  // download in progress: Update status
100  if (!HTTPClient.isConnected())
101  {
102  // still connecting
103  sStatus.Ref(LoadResStr("IDS_DL_STATUSCONNECTING"));
104  }
105  else
106  {
107  // header received?
108  size_t iSize = HTTPClient.getTotalSize();
109  if (!iSize)
110  {
111  // file size unknown: No header received.
112  sStatus.Ref(LoadResStr("IDS_PRC_CONNECTED"));
113  }
114  else
115  {
116  // file size known: Download in progress
117  sStatus.Ref(LoadResStr("IDS_CTL_DL_PROGRESS"));
118  if (iSize <= 1024)
119  sSize.Format(" (%ld Bytes)", (long)iSize);
120  else if (iSize <= 1024*1024)
121  sSize.Format(" (%ld KB)", (long)(iSize/1024));
122  else
123  sSize.Format(" (%ld MB)", (long)(iSize/1024/1024));
124  iProgress = int64_t(100) * HTTPClient.getDownloadedSize() / iSize;
125  }
126  }
127  const char *szStatusString = LoadResStr("IDS_PRC_DOWNLOADINGFILE");
128  SetStatus(FormatString(szStatusString, GetFilename(HTTPClient.getURL())).getData(), iProgress );
129 }
130 
132 {
133  // user cancelled
134  HTTPClient.Cancel(LoadResStr("IDS_ERR_USERCANCEL"));
135 }
136 
138 {
139  // own error?
140  if (szError) return szError;
141  // fallback to HTTP error
142  return HTTPClient.GetError();
143 }
144 
145 bool C4DownloadDlg::ShowModal(C4GUI::Screen *pScreen, const char *szURL, const char *szSaveAsFilename)
146 {
147  // reset error
148  szError = nullptr;
149  // initial text
150  if (!HTTPClient.Init()) return false;
151  HTTPClient.SetServer(szURL);
152  // show dlg
153  if (!Show(pScreen, true)) return false;
154  // start query
155  if (!HTTPClient.Query(nullptr, true)) return false;
156  // first time status update
157  OnIdle();
158  // cycle until query is finished or aborted
159  if (!DoModal()) return false;
160  // download successful: Save file
161  if (!HTTPClient.getResultBin().SaveToFile(szSaveAsFilename))
162  {
163  // file saving failed
164  szError = LoadResStr("IDS_FAIL_SAVE");
165  return false;
166  }
167  return true;
168 }
169 
170 bool C4DownloadDlg::DownloadFile(const char *szDLType, C4GUI::Screen *pScreen, const char *szURL, const char *szSaveAsFilename, const char *szNotFoundMessage)
171 {
172  // log it
173  LogF(LoadResStr("IDS_PRC_DOWNLOADINGFILE"), szURL);
174  // show download dialog
175  C4DownloadDlg *pDlg = new C4DownloadDlg(szDLType);
176  if (!pDlg->ShowModal(pScreen, szURL, szSaveAsFilename))
177  {
178  // show an appropriate error
179  const char *szError = pDlg->GetError();
180  if (!szError || !*szError) szError = LoadResStr("IDS_PRC_UNKOWNERROR");
181  StdStrBuf sError;
182  sError.Format(LoadResStr("IDS_PRC_DOWNLOADERROR"), GetFilename(szURL), szError);
183  // it's a 404: display extended message
184  if (SSearch(szError, "404") && szNotFoundMessage)
185  { sError.Append("|"); sError.Append(szNotFoundMessage); }
186  // display message
187  pScreen->ShowMessageModal(sError.getData(), FormatString(LoadResStr("IDS_CTL_DL_TITLE"), szDLType).getData(), C4GUI::MessageDialog::btnOK, C4GUI::Ico_Error, nullptr);
188  delete pDlg;
189  return false;
190  }
191  LogF(LoadResStr("IDS_PRC_DOWNLOADCOMPLETE"), szURL);
192  delete pDlg;
193  return true;
194 }
C4GraphicsResource GraphicsResource
#define C4GUI_ProgressDlgPBHgt
Definition: C4Gui.h:137
#define C4GUI_ProgressDlgWdt
Definition: C4Gui.h:130
#define C4GUI_ButtonAreaHgt
Definition: C4Gui.h:113
#define C4GUI_DefDlgIndent
Definition: C4Gui.h:132
#define C4GUI_MessageFontClr
Definition: C4Gui.h:43
#define C4GUI_IconWdt
Definition: C4Gui.h:93
#define C4GUI_ButtonHgt
Definition: C4Gui.h:111
#define C4GUI_DefButtonWdt
Definition: C4Gui.h:114
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:262
const int ACenter
Definition: C4Surface.h:41
const char * SSearch(const char *szString, const char *szIndex)
Definition: Standard.cpp:369
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
char * GetFilename(char *szPath)
Definition: StdFile.cpp:42
int iSize
Definition: TstC4NetIO.cpp:32
static bool DownloadFile(const char *szDLType, C4GUI::Screen *pScreen, const char *szURL, const char *szSaveAsFilename, const char *szNotFoundMessage=nullptr)
~C4DownloadDlg() override
void UserClose(bool fOK) override
void OnIdle() override
C4DownloadDlg(const char *szDLType)
const char * GetError()
bool ShowModal(C4GUI::Screen *pScreen, const char *szURL, const char *szSaveAsFilename)
void AddElement(Element *pChild)
void Close(bool fOK)
void SetClientSize(int32_t iToWdt, int32_t iToHgt)
bool Show(Screen *pOnScreen, bool fCB)
void SetBounds(const C4Rect &rcNewBound)
Definition: C4Gui.h:446
void SetToolTip(const char *szNewTooltip, bool is_immediate=false)
Definition: C4Gui.cpp:409
void SetText(const char *szToText, bool fAllowHotkey=true)
Definition: C4GuiLabels.cpp:74
void SetProgress(int32_t iToProgress)
Definition: C4Gui.h:578
bool ShowMessageModal(const char *szMessage, const char *szCaption, DWORD dwButtons, Icons icoIcon, int32_t *piConfigDontShowAgainSetting=nullptr)
C4Rect & GetClientRect() override
Definition: C4Gui.h:864
bool isSuccess() const
Definition: C4HTTP.h:88
size_t getTotalSize() const
Definition: C4HTTP.h:89
bool Execute(int iMaxTime=-1, pollfd *readyfds=nullptr) override
Definition: C4HTTP.cpp:59
bool Init()
Definition: C4HTTP.cpp:42
virtual const char * GetError() const
Definition: C4HTTP.h:96
bool SetServer(const char *szServerAddress)
Definition: C4HTTP.cpp:298
bool Query(const StdBuf &Data, bool fBinary)
Definition: C4HTTP.cpp:158
bool isConnected() const
Definition: C4HTTP.h:87
size_t getDownloadedSize() const
Definition: C4HTTP.h:90
const StdBuf & getResultBin() const
Definition: C4HTTP.h:91
const char * getURL() const
Definition: C4HTTP.h:93
bool isBusy() const
Definition: C4HTTP.h:86
void Cancel(const char *szReason)
Definition: C4HTTP.cpp:277
Definition: C4Rect.h:28
std::tuple< std::string, int > BreakMessage(const char *szMsg, int iWdt, bool fCheckMarkup, float fZoom=1.0f)
bool SaveToFile(const char *szFile) const
Definition: StdBuf.cpp:53
void Ref(const char *pnData)
Definition: StdBuf.h:455
const char * getData() const
Definition: StdBuf.h:442
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:519
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:174
@ Ico_NetWait
Definition: C4Gui.h:644
@ Ico_Error
Definition: C4Gui.h:652