Message box support.
This allows us to display a platform-native dialog for problems which occur early in startup (before we can show a PUI/Canvas dialog). In particular this improves feedback where FG_HOME, FG_DATA or aircraft selection is wrong, all of which happen very early in startup.
This commit is contained in:
parent
7e90c8aa2b
commit
136cd6ac51
10 changed files with 341 additions and 75 deletions
|
@ -21,6 +21,7 @@ set(SOURCES
|
|||
FileDialog.cxx
|
||||
PUIFileDialog.cxx
|
||||
MouseCursor.cxx
|
||||
MessageBox.cxx
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
|
@ -41,6 +42,7 @@ set(HEADERS
|
|||
FileDialog.hxx
|
||||
PUIFileDialog.hxx
|
||||
MouseCursor.hxx
|
||||
MessageBox.hxx
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
|
@ -51,8 +53,14 @@ if(WIN32)
|
|||
endif()
|
||||
|
||||
if (APPLE)
|
||||
list(APPEND HEADERS FGCocoaMenuBar.hxx CocoaFileDialog.hxx CocoaMouseCursor.hxx)
|
||||
list(APPEND SOURCES FGCocoaMenuBar.mm CocoaFileDialog.mm CocoaMouseCursor.mm)
|
||||
list(APPEND HEADERS FGCocoaMenuBar.hxx
|
||||
CocoaFileDialog.hxx
|
||||
CocoaMouseCursor.hxx
|
||||
CocoaAutoreleasePool.hxx)
|
||||
list(APPEND SOURCES FGCocoaMenuBar.mm
|
||||
CocoaFileDialog.mm
|
||||
CocoaMouseCursor.mm
|
||||
CocoaMessageBox.mm)
|
||||
endif()
|
||||
|
||||
flightgear_component(GUI "${SOURCES}" "${HEADERS}")
|
||||
|
|
24
src/GUI/CocoaAutoreleasePool.hxx
Normal file
24
src/GUI/CocoaAutoreleasePool.hxx
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef FG_GUI_COCOA_AUTORELEASE_POOL_HXX
|
||||
#define FG_GUI_COCOA_AUTORELEASE_POOL_HXX
|
||||
|
||||
#include <Foundation/NSAutoreleasePool.h>
|
||||
|
||||
class CocoaAutoreleasePool
|
||||
{
|
||||
public:
|
||||
CocoaAutoreleasePool()
|
||||
{
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
}
|
||||
|
||||
~CocoaAutoreleasePool()
|
||||
{
|
||||
[pool release];
|
||||
}
|
||||
|
||||
private:
|
||||
NSAutoreleasePool* pool;
|
||||
};
|
||||
|
||||
|
||||
#endif // of FG_GUI_COCOA_AUTORELEASE_POOL_HXX
|
42
src/GUI/CocoaMessageBox.mm
Normal file
42
src/GUI/CocoaMessageBox.mm
Normal file
|
@ -0,0 +1,42 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <GUI/CocoaAutoreleasePool.hxx>
|
||||
#include <GUI/MessageBox.hxx>
|
||||
|
||||
static NSString* stdStringToCocoa(const std::string& s)
|
||||
{
|
||||
return [NSString stringWithUTF8String:s.c_str()];
|
||||
}
|
||||
|
||||
flightgear::MessageBoxResult cocoaMessageBox(const std::string& msg,
|
||||
const std::string& text)
|
||||
{
|
||||
CocoaAutoreleasePool pool;
|
||||
NSAlert* alert = [NSAlert alertWithMessageText:stdStringToCocoa(msg)
|
||||
defaultButton:nil /* localized 'ok' */
|
||||
alternateButton:nil
|
||||
otherButton:nil
|
||||
informativeTextWithFormat:@"%@",stdStringToCocoa(text)];
|
||||
[[alert retain] autorelease];
|
||||
[alert runModal];
|
||||
return flightgear::MSG_BOX_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
flightgear::MessageBoxResult cocoaFatalMessage(const std::string& msg,
|
||||
const std::string& text)
|
||||
{
|
||||
CocoaAutoreleasePool pool;
|
||||
NSAlert* alert = [NSAlert alertWithMessageText:stdStringToCocoa(msg)
|
||||
defaultButton:@"Quit FlightGear"
|
||||
alternateButton:nil
|
||||
otherButton:nil
|
||||
informativeTextWithFormat:@"%@", stdStringToCocoa(text)];
|
||||
[[alert retain] autorelease];
|
||||
[alert runModal];
|
||||
return flightgear::MSG_BOX_OK;
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
#include <map>
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <GUI/CocoaAutoreleasePool.hxx>
|
||||
|
||||
class CocoaMouseCursor::CocoaMouseCursorPrivate
|
||||
{
|
||||
|
@ -84,7 +85,8 @@ void CocoaMouseCursor::setCursor(Cursor aCursor)
|
|||
if (aCursor == d->activeCursorKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
CocoaAutoreleasePool pool;
|
||||
d->activeCursorKey = aCursor;
|
||||
if (d->cursors.find(aCursor) == d->cursors.end()) {
|
||||
d->cursors[aCursor] = cocoaCursorForKey(aCursor);
|
||||
|
@ -96,6 +98,7 @@ void CocoaMouseCursor::setCursor(Cursor aCursor)
|
|||
|
||||
void CocoaMouseCursor::setCursorVisible(bool aVis)
|
||||
{
|
||||
CocoaAutoreleasePool pool;
|
||||
if (aVis) {
|
||||
[NSCursor unhide];
|
||||
} else {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <simgear/misc/strutils.hxx>
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <GUI/CocoaAutoreleasePool.hxx>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
@ -69,18 +70,29 @@ static NSString* stdStringToCocoa(const string& s)
|
|||
return [NSString stringWithUTF8String:s.c_str()];
|
||||
}
|
||||
|
||||
static void setFunctionKeyShortcut(NSMenuItem* item, unichar shortcut)
|
||||
static void setFunctionKeyShortcut(const std::string& shortcut, NSMenuItem* item)
|
||||
{
|
||||
unichar shortcutChar = NSF1FunctionKey;
|
||||
if (shortcut == "F11") {
|
||||
shortcutChar = NSF11FunctionKey;
|
||||
} else if (shortcut == "F12") {
|
||||
shortcutChar = NSF12FunctionKey;
|
||||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "CocoaMenu:setFunctionKeyShortcut: unsupported:" << shortcut);
|
||||
}
|
||||
|
||||
unichar ch[1];
|
||||
ch[0] = shortcut;
|
||||
ch[0] = shortcutChar;
|
||||
[item setKeyEquivalentModifierMask:NSFunctionKeyMask];
|
||||
[item setKeyEquivalent:[NSString stringWithCharacters:ch length:1]];
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void setItemShortcutFromString(NSMenuItem* item, const string& s)
|
||||
{
|
||||
const char* shortcut = "";
|
||||
std::string shortcut;
|
||||
|
||||
bool hasCtrl = strutils::starts_with(s, "Ctrl-");
|
||||
bool hasShift = strutils::starts_with(s, "Shift-");
|
||||
|
@ -91,21 +103,17 @@ static void setItemShortcutFromString(NSMenuItem* item, const string& s)
|
|||
if (hasCtrl) offset += 5;
|
||||
if (hasAlt) offset += 4;
|
||||
|
||||
shortcut = s.c_str() + offset;
|
||||
if (!strcmp(shortcut, "Esc"))
|
||||
shortcut = s.substr(offset);
|
||||
if (shortcut == "Esc")
|
||||
shortcut = "\e";
|
||||
|
||||
if (!strcmp(shortcut, "F11")) {
|
||||
setFunctionKeyShortcut(item, NSF11FunctionKey);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcmp(shortcut, "F12")) {
|
||||
setFunctionKeyShortcut(item, NSF12FunctionKey);
|
||||
return;
|
||||
}
|
||||
|
||||
[item setKeyEquivalent:[NSString stringWithCString:shortcut encoding:NSUTF8StringEncoding]];
|
||||
if ((shortcut.length() >= 2) && (shortcut[0] == 'F') && isdigit(shortcut[1])) {
|
||||
setFunctionKeyShortcut(shortcut, item);
|
||||
return;
|
||||
}
|
||||
|
||||
simgear::strutils::lowercase(shortcut);
|
||||
[item setKeyEquivalent:[NSString stringWithCString:shortcut.c_str() encoding:NSUTF8StringEncoding]];
|
||||
NSUInteger modifiers = 0;
|
||||
if (hasCtrl) modifiers |= NSControlKeyMask;
|
||||
if (hasShift) modifiers |= NSShiftKeyMask;
|
||||
|
@ -115,23 +123,7 @@ static void setItemShortcutFromString(NSMenuItem* item, const string& s)
|
|||
}
|
||||
|
||||
namespace {
|
||||
class CocoaAutoreleasePool
|
||||
{
|
||||
public:
|
||||
CocoaAutoreleasePool()
|
||||
{
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
}
|
||||
|
||||
~CocoaAutoreleasePool()
|
||||
{
|
||||
[pool release];
|
||||
}
|
||||
|
||||
private:
|
||||
NSAutoreleasePool* pool;
|
||||
};
|
||||
|
||||
|
||||
class CocoaEnabledListener : public SGPropertyChangeListener
|
||||
{
|
||||
public:
|
||||
|
|
148
src/GUI/MessageBox.cxx
Normal file
148
src/GUI/MessageBox.cxx
Normal file
|
@ -0,0 +1,148 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <simgear/simgear_config.h>
|
||||
|
||||
#include "MessageBox.hxx"
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Viewer/renderer.hxx>
|
||||
|
||||
#include <osgViewer/Viewer>
|
||||
|
||||
#include <simgear/structure/commands.hxx>
|
||||
|
||||
#ifdef SG_WINDOWS
|
||||
#include <windows.h>
|
||||
|
||||
#include <osgViewer/GraphicsWindow>
|
||||
#include <osgViewer/api/Win32/GraphicsWindowWin32>
|
||||
#endif
|
||||
|
||||
#if defined(SG_MAC)
|
||||
|
||||
// externs from CocoaMessageBox.mm
|
||||
flightgear::MessageBoxResult
|
||||
cocoaFatalMessage(const std::string& msg, const std::string& text);
|
||||
|
||||
flightgear::MessageBoxResult
|
||||
cocoaMessageBox(const std::string& msg, const std::string& text);
|
||||
|
||||
#endif
|
||||
|
||||
using namespace simgear::strutils;
|
||||
|
||||
namespace {
|
||||
|
||||
bool isCanvasImplementationRegistered()
|
||||
{
|
||||
SGCommandMgr* cmd = globals->get_commands();
|
||||
return (cmd->getCommand("canvas-message-box") != NULL);
|
||||
}
|
||||
|
||||
#if defined(SG_WINDOWS)
|
||||
|
||||
HWND getMainViewerHWND()
|
||||
{
|
||||
osgViewer::Viewer::Windows windows;
|
||||
if (!globals->get_renderer() || !globals->get_renderer()->getViewer()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
globals->get_renderer()->getViewer()->getWindows(windows);
|
||||
osgViewer::Viewer::Windows::const_iterator it = windows.begin();
|
||||
for(; it != windows.end(); ++it) {
|
||||
if (strcmp((*it)->className(), "GraphicsWindowWin32")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
osgViewer::GraphicsWindowWin32* platformWin =
|
||||
static_cast<osgViewer::GraphicsWindowWin32*>(*it);
|
||||
return platformWin->getHWND();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
flightgear::MessageBoxResult
|
||||
win32MessageBox(const std::string& caption,
|
||||
const std::string& msg,
|
||||
const std::string& moreText)
|
||||
{
|
||||
// during early startup (aircraft / fg-data validation) there is no
|
||||
// osgViewer so no HWND.
|
||||
HWND ownerWindow = getMainViewerHWND();
|
||||
std::string fullMsg(msg);
|
||||
if (!moreText.empty()) {
|
||||
fullMsg += "\n\n" + moreText;
|
||||
}
|
||||
|
||||
UINT mbType = MB_OK;
|
||||
WCharVec wMsg(convertUtf8ToWString(fullMsg)),
|
||||
wCap(convertUtf8ToWString(caption));
|
||||
wMsg.push_back(0);
|
||||
wCap.push_back(0);
|
||||
|
||||
::MessageBoxExW(ownerWindow, wMsg.data(), wCap.data(),
|
||||
mbType, 0 /* system lang */);
|
||||
|
||||
return flightgear::MSG_BOX_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
|
||||
MessageBoxResult modalMessageBox(const std::string& caption,
|
||||
const std::string& msg,
|
||||
const std::string& moreText)
|
||||
{
|
||||
// prefer canvas
|
||||
if (isCanvasImplementationRegistered()) {
|
||||
SGPropertyNode_ptr args(new SGPropertyNode);
|
||||
args->setStringValue("caption", caption);
|
||||
args->setStringValue("message", msg);
|
||||
args->setStringValue("more", moreText);
|
||||
globals->get_commands()->execute("canvas-message-box", args);
|
||||
|
||||
// how to make it modal?
|
||||
|
||||
return MSG_BOX_OK;
|
||||
}
|
||||
|
||||
#if defined(SG_WINDOWS)
|
||||
return win32MessageBox(caption, msg, moreText);
|
||||
#elif defined(SG_MAC)
|
||||
return cocoaFatalMessage(msg, moreText);
|
||||
#else
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, caption << ":" << msg);
|
||||
if (!moreText.empty()) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "(" << moreText << ")");
|
||||
}
|
||||
return MSG_BOX_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
MessageBoxResult fatalMessageBox(const std::string& caption,
|
||||
const std::string& msg,
|
||||
const std::string& moreText)
|
||||
{
|
||||
#if defined(SG_WINDOWS)
|
||||
return win32MessageBox(caption, msg, moreText);
|
||||
#elif defined(SG_MAC)
|
||||
return cocoaFatalMessage(msg, moreText);
|
||||
#else
|
||||
std::cerr << "FATAL:" << msg << "\n";
|
||||
if (!moreText.empty()) {
|
||||
std::cerr << "(" << moreText << ")";
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
return MSG_BOX_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // of namespace flightgear
|
26
src/GUI/MessageBox.hxx
Normal file
26
src/GUI/MessageBox.hxx
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef FG_GUI_MESSAGE_BOX_HXX
|
||||
#define FG_GUI_MESSAGE_BOX_HXX
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
|
||||
enum MessageBoxResult
|
||||
{
|
||||
MSG_BOX_OK,
|
||||
MSG_BOX_YES,
|
||||
MSG_BOX_NO
|
||||
};
|
||||
|
||||
MessageBoxResult modalMessageBox(const std::string& caption,
|
||||
const std::string& msg,
|
||||
const std::string& moreText = std::string());
|
||||
|
||||
MessageBoxResult fatalMessageBox(const std::string& caption,
|
||||
const std::string& msg,
|
||||
const std::string& moreText = std::string());
|
||||
|
||||
} // of namespace flightgear
|
||||
|
||||
#endif // of FG_GUI_MESSAGE_BOX_HXX
|
|
@ -57,12 +57,16 @@ using std::endl;
|
|||
|
||||
#include <Viewer/fgviewer.hxx>
|
||||
#include "main.hxx"
|
||||
#include "globals.hxx"
|
||||
#include "fg_props.hxx"
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <GUI/MessageBox.hxx>
|
||||
|
||||
#include "fg_os.hxx"
|
||||
|
||||
#if defined(SG_MAC)
|
||||
#include <Carbon/Carbon.h>
|
||||
#endif
|
||||
|
||||
std::string homedir;
|
||||
std::string hostname;
|
||||
|
||||
|
@ -120,7 +124,7 @@ static void initFPE()
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) || defined(_WIN32)
|
||||
#if defined(SG_WINDOWS)
|
||||
int main ( int argc, char **argv );
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||
LPSTR lpCmdLine, int nCmdShow) {
|
||||
|
@ -141,7 +145,7 @@ int _bootstrap_OSInit;
|
|||
// Main entry point; catch any exceptions that have made it this far.
|
||||
int main ( int argc, char **argv )
|
||||
{
|
||||
#if defined(_MSC_VER) || defined(_WIN32)
|
||||
#if defined(SG_WINDOWS)
|
||||
// Don't show blocking "no disk in drive" error messages on Windows 7,
|
||||
// silently return errors to application instead.
|
||||
// See Microsoft MSDN #ms680621: "GUI apps should specify SEM_NOOPENFILEERRORBOX"
|
||||
|
@ -157,6 +161,14 @@ int main ( int argc, char **argv )
|
|||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
#if defined(SG_MAC)
|
||||
// required so native messages boxes work prior to osgViewer init
|
||||
// (only needed when not running as a bundled app)
|
||||
ProcessSerialNumber sn = { 0, kCurrentProcess };
|
||||
TransformProcessType(&sn,kProcessTransformToForegroundApplication);
|
||||
SetFrontProcess(&sn);
|
||||
#endif
|
||||
|
||||
#ifdef PTW32_STATIC_LIB
|
||||
// Initialise static pthread win32 lib
|
||||
pthread_win32_process_attach_np ();
|
||||
|
@ -208,19 +220,15 @@ int main ( int argc, char **argv )
|
|||
|
||||
|
||||
} catch (const sg_throwable &t) {
|
||||
// We must use cerr rather than
|
||||
// logging, since logging may be
|
||||
// disabled.
|
||||
cerr << "Fatal error: " << t.getFormattedMessage() << endl;
|
||||
std::string info;
|
||||
if (std::strlen(t.getOrigin()) != 0)
|
||||
cerr << " (received from " << t.getOrigin() << ')' << endl;
|
||||
info = std::string("received from ") + t.getOrigin();
|
||||
flightgear::fatalMessageBox("Fatal exception", t.getFormattedMessage(), info);
|
||||
|
||||
} catch (const std::exception &e ) {
|
||||
cerr << "Fatal error (std::exception): " << e.what() << endl;
|
||||
|
||||
flightgear::fatalMessageBox("Fatal exception", e.what());
|
||||
} catch (const std::string &s) {
|
||||
cerr << "Fatal error (std::string): " << s << endl;
|
||||
|
||||
flightgear::fatalMessageBox("Fatal exception", s);
|
||||
} catch (const char *s) {
|
||||
cerr << "Fatal error (const char*): " << s << endl;
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
#include <Canvas/canvas_mgr.hxx>
|
||||
#include <Canvas/gui_mgr.hxx>
|
||||
#include <GUI/new_gui.hxx>
|
||||
#include <GUI/MessageBox.hxx>
|
||||
#include <Input/input.hxx>
|
||||
#include <Instrumentation/instrument_mgr.hxx>
|
||||
#include <Model/acmodel.hxx>
|
||||
|
@ -127,17 +128,13 @@ using namespace boost::algorithm;
|
|||
string fgBasePackageVersion() {
|
||||
SGPath base_path( globals->get_fg_root() );
|
||||
base_path.append("version");
|
||||
|
||||
if (!base_path.exists()) {
|
||||
return string();
|
||||
}
|
||||
|
||||
sg_gzifstream in( base_path.str() );
|
||||
if ( !in.is_open() ) {
|
||||
SGPath old_path( globals->get_fg_root() );
|
||||
old_path.append( "Thanks" );
|
||||
sg_gzifstream old( old_path.str() );
|
||||
if ( !old.is_open() ) {
|
||||
return "[none]";
|
||||
} else {
|
||||
return "[old version]";
|
||||
}
|
||||
if (!in.is_open()) {
|
||||
return string();
|
||||
}
|
||||
|
||||
string version;
|
||||
|
@ -219,6 +216,7 @@ public:
|
|||
{
|
||||
std::string aircraft = fgGetString( "/sim/aircraft", "");
|
||||
if (aircraft.empty()) {
|
||||
flightgear::fatalMessageBox("No aircraft", "No aircraft was specified");
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "no aircraft specified");
|
||||
return false;
|
||||
}
|
||||
|
@ -236,6 +234,9 @@ public:
|
|||
readProperties(setFile.str(), globals->get_props());
|
||||
} catch ( const sg_exception &e ) {
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Error reading aircraft: " << e.getFormattedMessage());
|
||||
flightgear::fatalMessageBox("Error reading aircraft",
|
||||
"An error occured reading the requested aircraft (" + aircraft + ")",
|
||||
e.getFormattedMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -243,6 +244,9 @@ public:
|
|||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "aircraft '" << _searchAircraft <<
|
||||
"' not found in specified dir:" << aircraftDir);
|
||||
flightgear::fatalMessageBox("Aircraft not found",
|
||||
"The requested aircraft '" + aircraft + "' could not be found in the specified location.",
|
||||
aircraftDir);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -262,6 +266,9 @@ public:
|
|||
|
||||
if (_foundPath.str().empty()) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Cannot find specified aircraft: " << aircraft );
|
||||
flightgear::fatalMessageBox("Aircraft not found",
|
||||
"The requested aircraft '" + aircraft + "' could not be found in any of the search paths");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -276,6 +283,9 @@ public:
|
|||
readProperties(_foundPath.str(), globals->get_props());
|
||||
} catch ( const sg_exception &e ) {
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Error reading aircraft: " << e.getFormattedMessage());
|
||||
flightgear::fatalMessageBox("Error reading aircraft",
|
||||
"An error occured reading the requested aircraft (" + aircraft + ")",
|
||||
e.getFormattedMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,8 +50,11 @@
|
|||
#include <simgear/sound/soundmgr_openal.hxx>
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
#include <Autopilot/route_mgr.hxx>
|
||||
#include <GUI/gui.h>
|
||||
|
||||
#include <GUI/gui.h>
|
||||
#include <GUI/MessageBox.hxx>
|
||||
|
||||
#include <Main/locale.hxx>
|
||||
#include "globals.hxx"
|
||||
#include "fg_init.hxx"
|
||||
#include "fg_props.hxx"
|
||||
|
@ -2289,21 +2292,23 @@ void Options::setupRoot()
|
|||
// validate it
|
||||
static char required_version[] = FLIGHTGEAR_VERSION;
|
||||
string base_version = fgBasePackageVersion();
|
||||
if ( !(base_version == required_version) ) {
|
||||
// tell the operator how to use this application
|
||||
|
||||
simgear::requestConsole(); // ensure console is shown on Windows
|
||||
if (base_version.empty()) {
|
||||
flightgear::fatalMessageBox("Base package not found",
|
||||
"Required data files not found, check your installation.",
|
||||
"Looking for base-package files at: '" + root + "'");
|
||||
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (base_version != required_version) {
|
||||
// tell the operator how to use this application
|
||||
|
||||
flightgear::fatalMessageBox("Base package version mismatch",
|
||||
"Version check failed: please check your installation.",
|
||||
"Found data files for version '" + base_version +
|
||||
"' at '" + globals->get_fg_root() + "', version '"
|
||||
+ required_version + "' is required.");
|
||||
|
||||
cerr << endl << "Base package check failed:" << endl \
|
||||
<< " Version " << base_version << " found at: " \
|
||||
<< globals->get_fg_root() << endl \
|
||||
<< " Version " << required_version << " is required." << endl \
|
||||
<< "Please upgrade/downgrade base package and set the path to your fgdata" << endl \
|
||||
<< "with --fg-root=path_to_your_fgdata" << endl;
|
||||
#ifdef _MSC_VER
|
||||
cerr << "Hit a key to continue..." << endl;
|
||||
cin.get();
|
||||
#endif
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue