2
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License as
6
* published by the Free Software Foundation; version 2 of the
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21
* Windows front end implementation of the mforms Utilities APIs.
30
#include "base/string_utilities.h"
31
#include "wf_Utilities.h"
33
using namespace Windows::Forms;
34
using namespace System::Text;
35
using namespace System::Drawing;
36
using namespace System::Threading;
37
using namespace System::Diagnostics;
39
using namespace MySQL::Forms;
40
using namespace MySQL::Utilities;
42
//--------------------------------------------------------------------------------------------------
44
CustomMessageBox::CustomMessageBox()
46
_picture= gcnew Windows::Forms::PictureBox();
47
_button1= gcnew Windows::Forms::Button();
48
_button2= gcnew Windows::Forms::Button();
49
_button3= gcnew Windows::Forms::Button();
50
_messageLabel= gcnew Windows::Forms::Label();
51
_checkbox = gcnew Windows::Forms::CheckBox();
55
Controls->Add(_picture);
56
Controls->Add(_button2);
57
Controls->Add(_button1);
58
Controls->Add(_button3);
59
Controls->Add(_messageLabel);
60
Controls->Add(_checkbox);
63
_picture->Name= "picture";
64
_picture->TabIndex= 0;
65
_picture->TabStop= false;
68
_button1->Name= "button1";
69
_button1->TabIndex= 1;
70
_button1->UseVisualStyleBackColor= true;
71
_button1->Click += gcnew System::EventHandler(this, &CustomMessageBox::ButtonClick);
74
_button2->Name= "button2";
75
_button2->TabIndex= 2;
76
_button2->UseVisualStyleBackColor= true;
77
_button2->Click += gcnew System::EventHandler(this, &CustomMessageBox::ButtonClick);
80
_button3->Name= "button3";
81
_button3->TabIndex= 3;
82
_button3->UseVisualStyleBackColor= true;
83
_button3->Click += gcnew System::EventHandler(this, &CustomMessageBox::ButtonClick);
86
_messageLabel->Name= "messageLabel";
87
_messageLabel->Padding= Windows::Forms::Padding(2);
88
_messageLabel->TabIndex= 4;
89
_messageLabel->Text= "label1";
91
_checkbox->Name = "checkBox";
92
_checkbox->TabIndex = 5;
95
this->Padding= Windows::Forms::Padding(8, 16, 8, 8);
96
this->FormBorderStyle= ::FormBorderStyle::FixedDialog;
97
this->AutoScaleDimensions= System::Drawing::SizeF(6, 13);
98
this->AutoScaleMode= Windows::Forms::AutoScaleMode::Font;
99
this->StartPosition = FormStartPosition::CenterScreen;
100
this->Name= "CustomMessageBox";
102
this->ShowInTaskbar= false;
103
this->HelpButton= false;
104
this->MinimizeBox= false;
105
this->MaximizeBox= false;
106
//this->TopMost= true;
107
this->Owner = UtilitiesImpl::get_mainform();
112
//--------------------------------------------------------------------------------------------------
114
// Some more task dialog icons, which are not defined in commctrl.h.
115
#define TD_SHIELD_BLUE_ICON MAKEINTRESOURCE(-5)
116
#define TD_SECURITY_WARNING_ICON MAKEINTRESOURCE(-6)
117
#define TD_SECURITY_ERROR_ICON MAKEINTRESOURCE(-7)
118
#define TD_SHIELD_SUCCESS_ICON MAKEINTRESOURCE(-8)
119
#define TD_SHIELD_GRAY_ICON MAKEINTRESOURCE(-9)
121
typedef HRESULT (WINAPI *PTaskDialogIndirect)(const TASKDIALOGCONFIG *pTaskConfig,
122
__out_opt int *pnButton, __out_opt int *pnRadioButton, __out_opt BOOL *pfVerificationFlagChecked);
124
mforms::DialogResult CustomMessageBox::ShowVistaStyle(const std::string& title, const std::string& text,
125
PCWSTR mainIcon, const std::string& buttonOK, const std::string& buttonCancel,
126
const std::string& buttonOther, const std::string& checkbox, bool& checked)
128
// Load TaskDialogIndirect dynamically so we don't get a problem on XP.
129
HMODULE comctl32 = LoadLibraryW(L"comctl32.dll");
130
PTaskDialogIndirect _TaskDialogIndirect = (PTaskDialogIndirect) GetProcAddress(comctl32, "TaskDialogIndirect");
132
TASKDIALOGCONFIG config = {0};
133
config.cbSize = sizeof(config);
137
BOOL verificationChecked = FALSE;
140
TASKDIALOG_BUTTON buttons[2];
142
std::wstring do_text = base::string_to_wstring(buttonOK);
143
if (do_text.size() > 0)
145
buttons[buttonCount].nButtonID = IDOK;
146
buttons[buttonCount].pszButtonText = do_text.c_str();
150
// For cancel we show the in-built button, instead creating our own.
151
// Additionally, we enable dialog cancellation.
152
if (buttonCancel.size() > 0)
154
config.dwFlags |= TDF_ALLOW_DIALOG_CANCELLATION;
155
config.dwCommonButtons = TDCBF_CANCEL_BUTTON;
158
std::wstring other_text = base::string_to_wstring(buttonOther);
159
if (other_text.size() > 0)
161
buttons[buttonCount].nButtonID = 1000;
162
buttons[buttonCount].pszButtonText = other_text.c_str();
166
// If we have more than one button to show then enable command links.
168
config.dwFlags |= TDF_USE_COMMAND_LINKS;
170
config.hwndParent = GetForegroundWindow();
172
config.pszMainIcon = mainIcon;
173
config.pszWindowTitle = L"MySQL Workbench";
175
std::wstring titleText= base::string_to_wstring(title);
176
config.pszMainInstruction = titleText.c_str();
177
std::wstring descriptionText= base::string_to_wstring(text);
178
config.pszContent = descriptionText.c_str();
179
config.pButtons = buttons;
180
config.cButtons = buttonCount;
182
std::wstring checkbox_text = base::string_to_wstring(checkbox);
183
if (checkbox_text.size() > 0)
184
config.pszVerificationText = checkbox_text.c_str();
186
HRESULT result = _TaskDialogIndirect(&config, &button, &radioButton, &verificationChecked);
187
if (!SUCCEEDED(result))
188
return mforms::ResultCancel;
190
checked = verificationChecked == TRUE;
194
return mforms::ResultOk;
197
return mforms::ResultCancel;
200
return mforms::ResultOther;
203
FreeLibrary(comctl32);
206
//--------------------------------------------------------------------------------------------------
209
/// Displays the CustomMessageBox and returns a dialog result, depending on the button clicked.
211
mforms::DialogResult CustomMessageBox::ShowTraditionalStyle(String^ title, String^ text, Image^ image, String^ button1,
212
String^ button2, String^ button3, String^ checkbox, bool& checked)
214
CustomMessageBox^ box= gcnew CustomMessageBox();
216
box->_picture->Image= image;
217
box->_picture->Size= image->Size;
219
box->_messageLabel->Text= text;
220
box->_button1->Text= button1;
221
box->_button1->DialogResult = Windows::Forms::DialogResult::OK;
222
box->_button2->Text= button2;
223
box->_button2->DialogResult = Windows::Forms::DialogResult::Cancel;
224
box->_button3->Text= button3;
225
box->_button3->DialogResult = Windows::Forms::DialogResult::Ignore;
226
box->_checkbox->Text = checkbox;
227
box->ComputeLayout();
229
box->AcceptButton = box->_button1;
230
box->CancelButton = box->_button2;
232
Windows::Forms::DialogResult rc = box->ShowDialog();
234
checked = box->_checkbox->Checked;
237
case Windows::Forms::DialogResult::OK:
238
return mforms::ResultOk;
241
case Windows::Forms::DialogResult::Cancel:
242
return mforms::ResultCancel;
244
case Windows::Forms::DialogResult::Ignore:
245
return mforms::ResultOther;
249
//--------------------------------------------------------------------------------------------------
251
// A little helper for repeating a button setup.
252
void AdjustButton(Windows::Forms::Button^ button)
254
// Note: we need to set the Enabled property too as indicator if this button should be considered
255
// when layouting the form. The Visible property cannot be used as long as the button's parent
256
// is still hidden (which is the case when we do the layout process).
257
if (button->Text == "")
259
button->Visible= false;
260
button->Enabled= false;
264
Size size= button->GetPreferredSize(Drawing::Size::Empty);
268
button->Visible= true;
269
button->Enabled= true;
273
//--------------------------------------------------------------------------------------------------
275
#define MESSAGE_BOX_BUTTON_SPACING 8 // The spacing between two message buttons.
276
#define MESSAGE_BOX_MIN_WIDTH 300
277
#define MESSAGE_BOX_MIN_HEIGHT 128
280
* As the name already says this function computes the layout of the message box depending on the
281
* content (image size, button text etc.).
283
void CustomMessageBox::ComputeLayout()
287
// Buttons have a minimum width of 75 px. Make them all same size and hide those which don't have
289
AdjustButton(_button1);
290
AdjustButton(_button2);
291
AdjustButton(_button3);
292
_checkbox->Enabled = _checkbox->Text != "";
293
_checkbox->Visible = _checkbox->Enabled;
295
int visibleButtonCount= 0;
296
System::Drawing::Size size= System::Drawing::Size::Empty;
297
if (_button1->Enabled)
299
size= _button1->Size;
300
visibleButtonCount++;
302
if (_button2->Enabled)
304
size.Height= _button2->Height;
305
if (_button2->Width > size.Width)
306
size.Width= _button2->Width;
307
visibleButtonCount++;
309
if (_button3->Enabled)
311
size.Height= _button3->Height;
312
if (_button3->Width > size.Width)
313
size.Width= _button3->Width;
314
visibleButtonCount++;
317
// For the common height we use the one from the last visible button we found.
318
// Since the font is assumed to be the same for all buttons they also should compute
319
// the same height when asked for their preferred size.
320
// Compute the total size of the button area on the way (including padding of the container).
321
System::Drawing::Size buttonSize= System::Drawing::Size::Empty;
324
// Compute only if there is at least one visible button.
325
buttonSize.Height= size.Height;
326
if (_button1->Enabled)
328
_button1->Size= size;
329
buttonSize.Width= size.Width;
331
if (_button2->Enabled)
333
_button2->Size= size;
334
if (buttonSize.Width > 0)
335
buttonSize.Width += MESSAGE_BOX_BUTTON_SPACING;
336
buttonSize.Width += size.Width;
338
if (_button3->Enabled)
340
_button3->Size= size;
341
if (buttonSize.Width > 0)
342
buttonSize.Width += MESSAGE_BOX_BUTTON_SPACING;
343
buttonSize.Width += size.Width;
346
// For the right spacing between button box and border.
347
buttonSize.Width += MESSAGE_BOX_BUTTON_SPACING;
350
// Additional size if the checkbox is visible.
351
int effective_button_width = buttonSize.Width;
352
if (_checkbox->Enabled)
354
_checkbox->Size = _checkbox->PreferredSize;
355
effective_button_width += Padding.Left + _checkbox->Size.Width + MESSAGE_BOX_BUTTON_SPACING;
358
// Compute message text layout. Start with a certain minimum width.
359
int minWidth= (effective_button_width > MESSAGE_BOX_MIN_WIDTH) ? effective_button_width : MESSAGE_BOX_MIN_WIDTH;
360
System::Drawing::Size proposedSize= System::Drawing::Size(minWidth, 1);
362
// We use the golden ratio to create an appealing layout.
363
// Increase width in 10% steps until we found the proper ratio.
367
size= _messageLabel->GetPreferredSize(proposedSize);
369
// Terminate loop if we get a height of 0, the same width as in the last run, beyond a maximum width
370
// or reached the golden ratio. Getting the same width means we never can get to the golden
371
// ratio as the text is too small.
372
if ((size.Height == 0) || (size.Width == lastWidth) ||
373
(size.Width >= 1000) || ((float) size.Width / size.Height >= 1.618))
376
lastWidth= size.Width;
377
proposedSize.Width += proposedSize.Width / 10;
380
// GetPreferredSize might return a value smaller than our minimum width. Account for that.
381
if (size.Width < minWidth)
382
size.Width= minWidth;
383
_messageLabel->Size= size;
385
// Now that we have the text size compute the overall size of the message box.
386
// The image is vertically centered at the left side (with some padding)
387
// and the buttons are at the bottom (right aligned).
388
int textHeight= _messageLabel->Padding.Vertical + _messageLabel->Height;
389
if (textHeight < _picture->Height + _picture->Padding.Vertical)
390
textHeight= _picture->Height + _picture->Padding.Vertical;
391
size.Width= Padding.Horizontal + _picture->Padding.Horizontal + _picture->Width +
392
_messageLabel->Padding.Horizontal + _messageLabel->Width;
393
size.Height= Padding.Vertical + textHeight + buttonSize.Height;
395
// Make sure we have good looking minimum height.
396
if (size.Height < MESSAGE_BOX_MIN_HEIGHT)
397
size.Height= MESSAGE_BOX_MIN_HEIGHT;
400
// Move picture to its final location (center vertically over the message text's height).
402
location.X= Padding.Left;
403
location.Y= Padding.Top + (textHeight - _picture->Height - _picture->Padding.Vertical) / 2;
404
_picture->Location= location;
406
// Text location too.
407
location.X= _picture->Right + _messageLabel->Padding.Left;
408
location.Y= Padding.Top;
409
_messageLabel->Location= location;
411
// Move the buttons to their final locations.
412
if (buttonSize.Width > 0)
414
location= Point(ClientSize.Width - buttonSize.Width, ClientSize.Height - buttonSize.Height - Padding.Bottom);
415
if (_button1->Enabled)
417
_button1->Location= location;
418
location.X += _button1->Width + MESSAGE_BOX_BUTTON_SPACING;
420
if (_button3->Enabled)
422
_button3->Location= location;
423
location.X += _button3->Width + MESSAGE_BOX_BUTTON_SPACING;
426
// Button 2 is our Cancel button (the one which is triggered when ESC is pressed), so place it last.
427
if (_button2->Enabled)
428
_button2->Location= location;
431
// Display the checkbox on the same line as the buttons but left aligned (if visible).
432
if (_checkbox->Enabled)
434
location.X = Padding.Left;
435
location.Y += (buttonSize.Height - _checkbox->Size.Height) / 2;
436
_checkbox->Location = location;
442
//--------------------------------------------------------------------------------------------------
444
void CustomMessageBox::ButtonClick(Object^ sender, EventArgs^ arguments)
446
DialogResult = ((Windows::Forms::Button^)sender)->DialogResult;
449
//--------------------------------------------------------------------------------------------------
451
mforms::DialogResult CustomMessageBox::Show(const std::string& title, const std::string& text,
452
PCWSTR mainIcon, const std::string& buttonOK, const std::string& buttonCancel,
453
const std::string& buttonOther, const std::string& checkbox, bool& checked)
455
// Our message looks different depending on whether we are running on XP or Vista and above.
456
if (ControlUtilities::IsVistaOrAbove())
458
mforms::Utilities::enter_modal_loop();
459
mforms::DialogResult result = ShowVistaStyle(title, text, mainIcon, buttonOK, buttonCancel,
460
buttonOther, checkbox, checked);
461
mforms::Utilities::leave_modal_loop();
467
String^ boxTitle= CppStringToNative(title);
468
String^ boxText= CppStringToNative(text);
469
String^ ok_text= CppStringToNative(buttonOK);
470
String^ cancel_text= CppStringToNative(buttonCancel);
471
String^ other_text= CppStringToNative(buttonOther);
472
String^ checkbox_text= CppStringToNative(checkbox);
475
if (mainIcon == TD_WARNING_ICON)
476
image= Image::FromFile("images/ui/message_warning.png");
478
if (mainIcon == TD_ERROR_ICON)
479
image= Image::FromFile("images/ui/message_error.png");
481
image= Image::FromFile("images/ui/message_confirm.png");
483
mforms::Utilities::enter_modal_loop();
484
mforms::DialogResult result = CustomMessageBox::ShowTraditionalStyle(boxTitle, boxText, image,
485
ok_text, cancel_text, other_text, checkbox_text, checked);
486
mforms::Utilities::leave_modal_loop();
491
//--------------------------------------------------------------------------------------------------
493
Windows::Forms::DialogResult CustomMessageBox::Show(MessageType type, String^ title, String^ text,
494
String^ buttonOK, String^ buttonCancel, String^ buttonOther, String^ checkbox, [Out] bool% checked)
496
mforms::DialogResult result;
498
// Our message looks different depending on whether we are running on XP or Vista and above.
499
if (ControlUtilities::IsVistaOrAbove())
501
mforms::Utilities::enter_modal_loop();
505
case MessageType::MessageWarning:
506
mainIcon = TD_WARNING_ICON;
508
case MessageType::MessageError:
509
mainIcon = TD_ERROR_ICON;
512
mainIcon = TD_INFORMATION_ICON;
515
bool isChecked = false;
516
result = ShowVistaStyle(
517
NativeToCppString(title), NativeToCppString(text), mainIcon, NativeToCppString(buttonOK),
518
NativeToCppString(buttonCancel), NativeToCppString(buttonOther), NativeToCppString(checkbox),
522
mforms::Utilities::leave_modal_loop();
529
case MessageType::MessageWarning:
530
image= Image::FromFile("images/ui/message_warning.png");
532
case MessageType::MessageError:
533
image= Image::FromFile("images/ui/message_error.png");
536
image= Image::FromFile("images/ui/message_confirm.png");
540
mforms::Utilities::enter_modal_loop();
541
bool isChecked = false;
542
result = CustomMessageBox::ShowTraditionalStyle(title, text, image, buttonOK, buttonCancel,
543
buttonOther, checkbox, isChecked);
545
mforms::Utilities::leave_modal_loop();
548
Windows::Forms::DialogResult native_result;
551
case mforms::ResultCancel:
552
native_result = Windows::Forms::DialogResult::Cancel;
554
case mforms::ResultOther:
555
native_result = Windows::Forms::DialogResult::Ignore;
558
native_result = Windows::Forms::DialogResult::OK;
561
return native_result;
564
//--------------------------------------------------------------------------------------------------
566
Windows::Forms::DialogResult CustomMessageBox::Show(MessageType type, String^ title, String^ text,
569
bool checked = false;
570
return Show(type, title, text, buttonOK, "", "", "", checked);
573
//----------------- DispatchControl ----------------------------------------------------------------
575
delegate InvokationResult^ RunSlotDelegate();
577
void* DispatchControl::RunOnMainThread(const boost::function<void* ()>& slot, bool wait)
579
if (InvokeRequired) // XXX handle wait here (if wait is false, it doesnt need to wait for the callback to finish executing
582
InvokationResult^ result = (InvokationResult^) Invoke(
583
gcnew RunSlotDelegate(this, &DispatchControl::RunSlot));
584
return result->Result;
590
//--------------------------------------------------------------------------------------------------
593
* Helper function to run a given slot in the main thread.
595
InvokationResult^ DispatchControl::RunSlot()
597
return gcnew InvokationResult((*_slot)());
600
//----------------- UtilitiesImpl ------------------------------------------------------------------
602
UtilitiesImpl::UtilitiesImpl()
606
//--------------------------------------------------------------------------------------------------
608
int UtilitiesImpl::show_message(const string &title, const string &text, const string &ok,
609
const string &cancel, const string &other)
612
return CustomMessageBox::Show(title, text, TD_INFORMATION_ICON, ok, cancel, other, "", checked);
615
//--------------------------------------------------------------------------------------------------
617
int UtilitiesImpl::show_error(const string &title, const string &text, const string &ok,
618
const string &cancel, const string &other)
621
return CustomMessageBox::Show(title, text, TD_ERROR_ICON, ok, cancel, other, "", checked);
624
//--------------------------------------------------------------------------------------------------
626
int UtilitiesImpl::show_warning(const string &title, const string &text, const string &ok,
627
const string &cancel, const string &other)
630
return CustomMessageBox::Show(title, text, TD_WARNING_ICON, ok, cancel, other, "", checked);
633
//--------------------------------------------------------------------------------------------------
635
int UtilitiesImpl::show_message_with_checkbox(const string &title, const string &text,
636
const string &ok, const string &cancel, const string &other, const std::string &checkbox_text,
639
std::string checkboxText = (checkbox_text.size() > 0) ? checkbox_text :
640
_("Don't show this message again");
641
return CustomMessageBox::Show(title, text, TD_INFORMATION_ICON, ok, cancel, other, checkboxText,
645
//--------------------------------------------------------------------------------------------------
648
* Shows the warning heads-up-display with the given title and text.
650
void UtilitiesImpl::show_wait_message(const string &title, const string &text)
652
HUDForm::Show(CppStringToNative(title), CppStringToNative(text), true);
655
//--------------------------------------------------------------------------------------------------
658
* Hides a previously shown wait message.
660
bool UtilitiesImpl::hide_wait_message()
662
bool result= HUDForm::IsVisible;
668
//--------------------------------------------------------------------------------------------------
670
ref class CallSlotDelegate
673
CallSlotDelegate(const boost::function<bool ()> *s) : slot(s) {}
674
const boost::function<bool ()> *slot;
681
//-------------------------------------------------------------------------------------------------
683
bool UtilitiesImpl::run_cancelable_wait_message(const string &title, const string &text,
684
const boost::function<void ()> &start_task,
685
const boost::function<bool ()> &cancel_slot)
687
CallSlotDelegate ^caller = gcnew CallSlotDelegate(&cancel_slot);
689
HUDForm::CancelDelegate ^deleg = gcnew HUDForm::CancelDelegate(caller, &CallSlotDelegate::call_slot);
693
Windows::Forms::DialogResult result = HUDForm::ShowModal(CppStringToNative(title), CppStringToNative(text), true, deleg);
695
// Abort is used if the window was forcibly closed (e.g. when showing another dialog, like password query).
696
return (result == Windows::Forms::DialogResult::OK) || (result == Windows::Forms::DialogResult::Abort);
699
//--------------------------------------------------------------------------------------------------
702
* Signals the operation being described in a previous run_cancelable_wait_message() call has
703
* finished and the message panel should be taken down.
705
void UtilitiesImpl::stop_cancelable_wait_message()
710
//--------------------------------------------------------------------------------------------------
713
* Places the given string on the clipboard.
715
* @param content The text to be placed on the clipboard. It is assume its encoding is UTF-8.
717
void UtilitiesImpl::set_clipboard_text(const string &content)
719
if (!content.empty())
720
Clipboard::SetText(CppStringToNative(content));
723
//--------------------------------------------------------------------------------------------------
726
* Returns the current text on the clipboard, if there is any.
728
* @result If there is text on the clipboard (ANSI or Unicode) it is returned as UTF-8 string.
729
* @note The returned text gets all CRLF Windows line breaks converted to pure LF.
731
string UtilitiesImpl::get_clipboard_text()
733
String^ unicode= (String^) Clipboard::GetData(DataFormats::UnicodeText);
734
if (unicode == nullptr)
737
return NativeToCppString(unicode);
740
//--------------------------------------------------------------------------------------------------
743
* Returns platform specific user folders, e.g. for the desktop, the user's documents etc.
745
string UtilitiesImpl::get_special_folder(FolderType type)
747
Environment::SpecialFolder special_folder;
751
special_folder = Environment::SpecialFolder::DesktopDirectory;
753
case ApplicationData:
754
special_folder = Environment::SpecialFolder::ApplicationData;
756
case WinProgramFiles:
757
special_folder = Environment::SpecialFolder::ProgramFiles;
759
case WinProgramFilesX86:
760
special_folder = Environment::SpecialFolder::ProgramFilesX86;
762
default: // Documents
763
special_folder = Environment::SpecialFolder::MyDocuments;
767
// Getting the 64 bit application folder works differently if we are a 32 bit application.
768
// IntPtr has a size of 8 for 64 bit apps.
769
if (IntPtr::Size == 4 && type == mforms::WinProgramFiles)
771
WCHAR folder[MAX_PATH];
772
ExpandEnvironmentStrings(L"%ProgramW6432%", folder, ARRAYSIZE(folder));
773
return base::wstring_to_string(folder);
775
return NativeToCppString(Environment::GetFolderPath(special_folder));
778
//--------------------------------------------------------------------------------------------------
780
void UtilitiesImpl::open_url(const string &url)
784
System::Diagnostics::Process::Start(CppStringToNative(url));
788
MessageBox::Show(e->Message->ToString(), "Error Opening Browser",
789
MessageBoxButtons::OK, MessageBoxIcon::Error, MessageBoxDefaultButton::Button1);
793
//--------------------------------------------------------------------------------------------------
795
bool UtilitiesImpl::move_to_trash(const string &file_name)
797
SHFILEOPSTRUCT shf = {0};
799
// Filenames must be double 0 terminated.
800
wchar_t path[MAX_PATH + 1] = {0};
802
shf.wFunc = FO_DELETE;
803
shf.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION;
805
// Paths must be double 0 terminated.
806
std::wstring converted_filename = base::string_to_wstring(file_name);
807
StringCchCopyW(path, sizeof(path), converted_filename.c_str());
809
int result = SHFileOperation(&shf);
811
return (result == 0) && !shf.fAnyOperationsAborted;
814
//--------------------------------------------------------------------------------------------------
816
// The password cache is a temporary storage and only used for a short time frame when looking up a password.
817
static GStaticMutex password_mutex= G_STATIC_MUTEX_INIT;
818
static std::map<std::string, std::string> password_cache;
819
typedef std::map<std::string, std::string>::iterator PasswordIterator;
821
#define DOMAIN_SEPARATOR (char) 2
822
#define PASSWORD_SEPARATOR (char) 3
825
* Loads encrypted passwords from disk. These are typically held only for a short moment.
827
void UtilitiesImpl::load_passwords()
829
// Load password cache from disk. Don't throw an error if the cache file doesn't exist yet, though.
830
std::string file= get_special_folder(ApplicationData) + "/MySQL/Workbench/workbench_user_data.dat";
831
if (g_file_test(file.c_str(), G_FILE_TEST_EXISTS))
836
bool result= g_file_get_contents(file.c_str(), &content, &length, &error) == TRUE;
839
show_error("Password management error", "Error while loading passwords: " + std::string(error->message),
847
data_in.pbData= (BYTE*) content;
848
data_in.cbData= length;
849
result= CryptUnprotectData(&data_in, NULL, NULL, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &data_out) == TRUE;
855
show_error("Password management error", "Could not decrypt password cache.", _("Close"), "", "");
861
// Split the string into individual items and fill the password cache with them.
862
std::stringstream ss((char*) data_out.pbData);
864
while (std::getline(ss, item, '\n'))
866
string::size_type pos= item.find_first_of(PASSWORD_SEPARATOR, 0);
868
if (string::npos != pos)
869
password_cache[item.substr(0, pos)]= item.substr(pos + 1, item.length());
874
LocalFree(data_out.pbData);
879
//--------------------------------------------------------------------------------------------------
882
* Saves the password cache to disk (if store is true) and clears it so passwords aren't kept in
883
* memory any longer than necessary.
885
void UtilitiesImpl::unload_passwords(bool store)
887
// Store all passwords in a string for encryption.
892
std::string plain_data;
893
for (PasswordIterator iterator= password_cache.begin(); iterator != password_cache.end(); iterator++)
894
plain_data += iterator->first + PASSWORD_SEPARATOR + iterator->second + "\n";
899
data_in.pbData= (BYTE*) plain_data.c_str();
900
data_in.cbData= (DWORD) plain_data.length() + 1;
902
if (!CryptProtectData(&data_in, NULL, NULL, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &data_out))
904
show_error("Password management error", "Could not encrypt password cache.", _("Close"), "", "");
908
// Now write the encrypted data to file.
909
std::string file= get_special_folder(ApplicationData) + "/MySQL/Workbench/workbench_user_data.dat";
911
bool result= g_file_set_contents(file.c_str(), (gchar*) data_out.pbData, data_out.cbData, &error) == TRUE;
913
LocalFree(data_out.pbData);
916
show_error("Password management error", "Error while storing passwords: " + std::string(error->message),
922
password_cache.clear();
926
//--------------------------------------------------------------------------------------------------
929
* This function stores the given password in our password file, parameterized by the given service
930
* and user name. The file is encrypted by the system for safety and can only be decrypted by the
931
* same user who encrypted it.
933
void UtilitiesImpl::store_password(const std::string &service, const std::string &account, const std::string &password)
935
g_static_mutex_lock(&password_mutex);
941
// Keep the password in our password cache and write the entire cache to file after that.
942
password_cache[service + DOMAIN_SEPARATOR + account]= password;
944
unload_passwords(true);
948
g_static_mutex_unlock(&password_mutex);
952
//--------------------------------------------------------------------------------------------------
955
* Return the plain text password for the given service and account.
957
bool UtilitiesImpl::find_password(const std::string &service, const std::string &account, std::string &password)
959
g_static_mutex_lock(&password_mutex);
966
PasswordIterator iterator= password_cache.find(service + DOMAIN_SEPARATOR + account);
967
if (iterator == password_cache.end())
970
password= iterator->second;
972
unload_passwords(false);
977
g_static_mutex_unlock(&password_mutex);
981
//--------------------------------------------------------------------------------------------------
984
* Remove the password for the given service and account if there is one.
986
void UtilitiesImpl::forget_password(const std::string &service, const std::string &account)
988
g_static_mutex_lock(&password_mutex);
994
PasswordIterator iterator= password_cache.find(service + DOMAIN_SEPARATOR + account);
995
if (iterator != password_cache.end())
997
password_cache.erase(iterator);
998
unload_passwords(true);
1001
unload_passwords(false);
1005
g_static_mutex_unlock(&password_mutex);
1009
//--------------------------------------------------------------------------------------------------
1011
void* UtilitiesImpl::perform_from_main_thread(const boost::function<void* ()>& slot, bool wait)
1013
return _dispatcher->RunOnMainThread(slot, wait);
1016
//--------------------------------------------------------------------------------------------------
1019
* Returns the main form of the application.
1021
Windows::Forms::Form^ UtilitiesImpl::get_mainform()
1023
return Application::OpenForms["MainForm"];
1026
//--------------------------------------------------------------------------------------------------
1028
public ref class TimerHandler
1031
TimerHandler(float interval, const boost::function<bool ()> &slot)
1033
_timer = gcnew System::Windows::Forms::Timer();
1035
_slot = new boost::function<bool ()>(slot);
1037
_timer->Interval = (int) (interval * 1000);
1038
_timer->Tick += gcnew EventHandler(this, &TimerHandler::timer_tick);
1050
boost::function<bool ()> *_slot;
1051
System::Windows::Forms::Timer ^_timer;
1053
void timer_tick(Object^ sender, System::EventArgs ^e)
1055
// emulate behaviour in MacOS X (timers arent fired when in modal loops)
1056
// also works around a deadlock of python when a timer is fired while inside a modal loop
1057
if (!mforms::Utilities::in_modal_loop())
1061
// if callback returns true, then restart the timer
1063
_timer->Enabled = true;
1070
//-------------------------------------------------------------------------------------------------
1072
void UtilitiesImpl::add_timeout(float interval, const boost::function<bool ()> &slot)
1074
TimerHandler ^handler = gcnew TimerHandler(interval, slot);
1077
//-------------------------------------------------------------------------------------------------