mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 04:27:37 +00:00
616 lines
20 KiB
C++
616 lines
20 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 2002
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Conrad Carlen <ccarlen@netscape.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#include "UDownloadDisplay.h"
|
|
#include "ApplIDs.h"
|
|
#include "CIconServicesIcon.h"
|
|
|
|
// Gecko
|
|
#include "nsString.h"
|
|
#include "nsILocalFileMac.h"
|
|
|
|
// Std
|
|
#include <algorithm>
|
|
using namespace std;
|
|
|
|
// PowerPlant
|
|
#include <LStaticText.h>
|
|
#include <LProgressBar.h>
|
|
|
|
//*****************************************************************************
|
|
// CMultiDownloadProgress
|
|
//*****************************************************************************
|
|
#pragma mark [CMultiDownloadProgress]
|
|
|
|
bool CMultiDownloadProgress::sRegisteredViewClasses = false;
|
|
|
|
CMultiDownloadProgress::CMultiDownloadProgress() :
|
|
mWindow(nil)
|
|
{
|
|
if (!sRegisteredViewClasses) {
|
|
RegisterClass_(CMultiDownloadProgressWindow);
|
|
RegisterClass_(CDownloadProgressView);
|
|
RegisterClass_(CIconServicesIcon);
|
|
sRegisteredViewClasses = true;
|
|
}
|
|
}
|
|
|
|
CMultiDownloadProgress::~CMultiDownloadProgress()
|
|
{
|
|
}
|
|
|
|
void CMultiDownloadProgress::AddDownloadItem(CDownload *aDownloadItem)
|
|
{
|
|
if (!mWindow) {
|
|
mWindow = static_cast<CMultiDownloadProgressWindow*>
|
|
(LWindow::CreateWindow(wind_DownloadProgress, this));
|
|
ThrowIfNil_(mWindow);
|
|
|
|
// Add this as a listener to the window so we can know when it's destroyed.
|
|
mWindow->AddListener(this);
|
|
}
|
|
|
|
// Create the view...
|
|
LView::SetDefaultView(mWindow);
|
|
LCommander::SetDefaultCommander(mWindow);
|
|
LAttachable::SetDefaultAttachable(nil);
|
|
|
|
CDownloadProgressView *itemView = static_cast<CDownloadProgressView*>
|
|
(UReanimator::ReadObjects(ResType_PPob, view_DownloadProgressItem));
|
|
ThrowIfNil_(itemView);
|
|
|
|
// and add it to the window.
|
|
mWindow->AddDownloadView(itemView);
|
|
itemView->SetDownload(aDownloadItem);
|
|
}
|
|
|
|
// This happens in response to the window being closed. Check for active
|
|
// downloads and confirm stopping them if there are any. Returning false
|
|
// will prevent the window from being closed.
|
|
Boolean CMultiDownloadProgress::AllowSubRemoval(LCommander* inSub)
|
|
{
|
|
return (!mWindow || (inSub == mWindow && mWindow->ConfirmClose()));
|
|
}
|
|
|
|
// This happens in response to the app being quit. Check for active
|
|
// downloads and confirm stopping them if there are any. Returning
|
|
// false will prevent the app from quitting.
|
|
Boolean CMultiDownloadProgress::AttemptQuitSelf(SInt32 inSaveOption)
|
|
{
|
|
return (!mWindow || mWindow->ConfirmClose());
|
|
}
|
|
|
|
void CMultiDownloadProgress::ListenToMessage(MessageT inMessage,
|
|
void* ioParam)
|
|
{
|
|
if (inMessage == msg_BroadcasterDied &&
|
|
(CMultiDownloadProgressWindow*)((LBroadcaster*)ioParam) == mWindow)
|
|
mWindow = nil;
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
// CMultiDownloadProgressWindow
|
|
//*****************************************************************************
|
|
#pragma mark -
|
|
#pragma mark [CMultiDownloadProgressWindow]
|
|
|
|
CMultiDownloadProgressWindow::CMultiDownloadProgressWindow() :
|
|
mDownloadViewCount(0)
|
|
{
|
|
StartBroadcasting();
|
|
}
|
|
|
|
CMultiDownloadProgressWindow::CMultiDownloadProgressWindow(LStream* inStream) :
|
|
LWindow(inStream),
|
|
mDownloadViewCount(0)
|
|
{
|
|
StartBroadcasting();
|
|
}
|
|
|
|
CMultiDownloadProgressWindow::~CMultiDownloadProgressWindow()
|
|
{
|
|
}
|
|
|
|
void CMultiDownloadProgressWindow::AddDownloadView(CDownloadProgressView *aView)
|
|
{
|
|
const SInt16 kSeparatorHeight = 3;
|
|
|
|
SDimension16 currSize;
|
|
GetFrameSize(currSize);
|
|
|
|
SDimension16 viewSize;
|
|
aView->GetFrameSize(viewSize);
|
|
ResizeWindowTo(currSize.width, (viewSize.height * (mDownloadViewCount + 1)) - kSeparatorHeight);
|
|
|
|
aView->PlaceInSuperFrameAt(0, viewSize.height * mDownloadViewCount++, false);
|
|
aView->FinishCreate();
|
|
}
|
|
|
|
void CMultiDownloadProgressWindow::RemoveDownloadView(CDownloadProgressView *aView)
|
|
{
|
|
// We can't remove the last view, leaving an empty window frame
|
|
if (mDownloadViewCount <= 1)
|
|
return;
|
|
|
|
SDimension16 removedPaneSize;
|
|
aView->GetFrameSize(removedPaneSize);
|
|
SPoint32 removedPaneLoc;
|
|
aView->GetFrameLocation(removedPaneLoc);
|
|
|
|
delete aView;
|
|
RemoveSubPane(aView);
|
|
mDownloadViewCount--;
|
|
|
|
TArrayIterator<LPane*> iterator(GetSubPanes());
|
|
LPane *subPane;
|
|
while (iterator.Next(subPane)) {
|
|
SPoint32 subPaneLoc;
|
|
subPane->GetFrameLocation(subPaneLoc);
|
|
if (subPaneLoc.v >= removedPaneLoc.v + removedPaneSize.height) {
|
|
subPane->MoveBy(0, -removedPaneSize.height, true);
|
|
}
|
|
}
|
|
ResizeWindowBy(0, -removedPaneSize.height);
|
|
}
|
|
|
|
Boolean CMultiDownloadProgressWindow::ConfirmClose()
|
|
{
|
|
Boolean canClose = true;
|
|
SInt32 numActiveDownloads = 0;
|
|
|
|
TArrayIterator<LPane*> iterator(GetSubPanes());
|
|
LPane *subPane;
|
|
while (iterator.Next(subPane)) {
|
|
CDownloadProgressView *downloadView = dynamic_cast<CDownloadProgressView*>(subPane);
|
|
if (downloadView && downloadView->IsActive())
|
|
numActiveDownloads++;
|
|
}
|
|
|
|
if (numActiveDownloads != 0) {
|
|
short itemHit;
|
|
AlertStdAlertParamRec pb;
|
|
|
|
pb.movable = false;
|
|
pb.helpButton = false;
|
|
pb.filterProc = nil;
|
|
pb.defaultText = (StringPtr) kAlertDefaultOKText;
|
|
pb.cancelText = (StringPtr) kAlertDefaultCancelText;
|
|
pb.otherText = nil;
|
|
pb.defaultButton = kStdOkItemIndex;
|
|
pb.cancelButton = kStdCancelItemIndex;
|
|
pb.position = kWindowAlertPositionParentWindowScreen;
|
|
|
|
LStr255 msgString(STRx_StdAlertStrings, str_ConfirmCloseDownloads);
|
|
LStr255 explainString(STRx_StdAlertStrings, str_ConfirmCloseDownloadsExp);
|
|
::StandardAlert(kAlertStopAlert, msgString, explainString, &pb, &itemHit);
|
|
if (itemHit != kAlertStdAlertOKButton)
|
|
canClose = false;
|
|
}
|
|
return canClose;
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
// CDownloadProgressView
|
|
//*****************************************************************************
|
|
#pragma mark -
|
|
#pragma mark [CDownloadProgressView]
|
|
|
|
enum {
|
|
paneID_ProgressBar = 'Prog',
|
|
paneID_CancelButton = 'Cncl',
|
|
paneID_OpenButton = 'Open',
|
|
paneID_RevealButton = 'Rvel',
|
|
paneID_CloseButton = 'Clos',
|
|
paneID_StatusText = 'Stat',
|
|
paneID_StatusLabel = 'StLa',
|
|
paneID_TimeRemText = 'Time',
|
|
paneID_TimeRemLabel = 'TiLa',
|
|
paneID_SrcURIText = 'SURI',
|
|
paneID_SrcURILabel = 'SULa',
|
|
paneID_DestFileText = 'Dest',
|
|
paneID_DestFileLabel = 'DFLa'
|
|
};
|
|
|
|
CDownloadProgressView::CDownloadProgressView() :
|
|
mDownloadActive(false)
|
|
{
|
|
}
|
|
|
|
CDownloadProgressView::CDownloadProgressView(LStream* inStream) :
|
|
LView(inStream),
|
|
mDownloadActive(false)
|
|
{
|
|
}
|
|
|
|
CDownloadProgressView::~CDownloadProgressView()
|
|
{
|
|
if (mDownloadActive)
|
|
CancelDownload();
|
|
|
|
mDownload = nsnull;
|
|
}
|
|
|
|
void CDownloadProgressView::FinishCreateSelf()
|
|
{
|
|
mProgressBar = dynamic_cast<LProgressBar*>(FindPaneByID(paneID_ProgressBar));
|
|
mCancelButton = dynamic_cast<LControl*>(FindPaneByID(paneID_CancelButton));
|
|
mOpenButton = dynamic_cast<LControl*>(FindPaneByID(paneID_OpenButton));
|
|
mRevealButton = dynamic_cast<LControl*>(FindPaneByID(paneID_RevealButton));
|
|
mCloseButton = dynamic_cast<LControl*>(FindPaneByID(paneID_CloseButton));
|
|
mStatusText = dynamic_cast<LStaticText*>(FindPaneByID(paneID_StatusText));
|
|
mTimeRemainingText = dynamic_cast<LStaticText*>(FindPaneByID(paneID_TimeRemText));
|
|
mSrcURIText = dynamic_cast<LStaticText*>(FindPaneByID(paneID_SrcURIText));
|
|
mDestFileText = dynamic_cast<LStaticText*>(FindPaneByID(paneID_DestFileText));
|
|
|
|
// The control value is set in terms of percent
|
|
if (mProgressBar)
|
|
mProgressBar->SetMaxValue(100);
|
|
|
|
ControlFontStyleRec styleRec;
|
|
|
|
if (CreateStyleRecFromThemeFont(kThemeSmallSystemFont, styleRec) == noErr) {
|
|
if (mStatusText)
|
|
mStatusText->SetFontStyle(styleRec);
|
|
if (mTimeRemainingText)
|
|
mTimeRemainingText->SetFontStyle(styleRec);
|
|
if (mSrcURIText)
|
|
mSrcURIText->SetFontStyle(styleRec);
|
|
if (mDestFileText)
|
|
mDestFileText->SetFontStyle(styleRec);
|
|
}
|
|
if (CreateStyleRecFromThemeFont(kThemeSmallEmphasizedSystemFont, styleRec) == noErr) {
|
|
|
|
ResIDT labelIDs [] = { paneID_StatusLabel,
|
|
paneID_TimeRemLabel,
|
|
paneID_SrcURILabel,
|
|
paneID_DestFileLabel };
|
|
|
|
for (size_t i = 0; i < sizeof(labelIDs) / sizeof(labelIDs[0]); i++) {
|
|
LStaticText *staticText = dynamic_cast<LStaticText*>(FindPaneByID(labelIDs[i]));
|
|
if (staticText)
|
|
staticText->SetFontStyle(styleRec);
|
|
}
|
|
}
|
|
|
|
UReanimator::LinkListenerToControls(this, this, view_DownloadProgressItem);
|
|
StartListening();
|
|
}
|
|
|
|
|
|
Boolean CDownloadProgressView::ObeyCommand(CommandT inCommand,
|
|
void *ioParam)
|
|
{
|
|
#pragma unused(ioParam)
|
|
|
|
Boolean cmdHandled = false;
|
|
nsCOMPtr<nsILocalFile> targetFile;
|
|
|
|
switch (inCommand)
|
|
{
|
|
case paneID_CancelButton:
|
|
{
|
|
CancelDownload();
|
|
cmdHandled = true;
|
|
}
|
|
break;
|
|
|
|
case paneID_OpenButton:
|
|
{
|
|
mDownload->GetTarget(getter_AddRefs(targetFile));
|
|
if (targetFile)
|
|
targetFile->Launch();
|
|
}
|
|
break;
|
|
|
|
case paneID_RevealButton:
|
|
{
|
|
mDownload->GetTarget(getter_AddRefs(targetFile));
|
|
if (targetFile)
|
|
targetFile->Reveal();
|
|
}
|
|
break;
|
|
|
|
case paneID_CloseButton:
|
|
{
|
|
LView *view = this, *superView;
|
|
while ((superView = view->GetSuperView()) != nil)
|
|
view = superView;
|
|
CMultiDownloadProgressWindow *multiWindow = dynamic_cast<CMultiDownloadProgressWindow*>(view);
|
|
if (multiWindow)
|
|
multiWindow->RemoveDownloadView(this);
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
return cmdHandled;
|
|
}
|
|
|
|
void CDownloadProgressView::ListenToMessage(MessageT inMessage,
|
|
void* ioParam)
|
|
{
|
|
switch (inMessage) {
|
|
|
|
case CDownload::msg_OnDLStart:
|
|
{
|
|
mDownloadActive = true;
|
|
if (mCancelButton)
|
|
mCancelButton->Enable();
|
|
}
|
|
break;
|
|
|
|
case CDownload::msg_OnDLComplete:
|
|
{
|
|
mDownloadActive = false;
|
|
if (mCancelButton)
|
|
mCancelButton->Disable();
|
|
if (mCloseButton)
|
|
mCloseButton->Enable();
|
|
|
|
CDownload *download = reinterpret_cast<CDownload*>(ioParam);
|
|
nsresult downloadStatus;
|
|
download->GetStatus(downloadStatus);
|
|
|
|
// When saving documents as plain text, we might not get any
|
|
// progress change notifications in which to set the progress bar.
|
|
// Now that the download is done, put the bar in a reasonable state.
|
|
if (mProgressBar) {
|
|
mProgressBar->SetIndeterminateFlag(false, false);
|
|
if (NS_SUCCEEDED(downloadStatus))
|
|
mProgressBar->SetValue(mProgressBar->GetMaxValue());
|
|
else
|
|
mProgressBar->SetValue(0);
|
|
}
|
|
|
|
if (NS_SUCCEEDED(downloadStatus)) {
|
|
if (mOpenButton)
|
|
mOpenButton->Enable();
|
|
}
|
|
if (mRevealButton)
|
|
mRevealButton->Enable();
|
|
if (mTimeRemainingText)
|
|
mTimeRemainingText->SetText(LStr255("\p"));
|
|
}
|
|
break;
|
|
|
|
case CDownload::msg_OnDLProgressChange:
|
|
{
|
|
CDownload::MsgOnDLProgressChangeInfo *info =
|
|
static_cast<CDownload::MsgOnDLProgressChangeInfo*>(ioParam);
|
|
|
|
if (mProgressBar) {
|
|
PRInt32 percentComplete;
|
|
info->mBroadcaster->GetPercentComplete(&percentComplete);
|
|
if (percentComplete != -1 && mProgressBar->IsIndeterminate())
|
|
mProgressBar->SetIndeterminateFlag(false, false);
|
|
else if (percentComplete == -1 && !mProgressBar->IsIndeterminate())
|
|
mProgressBar->SetIndeterminateFlag(true, true);
|
|
|
|
if (!mProgressBar->IsIndeterminate()) {
|
|
PRInt32 controlVal = min(100, max(0, percentComplete));
|
|
mProgressBar->SetValue(controlVal);
|
|
}
|
|
}
|
|
|
|
// Set the progress bar as often as we're called. Smooth movement is nice.
|
|
// Limit the frequency at which the textual status is updated though.
|
|
if (info->mCurProgress == info->mMaxProgress ||
|
|
::TickCount() - mLastStatusUpdateTicks >= kStatusUpdateIntervalTicks) {
|
|
UpdateStatus(info);
|
|
mLastStatusUpdateTicks = ::TickCount();
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ProcessCommand(inMessage, ioParam);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CDownloadProgressView::SetDownload(CDownload *aDownload)
|
|
{
|
|
mDownload = aDownload;
|
|
if (!mDownload)
|
|
return;
|
|
|
|
mDownloadActive = true;
|
|
mLastStatusUpdateTicks = ::TickCount();
|
|
aDownload->AddListener(this);
|
|
|
|
nsresult rv;
|
|
nsCAutoString tempStr;
|
|
|
|
if (mSrcURIText) {
|
|
nsCOMPtr<nsIURI> srcURI;
|
|
aDownload->GetSource(getter_AddRefs(srcURI));
|
|
if (srcURI) {
|
|
rv = srcURI->GetSpec(tempStr);
|
|
if (NS_SUCCEEDED(rv))
|
|
mSrcURIText->SetText(const_cast<Ptr>(PromiseFlatCString(tempStr).get()), tempStr.Length());
|
|
}
|
|
}
|
|
|
|
if (mDestFileText) {
|
|
nsCOMPtr<nsILocalFile> destFile;
|
|
aDownload->GetTarget(getter_AddRefs(destFile));
|
|
if (destFile) {
|
|
rv = destFile->GetNativePath(tempStr);
|
|
if (NS_SUCCEEDED(rv))
|
|
mDestFileText->SetText(const_cast<Ptr>(PromiseFlatCString(tempStr).get()), tempStr.Length());
|
|
}
|
|
}
|
|
|
|
// At this point, make sure our window is showing.
|
|
LWindow::FetchWindowObject(GetMacWindow())->Show();
|
|
}
|
|
|
|
void CDownloadProgressView::CancelDownload()
|
|
{
|
|
CDownload *download = dynamic_cast<CDownload*>(mDownload.get());
|
|
download->Cancel();
|
|
}
|
|
|
|
Boolean CDownloadProgressView::IsActive()
|
|
{
|
|
return mDownloadActive;
|
|
}
|
|
|
|
void CDownloadProgressView::UpdateStatus(CDownload::MsgOnDLProgressChangeInfo *info)
|
|
{
|
|
PRInt64 startTime;
|
|
mDownload->GetStartTime(&startTime);
|
|
PRInt32 elapsedSecs = (PR_Now() - startTime) / PR_USEC_PER_SEC;
|
|
float bytesPerSec = info->mCurProgress / elapsedSecs;
|
|
|
|
UInt8 startPos;
|
|
LStr255 valueStr;
|
|
|
|
if (mStatusText) {
|
|
// "@1 of @2 (at @3/sec)"
|
|
LStr255 formatStr(STRx_DownloadStatus, str_ProgressFormat);
|
|
|
|
// Insert each item into the string individually in order to
|
|
// allow certain elements to be omitted from the format.
|
|
if ((startPos = formatStr.Find("\p@1")) != 0)
|
|
formatStr.Replace(startPos, 2, FormatBytes(info->mCurProgress, valueStr));
|
|
if ((startPos = formatStr.Find("\p@2")) != 0)
|
|
formatStr.Replace(startPos, 2, FormatBytes(info->mMaxProgress, valueStr));
|
|
if ((startPos = formatStr.Find("\p@3")) != 0)
|
|
formatStr.Replace(startPos, 2, FormatBytes(bytesPerSec, valueStr));
|
|
|
|
mStatusText->SetText(formatStr);
|
|
}
|
|
|
|
if (mTimeRemainingText) {
|
|
PRInt32 secsRemaining = (PRInt32)(float(info->mMaxProgress - info->mCurProgress) / bytesPerSec + 0.5);
|
|
mTimeRemainingText->SetText(FormatFuzzyTime(secsRemaining, valueStr));
|
|
}
|
|
}
|
|
|
|
LStr255& CDownloadProgressView::FormatBytes(float inBytes, LStr255& ioString)
|
|
{
|
|
const float kOneThousand24 = 1024.0;
|
|
char buf[256];
|
|
|
|
if (inBytes < 0) {
|
|
return (ioString = "???");
|
|
}
|
|
if (inBytes < kOneThousand24) {
|
|
sprintf(buf, "%.1f Bytes", inBytes);
|
|
return (ioString = buf);
|
|
}
|
|
inBytes /= kOneThousand24;
|
|
if (inBytes < 1024) {
|
|
sprintf(buf, "%.1f KB", inBytes);
|
|
return (ioString = buf);
|
|
}
|
|
inBytes /= kOneThousand24;
|
|
if (inBytes < 1024) {
|
|
sprintf(buf, "%.1f MB", inBytes);
|
|
return (ioString = buf);
|
|
}
|
|
inBytes /= kOneThousand24;
|
|
sprintf(buf, "%.2f GB", inBytes);
|
|
return (ioString = buf);
|
|
}
|
|
|
|
LStr255& CDownloadProgressView::FormatFuzzyTime(PRInt32 inSecs, LStr255& ioString)
|
|
{
|
|
char valueBuf[32];
|
|
|
|
if (inSecs < 90) {
|
|
if (inSecs < 7)
|
|
ioString.Assign(STRx_DownloadStatus, str_About5Seconds);
|
|
else if (inSecs < 13)
|
|
ioString.Assign(STRx_DownloadStatus, str_About10Seconds);
|
|
else if (inSecs < 60)
|
|
ioString.Assign(STRx_DownloadStatus, str_LessThan1Minute);
|
|
else
|
|
ioString.Assign(STRx_DownloadStatus, str_About1Minute);
|
|
return ioString;
|
|
}
|
|
inSecs = (inSecs + 30) / 60; // Round up so we don't say "About 1 minutes"
|
|
if (inSecs < 60) {
|
|
sprintf(valueBuf, "%d", inSecs);
|
|
ioString.Assign(STRx_DownloadStatus, str_AboutNMinutes);
|
|
ioString.Replace(ioString.Find("\p@1"), 2, LStr255(valueBuf));
|
|
return ioString;
|
|
}
|
|
inSecs /= 60;
|
|
if (inSecs == 1)
|
|
ioString.Assign(STRx_DownloadStatus, str_About1Hour);
|
|
else {
|
|
sprintf(valueBuf, "%d", inSecs);
|
|
ioString.Assign(STRx_DownloadStatus, str_AboutNHours);
|
|
ioString.Replace(ioString.Find("\p@1"), 2, LStr255(valueBuf));
|
|
}
|
|
return ioString;
|
|
}
|
|
|
|
OSErr CDownloadProgressView::CreateStyleRecFromThemeFont(ThemeFontID inThemeID,
|
|
ControlFontStyleRec& outStyle)
|
|
{
|
|
Str255 themeFontName;
|
|
SInt16 themeFontSize;
|
|
Style themeStyle;
|
|
SInt16 themeFontNum;
|
|
|
|
OSErr err = ::GetThemeFont(kThemeSmallSystemFont,
|
|
smSystemScript,
|
|
themeFontName,
|
|
&themeFontSize,
|
|
&themeStyle);
|
|
if (err != noErr)
|
|
return err;
|
|
|
|
outStyle.flags = kControlUseFontMask +
|
|
kControlUseFaceMask +
|
|
kControlUseSizeMask;
|
|
|
|
::GetFNum(themeFontName, &themeFontNum);
|
|
outStyle.font = themeFontNum;
|
|
outStyle.size = themeFontSize;
|
|
outStyle.style = themeStyle;
|
|
|
|
return noErr;
|
|
}
|
|
|