FileDialog.cxx
PUIFileDialog.cxx
MouseCursor.cxx
+ MessageBox.cxx
)
set(HEADERS
FileDialog.hxx
PUIFileDialog.hxx
MouseCursor.hxx
+ MessageBox.hxx
)
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}")
--- /dev/null
+#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
\ No newline at end of file
--- /dev/null
+
+#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;
+}
+
#include <map>
#include <Main/globals.hxx>
+#include <GUI/CocoaAutoreleasePool.hxx>
class CocoaMouseCursor::CocoaMouseCursorPrivate
{
if (aCursor == d->activeCursorKey) {
return;
}
-
+
+ CocoaAutoreleasePool pool;
d->activeCursorKey = aCursor;
if (d->cursors.find(aCursor) == d->cursors.end()) {
d->cursors[aCursor] = cocoaCursorForKey(aCursor);
void CocoaMouseCursor::setCursorVisible(bool aVis)
{
+ CocoaAutoreleasePool pool;
if (aVis) {
[NSCursor unhide];
} else {
#include <simgear/misc/strutils.hxx>
#include <Main/fg_props.hxx>
+#include <GUI/CocoaAutoreleasePool.hxx>
#include <iostream>
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-");
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;
}
namespace {
- class CocoaAutoreleasePool
- {
- public:
- CocoaAutoreleasePool()
- {
- pool = [[NSAutoreleasePool alloc] init];
- }
-
- ~CocoaAutoreleasePool()
- {
- [pool release];
- }
-
- private:
- NSAutoreleasePool* pool;
- };
-
+
class CocoaEnabledListener : public SGPropertyChangeListener
{
public:
--- /dev/null
+#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
--- /dev/null
+#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
#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;
}
#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) {
// 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"
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 ();
} 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;
#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>
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;
{
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;
}
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;
}
} 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;
}
}
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;
}
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;
}
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/misc/strutils.hxx>
#include <Autopilot/route_mgr.hxx>
+
#include <GUI/gui.h>
+#include <GUI/MessageBox.hxx>
+#include <Main/locale.hxx>
#include "globals.hxx"
#include "fg_init.hxx"
#include "fg_props.hxx"
// 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
+ 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);
+ }
- simgear::requestConsole(); // ensure console is shown on Windows
-
- 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
+ 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.");
+
exit(-1);
}
}